spring 16 从 @Aspect 到 Advisor

代理创建器

点击查看代码
package org.springframework.aop.framework.autoproxy; 
// 包名与 AnnotationAwareAspectJAutoProxyCreator 一致,方便调用方法。
import org.aopalliance.intercept.MethodInterceptor;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import java.util.List;

public class S16 {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("s16Aspect", S16Aspect.class);
        context.registerBean("s16Config", S16Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        context.refresh();
//        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
//            System.out.println(beanDefinitionName);
//        }

        /*AnnotationAwareAspectJAutoProxyCreator 的作用 是一个 BeanPostProcessor
        将高级 @Aspect 切面统一为低级 Advisor 切面
        在合适的时机创建代理
        创建 -> (*) 依赖注入 -> 初始化 (*)
        为了方便测试将包名改成了其所在包。*/
        AnnotationAwareAspectJAutoProxyCreator proxyCreator
                = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);

        //第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
        //* 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如本例 S16 中的 advisor3
        //* 有【资格】的 Advisor 另一部分是高级的, 由解析 @Aspect 后获得
        List<Advisor> advisors = proxyCreator.findEligibleAdvisors(S16Bean1.class, "s16Bean1");
//        for (Advisor advisor : advisors) {
//            System.out.println(advisor);
//        }


        // 第二个重要方法 wrapIfNecessary
        //* 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
        //* 它的调用时机通常在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行
        S16Bean1 s16Bean1 = new S16Bean1();
        Object o1 = proxyCreator.wrapIfNecessary(s16Bean1, "s16Bean1", "s16Bean1");
//        System.out.println(o1.getClass().getSimpleName());
        Object o2 = proxyCreator.wrapIfNecessary(new S16Bean2(), "s16Bean2", "s16Bean2");
//        System.out.println(o2.getClass().getSimpleName());
        ((S16Bean1) o1).s16B();
    }


}

class S16Bean1 {
    public void s16A() {
        System.out.println("s16A running1...");
    }
    public void s16B() {
        System.out.println("s16B running1...");
    }
}
class S16Bean2 {
    public void s16A2() {
        System.out.println("s16A running2...");
    }
    public void s16B2() {
        System.out.println("s16B running2...");
    }
}



@Aspect
class S16Aspect{
    @Before("execution(* s16B())")
    public void s16Advice1() {
        System.out.println("s16Advice1 before...");
    }
    @After("execution(* s16A())")
    public void s16Advice2() {
        System.out.println("s16Advice2 after...");
    }

}

@Configuration
class S16Config {

    @Bean("s16Advisor")
    public Advisor advisor(MethodInterceptor s16Advice3) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* s16B())");
        return new DefaultPointcutAdvisor(pointcut,s16Advice3);
    }

    @Bean
    public MethodInterceptor s16Advice3() {
        return invocation -> {
            System.out.println("s16Advice3 before...");
            Object result = invocation.proceed();
            System.out.println("s16Advice3 after...");
            return result;
        };
    }

}
  1. AnnotationAwareAspectJAutoProxyCreator 的作用
    • 将高级 @Aspect 切面统一为低级 Advisor 切面
    • 在合适的时机创建代理
  2. findEligibleAdvisors 找到有【资格】的 Advisors
    • 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如本例 S16 中的 advisor3
    • 有【资格】的 Advisor 另一部分是高级的, 由解析 @Aspect 后获得
  3. wrapIfNecessary
    • 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
    • 它的调用时机通常在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行

代理创建时机

