第17讲 - 从@Aspect 到 Advisor

@Aspect与Advisor

public class Target01 {
    public void foo() {
        System.out.println("target01 foo...");
    }
}

public class Target02 {
    public void bar() {
        System.out.println("target02 bar...");
    }
}

@Aspect
public class Aspect01 {

    @Before("execution(* foo())")
    public void before01() {
        System.out.println("target before...");
    }

    @After("execution(* foo())")
    public void after01() {
        System.out.println("target after...");
    }

}

@Configuration
public class Config01 {

    @Bean
    public Advisor advisor3(MethodInterceptor advice3) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        return new DefaultPointcutAdvisor(pointcut, advice3);
    }

    @Bean
    public MethodInterceptor advice3() {
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                System.out.println("advice3 before...");
                Object result = methodInvocation.proceed();
                System.out.println("advice3 after...");
                return result;
            }
        };

        return methodInterceptor;
    }

}
public class A17Application extends AnnotationAwareAspectJAutoProxyCreator {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("aspect01", Aspect01.class);
        context.registerBean("config01", Config01.class);
        // 解析@Bean注解
        context.registerBean(ConfigurationClassPostProcessor.class);
        // 切面相关处理器
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        context.refresh();

        /**
         * findEligibleAdvisors: 找到容器中与类有关的advisor
         */
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        List advisors = creator.findEligibleAdvisors(Target01.class, "target01");
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }

        /**
         * wrapIfNecessary: 它内部调用findEligibleAdvisors,如果返回集合不为空,则表示需要创建代理
         */
        Object o1 = creator.wrapIfNecessary(new Target01(), "target01", "target01");
        System.out.println(o1.getClass());
        Object o2 = creator.wrapIfNecessary(new Target02(), "target02", "target02");
        System.out.println(o2.getClass());
        // 调用增强方法测试效果
        ((Target01) o1).foo();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

需要注意的是上文提到的方法属于protected,所以需将测试类与AnnotationAwareAspectJAutoProxyCreator类放在同一个包下

package org.springframework.aop.framework.autoproxy;

程序运行结果如下:

// 符合表达式的切面

org.springframework.aop.interceptor.ExposeInvocationInterceptor.ADVISOR
org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [com.shuttle.spring5.Config01$1@6f45df59]
InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void com.shuttle.spring5.Aspect01.after01()]; perClauseKind=SINGLETON
InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void com.shuttle.spring5.Aspect01.before01()]; perClauseKind=SINGLETON

// Target01需要创建代理,Target02不需要
class com.shuttle.spring5.Target01$$EnhancerBySpringCGLIB$$8b5fc085
class com.shuttle.spring5.Target02

// 方法增强
advice3 before...
target before...
target01 foo...
target after...
advice3 after...

// 容器中的bean
aspect01
config01
org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
advisor3
advice3

 第17讲 - 从@Aspect 到 Advisor_第1张图片

代理创建时机

  • 初始化之后(无循环依赖时)
  • 实例创建后,依赖注入前(有循环依赖时),并暂存于二级缓存。

依赖注入和初始化阶段不应该被增强,仍应使用原始对象。 

@Order注解

第17讲 - 从@Aspect 到 Advisor_第2张图片

加在切面类上可以控制与其它切面类执行的顺序,数字越小优先级越高。【注意:加在方法上不生效】 

第17讲 - 从@Aspect 到 Advisor_第3张图片

高级切面【Aspect】转换为低级切面【advisor】

public class A17Application2 {
    
    public static void main(String[] args) {
        AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());
        // 高级切面转低级切面
        List advisors = new ArrayList<>();
        for (Method method : Aspect.class.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Before.class)) {
                // 获取切面表达式
                String expression = method.getAnnotation(Before.class).value();
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(expression);
                // 通知类
                AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
                DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                advisors.add(advisor);
            }
        }

        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }
        
    }
}

@Before 前置通知会被转换为原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息

  • 通知代码从哪儿来
  • 切点是什么
  • 通知对象如何创建, 本例共用同一个 Aspect 对象

类似的通知还有

  • AspectJAroundAdvice (环绕通知)
  • AspectJAfterReturningAdvice(返回通知)
  •  AspectJAfterThrowingAdvice(异常通知)
  • AspectJAfterAdvice (最终通知)

 第17讲 - 从@Aspect 到 Advisor_第4张图片

你可能感兴趣的:(《黑马,-,java,spring,spring,boot,程序人生,java-ee)