专栏首页用户画像Spring AOP的三种实现方式

Spring AOP的三种实现方式

一、浅析AOP

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-api

AOP意味面向切面编程,是通过预编译方式和运行期动态代理,实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

1、方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的 Advisor或拦截器实现。

2、连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。

通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvic

3、切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上

4、引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口

5、目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。POJO

AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

6、织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

二、AOP项目预览

1、有图有真相

2、 github源码:https://github.com/jxq0816/spring-aop-demo

3、代码组织结构

三、基础配置

1、 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.week7i.share</groupId>
  <artifactId>spring-aop-demo</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>spring-aop-demo Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties>
    <spring.version>4.3.6.RELEASE</spring.version>
  </properties>
  <dependencies>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <!--JSP Standard Tag Library,JSP标准标签库-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!--AOP-->

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.13</version>
    </dependency>

    <!--Code Generation Library 是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口
    它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)-->
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.2.4</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
      <version>4.10</version>
    </dependency>
    
  </dependencies>
  <build>
    <finalName>spring-aop-demo</finalName>
  </build>
</project>

2、web.xml

注意:aop的配置文件必须放在servlet的param-value中,才可以在springmvc上AOP,最初放在了context-param的param-value中,折腾了一天才搞定。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <context-param>
   <!-- applicationContext.xml默认地址目录是/WEB-INF-->
    <param-name>contextConfigLocation</param-name>
    <param-value>
      classpath:/applicationContext.xml
    </param-value>
  </context-param>

  <!-- 加入ContextLoaderListener 启动Web容器时,自动装配ApplicationContext的配置信息-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--DispatcherServlet是前置控制器,拦截匹配的请求,Servlet拦截匹配规则要自己定义,把拦截下来的请求,依据相应的规则分发到目标Controller来处理-->
  <servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
        classpath:/dispatcherServlet.xml
        classpath:/dispatcherServlet-aop-01.xml
        classpath:/dispatcherServlet-aop-02.xml
        classpath:/dispatcherServlet-aop-03.xml
      </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>/index.jsp</welcome-file>
  </welcome-file-list>
</web-app

四、 AOP方法01

配置文件定义Advice通知对象、Aspect切面、Pointcut切点,并通过定义aop:after连接Adivicef通知方法和Pointcut切点

1、 dispatcherServlet-aop-01.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.weeking.share"/>

    <!-- 被代理对象 -->
    <bean id="math" class="com.weeking.share.service.aop01.MathUtils"></bean>
    <!-- 切面 -->
    <bean id="aspect" class="com.weeking.share.service.aop01.AspectProxy"></bean>

    <aop:config proxy-target-class="true">
        <!-- 切点 -->
        <aop:pointcut id="pointCut" expression="execution(public * com.weeking.share.service.aop01.MathUtils.*(..))" />
        <!--切面 -->
        <aop:aspect ref="aspect">
            <!--连接通知方法与切点 -->
            <aop:before method="before" pointcut-ref="pointCut"/>
            <aop:after method="after" pointcut-ref="pointCut"/>
        </aop:aspect>

    </aop:config>
    
</beans>

2、 AspectProxy.java

package com.weeking.share.service.aop01;

import org.aspectj.lang.JoinPoint;

/**
 * 切面类,其方法为通知
 *
 */
public class AspectProxy {

    public void before(JoinPoint jp){
        System.out.println("----------AOP01 before execute----------");
        System.out.println(jp.getSignature().getName());
    }

    public void after(JoinPoint jp){
        System.out.println("----------AOP01 after execute----------");
    }
}

3、MathUtils.java

package com.weeking.share.service.aop01;

/**
 * 被代理的目标类
 */
public class MathUtils{
    //加
    public int add(int n1,int n2){
        int result=n1+n2;
        System.out.println(n1+"+"+n2+"="+result);
        return result;
    }

    //减
    public int sub(int n1,int n2){
        int result=n1-n2;
        System.out.println(n1+"-"+n2+"="+result);
        return result;
    }

