Spring AOP 实现机制

1. AOP概念

1.1 JoinPoint连接点:程序执行中的特定点,如方法执行,调用构造函数或字段复制等,面向切面编程,JoinPoint就是要被切入的对象。  

1.2 Advice通知:在一个连接点中,切面采取的行动,针对切入点,要做的事情。 

1.3 Pointcut切点:一个匹配连接点的正则表达式。每个任何连接点匹配一个切入点时,就执行与该切入点相关联的指定通知。关注哪些被切入点可以切入。 

1.4 Aspect切面(Advisor):一个分布在应用程序中多个位置的标准代码/功能,通常与实际的业务逻辑(例事务管理)不同。每个切面都侧重于一个特定的横切功能。

1.5 Weaving织入:链接切面和目标对象来创建一个通知对象的过程。

1.6 Advice通知 + Pointcut切点形成了切面Aspect/Advisor

1.7 JoinPoint与Pointcut区别:在Spring AOP中,所有方法执行都是JoinPoint。Pointcut是描述信息,修饰的是JoinPoint,通过Pointcut就可以确定哪些JoinPoint可以织入Advice,JointPoint与Pointcut本质上两个不同的纬度。Advice是在JointPoint执行,Pointcut确定了哪些JoinPoint执行Advice。

2. AOP实现

2.1 织入节点

    编译期间:切面在目标类编译时被织入,需要引入独立的编译器。

    编译后:增强已经编译出来的类,如我们要增强依赖的 jar 包中的某个类的某个方法。

    类加载期:在 JVM 进行类加载的时候进行织入。

    运行期:切面在应用运行的某个时期被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象。

2.2 实现框架

    AspectJ:AspectJ 是一个采用Java 实现的AOP框架,它能够对代码进行编译(一般在编译期进行),让代码具有AspectJ 的 AOP 功能,AspectJ 是目前实现 AOP 框架中最成熟,功能最丰富的语言。ApectJ 主要采用的是编译期静态织入的方式。

    AspectWerkz:基于Java的简单、动态、轻量级、强大的AOP框架。可以在运行时或编译时轻松的改造任何(旧)应用程序或除了rt.jar以外的外部类库。

    JBoss AOP:JBoss 4.0带了一个AOP框架。这个框架和JBoss应用服务器紧密地结合,但是也能够在应用中单独运行它。

    Spring AOP:Spring AOP 是通过动态代理技术实现的,而动态代理是基于反射设计的。Spring AOP 采用了两种混合的实现方式:JDK 动态代理和 CGLib 动态代理

2.3 AspectJ 与 Spring AOP比较


3. AspectJ实现

AspectJ是提供了完整的AOP方案,采用静态织入,不依赖Spring AOP。

3.1 定义切面

针对test()方法进行拦截,方法执行前打印"before interceptor"

@Aspect

public class AspectjInterceptor {

    @Pointcut("execution( * com.hobbit.aspectj.Hello.test())")

    public void execute(){

    }

    @Before("execute()")

    public void beforeLog(){

        System.out.println("before interceptor");

    }

}

3.2 主任务

@Component

public class Hello {

    public void test(){

        System.out.println("hello aspectj");

    }

}

3.3 设置编译器

Java Compiler -> User compiler 选择Ajc,同时设置aspectjtools.jar,见下图


3.4 运行结果

3.5 反编译文件


4. Spring AOP创建代理

spring aop既可以使用AspectJ注解实现拦截,也可以不依赖AspectJ,使用Spring advice + pointcut,实现拦截注入。

tip: spring aop 使用AspectJ注解时,拦截实现方式是?

4.1 使用AspectJ注解

4.1.1 定义元注解

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface LogAnnotation {

        Stringvalue();

}

4.1.2 定义切面

@Aspect

@Component

public class LogInterceptor {

@Pointcut("@annotation(com.hobbit.interceptor.LogAnnotation)")

public void annotationPointCut(){

}

@Before("annotationPointCut()")

public void beforeLog(JoinPoint joinPoint){

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        LogAnnotation logAnnotation = methodSignature.getMethod().getAnnotation(LogAnnotation.class);

        if(Objects.nonNull(logAnnotation)){

             System.out.println("beforeLog : " + logAnnotation.value());

        }

    }

}

4.1.3 织入

@Service

public class UserService {

    @Autowired

    private UserMapperuserMapper;


    @LogAnnotation("queryUser")

    public UserEntityqueryUser(int id){

        return userMapper.getById(id);

    }

}

tip:使用Aspect切面时,底层使用AspectJ实现的静态织入,还是有Spring AOP实现的动态织入?

4.2 Spring AOP实现

Spring AOP实现了完整的方案,通过定义advice + pointcut 实现对象动态织入。

4.2.1 定义Advice

public class LogBeforeAdviceimplements MethodBeforeAdvice {    

    @Override

    public void before(Method method, Object[] args, Object target)throws Throwable{

        System.out.println("before advice for class:" + target.getClass() +" and method:" + method.getName());

    }

}

4.2.2 配置PointCut及切面

    

    

          

   

    

          

          

    

4.2.3 通过ProxyFactoryBean创建代理

      

       

      

4.3  创建代理时序图

Spring的代理对象通过Bean的后置处理器,在createBean对象时封装的。创建的代理的时序图如下

5. Spring AOP生效

5.1 Spring 创建代理的节点

Spring 通过org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization实现AspectJ注解代理对象的创建,具体在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization实现代理对象的创建

代理对象创建前


创建代理对象


5.2 Spring AOP拦截

       Spring AOP通过把Advice转化成MethodIntercetor,通过递归调用的方式实现了Advice的织入,完成advice的调用后,调用目标方法完成切入。

       目标对象:ReflectiveMethodInvocation,在JdkDynamicAopProxy invoke方法中创建,是JoinPiont的一个实现。


        拦截对象:MethodInterceptor.invoke(MethodInvocation invocation)包括了要拦截的对象。实现不同形式的拦截


  事务拦截TransactionInterceptor

   tip:先调用拦截链,如何时间后置拦截?Interceptor异常是否会导致事务切面回滚?

5.3 总结

Spring的AOP实现并不依赖于AspectJ任何类,它自己实现了一套AOP的。比如它Spring自己提供的BeforeAdvice和AfterAdvice都是对AOP联盟规范的标准实现。以及Spring自己抽象出来的对Advice的包装:org.springframework.aop.Advisor贯穿Spring AOP的始终。

你可能感兴趣的:(Spring AOP 实现机制)