点击查看代码
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(Config.class);
        context.refresh();
        context.close();
        // 创建 -> (*) 依赖注入 -> 初始化 (*)
        /*
            学到了什么
                a. 代理的创建时机
                    1. 初始化之后 (无循环依赖时)
                    2. 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存
                b. 依赖注入与初始化不应该被增强, 仍应被施加于原始对象
         */
    }

    @Configuration
    static class Config {
        @Bean // 解析 @Aspect、产生代理
        public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
        }

        @Bean // 解析 @Autowired
        public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            return new AutowiredAnnotationBeanPostProcessor();
        }

        @Bean // 解析 @PostConstruct
        public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            return new CommonAnnotationBeanPostProcessor();
        }

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

        @Bean
        public MethodInterceptor advice() {
            return (MethodInvocation invocation) -> {
                System.out.println("before...");
                return invocation.proceed();
            };
        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean1 {
        public void foo() {

        }
        public Bean1() {
            System.out.println("Bean1()");
        }
        @Autowired public void setBean2(Bean2 bean2) {
            System.out.println("Bean1 setBean2(bean2) class is: " + bean2.getClass());
        }
        @PostConstruct public void init() {
            System.out.println("Bean1 init()");
        }
    }

    static class Bean2 {
        public Bean2() {
            System.out.println("Bean2()");
        }
        @Autowired public void setBean1(Bean1 bean1) {
            System.out.println("Bean2 setBean1(bean1) class is: " + bean1.getClass());
        }
        @PostConstruct public void init() {
            System.out.println("Bean2 init()");
        }
    }
}
  1. 代理的创建时机
    • 初始化之后 (无循环依赖时)
    • 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存
    • 循环依赖,A 中要依赖注入 B,B 中要注入 A
  2. 依赖注入与初始化不应该被增强, 仍应被施加于原始对象
  3. 高级切面利用 @Order 注解可以设置通知的优先级,值越小优先级越高,低级切面可以通过 setOrder 方法来设置值,Order 加在方法和 @Bean 上不生效。
点击查看代码

@Aspect
@Order(2) //设置 Order 值为2,默认是整数最大值
class S16Aspect{
    @Before("execution(* s16B())")
    public void s16Advice1() {
        System.out.println("s16Advice1 before...");
    }
    @After("execution(* s16A())")
    public void s16Advice2() {
        System.out.println("s16Advice2 after...");
    }

}

@Configuration
class S16Config {

    @Bean("s16Advisor")
    public Advisor advisor(MethodInterceptor s16Advice3) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* s16B())");
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, s16Advice3);
        advisor.setOrder(1); //设置 Order 值
        return advisor;
    }
}

@Before 对应的低级通知

点击查看代码

// 模拟将用注解标注的通知(@Before @After...)转换为低级通知
public class S16Test {
    public static void main(String[] args) {
        //创建切面的工厂对象
        SingletonAspectInstanceFactory factory = new SingletonAspectInstanceFactory(new S16Aspect());
        //创建包含低级切面的集合
        List<Advisor> advisors = new ArrayList<>();
        //利用反射获得高级切面中的所有方法
        Method[] methods = S16Aspect.class.getDeclaredMethods();
        //遍历方法找到所有含相关注解的方法
        for (Method method : methods) {
            if (method.isAnnotationPresent(Before.class)) {
                //获得其中的切点表达式
                String execution = method.getAnnotation(Before.class).value();
                //创建切点
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(execution);
                //创建通知                                前置通知
                AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
                //创建低级切面
                DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                //将切面添加到切面的集合
                advisors.add(advisor);
            } else if (method.isAnnotationPresent(After.class)) {
                //获得其中的切点表达式
                String execution = method.getAnnotation(After.class).value();
                //创建切点
                AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
                pointcut.setExpression(execution);
                //创建通知                       后置通知
                AspectJAfterAdvice advice = new AspectJAfterAdvice(method, pointcut, factory);
                //创建低级切面
                DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
                //将切面添加到切面的集合
                advisors.add(advisor);
            }
        }
        for (Advisor advisor : advisors) {
            System.out.println(advisor);

        }
    }

    @Order(2)
    @Aspect
    static class S16Aspect {
        @Before("execution(* s16B())")
        public void s16Advice1() {
            System.out.println("s16Advice1 before...");
        }

        @After("execution(* s16A())")
        public void s16Advice2() {
            System.out.println("s16Advice2 after...");
        }

    }

    static class S16Bean1 {
        public void s16A() {
            System.out.println("s16A running1...");
        }

        public void s16B() {
            System.out.println("s16B running1...");
        }
    }

    static class S16Bean2 {
        public void s16A2() {
            System.out.println("s16A running2...");
        }

        public void s16B2() {
            System.out.println("s16B running2...");
        }
    }


}

  1. @Before 前置通知会被转换为原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息
    1. 通知代码从哪儿来
    2. 切点是什么(这里为啥要切点, 后面解释)
    3. 通知对象如何创建, 本例共用同一个 Aspect 对象
  2. 类似的还有
    1. AspectJAroundAdvice (环绕通知)
    2. AspectJAfterReturningAdvice(返回后通知)
    3. AspectJAfterThrowingAdvice (异常通知)
    4. AspectJAfterAdvice (后置通知)
posted @   xy7112  阅读(109)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示