    //乘
    public int mut(int n1,int n2){
        int result=n1*n2;
        System.out.println(n1+"X"+n2+"="+result);
        return result;
    }

    //除
    public int div(int n1,int n2){
        int result=n1/n2;
        System.out.println(n1+"/"+n2+"="+result);
        return result;
    }
}

4、测试方法

 @Test
    public void testAop01() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:dispatcherServlet-aop-01.xml");
        MathUtils math = ctx.getBean("math", MathUtils.class);
        int n1 = 100, n2 = 5;
        math.add(n1, n2);
        math.sub(n1, n2);
        math.mut(n1, n2);
        math.div(n1, n2);
    }

5、运行结果

五、AOP02 注解实现

1、 dispatcherServlet-aop-02.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
               http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.weeking.share"/>

    <aop:config>

        <!--定义切点-->
        <aop:pointcut
                expression="execution(public * com.weeking.share.service.aop02.service.LoginService.*(..)) and @annotation(com.weeking.share.service.aop02.annotion.Operate)"
                id="pointCut"/>
        <!--定义切面 当执行同一个切入点时,不同切面的执行先后顺序是由“每个切面的order属性”而定的.
        order越小,则该该切面中的通知越先被执行。-->
        <aop:aspect  ref="aspectProxy02" order="1">
            <!--连接通知方法与切点-->
            <aop:after method="doAfter" pointcut-ref="pointCut" />
        </aop:aspect>

    </aop:config>

    <bean id="aspectProxy02" class="com.weeking.share.service.aop02.AspectProxy02"></bean>
</beans>

2、Operate.java

package com.weeking.share.service.aop02.annotion;

import com.weeking.share.service.aop02.ennum.OperateEnum;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到  
@Target(ElementType.METHOD)
public @interface Operate {
	public OperateEnum status();
}

3、OperateEnum.java

package com.weeking.share.service.aop02.ennum;


public enum OperateEnum {

	USERNAME("username");
	private String type;
    OperateEnum(String type) {
        this.type = type;
    }

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}


}

4、AspectProxy02.java

package com.weeking.share.service.aop02;

import com.weeking.share.service.aop02.annotion.Operate;
import com.weeking.share.service.aop02.ennum.OperateEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

public class AspectProxy02 {

	public void doAfter(JoinPoint jp) throws NoSuchMethodException, SecurityException {
		System.out.println("---------- AOP02 after execute ----------");
		MethodSignature signature = (MethodSignature) jp.getSignature();
		Method method = signature.getMethod();
		System.out.println("method : "+method.getName());

		Method realMethod = jp.getTarget().getClass().getDeclaredMethod(signature.getName(), method.getParameterTypes());
		System.out.println("realMethod : "+method.getName());

		Operate operate = realMethod.getAnnotation(Operate.class);
		Object[] args = jp.getArgs();
		if( args.length > 0 && operate != null) {
			OperateEnum status = operate.status();
			System.out.println("keys:"+status);
			System.out.print("values:");
			for(int i=0;i<args.length;i++){
				System.out.print(args[i]);
			}
		}
		System.out.println();
	}
}

5、LoginService.java

package com.weeking.share.service.aop02.service;

import com.weeking.share.service.aop02.annotion.Operate;
import com.weeking.share.service.aop02.ennum.OperateEnum;
import org.springframework.stereotype.Service;

@Service
public class LoginService {

    @Operate(status= OperateEnum.USERNAME)
    public String login(String username){

        System.out.println("login service username:"+username);
        return username;
    }
}

6、测试方法

@Test
    public void testAop02() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:dispatcherServlet-aop-02.xml");
        LoginService service = (LoginService)ctx.getBean(LoginService.class);
        service.login("jiang");
    }

7、运行结果

六、自动代理AOP03

1、dispatcherServlet-aop-03.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
               http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.weeking.share"/>

    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

2、AspectProxy03.java

package com.weeking.share.service.aop03;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 切面类,横切逻辑
 *
 */
@Component
@Aspect
public class AspectProxy03 {
    @Before("execution(* com.weeking.share.service.aop03.MathService.*(..))")
    public void before(JoinPoint jp){
        System.out.println("---------- AOP03 before execute ----------");
        MethodSignature signature = (MethodSignature) jp.getSignature();
        Method method = signature.getMethod();
        System.out.println("method : "+method.getName());
        Object[] args = jp.getArgs();
        if( args.length>0) {
            System.out.print("param:");
            for(int i=0;i<args.length;i++){
                System.out.print(args[i]+" ");
            }
        }
        System.out.println();
    }

    @After("execution(* com.weeking.share.service.aop03.MathService.*(..))")
    public void after(JoinPoint jp){
        System.out.println("---------- AOP03 after execute ----------");
    }
}

3、MathService.java

package com.weeking.share.service.aop03;

import org.springframework.stereotype.Service;

@Service
public class MathService {
    //加
    public int add(int n1,int n2){
        int result=n1+n2;
        System.out.println(n1+"+"+n2+"="+result);
        return result;
    }

    //减
    public int sub(int n1,int n2){
        int result=n1-n2;
        System.out.println(n1+"-"+n2+"="+result);
        return result;
    }

    //乘
    public int mut(int n1,int n2){
        int result=n1*n2;
        System.out.println(n1+"X"+n2+"="+result);
        return result;
    }

    //除
    public int div(int n1,int n2){
        int result=n1/n2;
        System.out.println(n1+"/"+n2+"="+result);
        return result;
    }
}

4、测试方法

@Test
public void testAop03() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:dispatcherServlet-aop-03.xml");
    MathService math = ctx.getBean(MathService.class);
    int n1 = 100, n2 = 5;
    math.add(n1, n2);
    math.sub(n1, n2);
    math.mut(n1, n2);
    math.div(n1, n2);
}

5、运行结果

七、HTTP请求

1、LoginController.java

package com.weeking.share.controller;

import com.weeking.share.service.aop02.annotion.Operate;
import com.weeking.share.service.aop02.ennum.OperateEnum;
import com.weeking.share.service.aop02.service.LoginService;
import com.weeking.share.service.aop03.MathService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Created by jiangxingqi on 2017/7/25.
 */
@Controller
public class LoginController {

    @Autowired
    private LoginService loginService;
    @Autowired
    private MathService mathService;

    @RequestMapping(value = "/login")
    public String login(){
        String username=loginService.login("jiangxingqi");
        return "login";
    }
    @RequestMapping(value = "/math")
    public String math(){
        mathService.add(1,2);
        return "login";
    }
}

2、HTTP请求http://localhost:8084/login

控制台输出显示AOP成功执行

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • springmvc 最简化配置

    一、新建maven webapp项目 http://blog.csdn.net/jxq0816/article/details/76063973

    week
  • springboot 禁用mongoDB自动配置

    springboot 内置了mongoDB驱动,默认配置localhost:27017,若本机没有配置mongoDB,则会连接失败。

    week
  • dubbo框架搭建

    Dubbo offers three key functionalities, which include interface based remote cal...

    week
  • java之aop

    1.AOP:aspect orientied programming 面向切面编程。就是横向编程。

    Vincent-yuan
  • Spring 中基于 AOP 的 XML操作方式

    Spring 框架的一个关键组件是面向方面的编程(AOP)框架。面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为...

    Jerry Wang
  • Spring(3)——AOP

    作用:在程序运行期间,不修改源码对已有方法进行增强。 优势:1减少重复代码,2提高开发效率,3维护方便

    羊羽shine
  • day34_Spring学习笔记_02

    1.2.2.2、切面类   MyAspect.java的代码同上 1.2.1.2、切面类 代码,这里不再赘述!

    黑泽君
  • aop-aspectJ的通知不被执行

    qubianzhong
  • Spring笔记(二)

    1.注解ioc 1.开启注解扫描 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www...

    lwen
  • springboot-3-springboot中引入xml文件

    原文地址: http://412887952-qq-com.iteye.com/blog/2293846

    用户5640963

扫码关注云+社区

领取腾讯云代金券