Spring从@Aspect到Advisor使用演示实例

作者:tanglin_030907031026 时间:2022-11-21 11:42:08 

演示1 - 代理创建器

public class A17 {
   public static void main(String[] args) {
       GenericApplicationContext context = new GenericApplicationContext();
       context.registerBean("aspect1", Aspect1.class);
       context.registerBean("config", Config.class);
       context.registerBean(ConfigurationClassPostProcessor.class);
       context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
       // BeanPostProcessor
       // 创建 -> (*) 依赖注入 -> 初始化 (*)
       context.refresh();
//        for (String name : context.getBeanDefinitionNames()) {
//            System.out.println(name);
//        }
       /*
           第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
               a. 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如下例中的 advisor3
               b. 有【资格】的 Advisor 另一部分是高级的, 由本章的主角解析 @Aspect 后获得
        */
       AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
       List<Advisor> advisors = creator.findEligibleAdvisors(Target2.class, "target2");
       /*for (Advisor advisor : advisors) {
           System.out.println(advisor);
       }*/
       /*
           第二个重要方法 wrapIfNecessary
               a. 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
        */
       Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");
       System.out.println(o1.getClass());
       Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
       System.out.println(o2.getClass());
       ((Target1) o1).foo();
       /*
           学到了什么
               a. 自动代理后处理器 AnnotationAwareAspectJAutoProxyCreator 会帮我们创建代理
               b. 通常代理创建的活在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行
               c. 高级的 @Aspect 切面会转换为低级的 Advisor 切面, 理解原理, 大道至简
        */
   }
   static class Target1 {
       public void foo() {
           System.out.println("target1 foo");
       }
   }
   static class Target2 {
       public void bar() {
           System.out.println("target2 bar");
       }
   }
   @Aspect // 高级切面类
   @Order(1)
   static class Aspect1 {
       @Before("execution(* foo())")
       public void before1() {
           System.out.println("aspect1 before1...");
       }
       @Before("execution(* foo())")
       public void before2() {
           System.out.println("aspect1 before2...");
       }
   }
   @Configuration
   static class Config {
       /*@Bean // 低级切面
       public Advisor advisor3(MethodInterceptor advice3) {
           AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
           pointcut.setExpression("execution(* foo())");
           DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice3);
           return advisor;
       }
       @Bean
       public MethodInterceptor advice3() {
           return invocation -> {
               System.out.println("advice3 before...");
               Object result = invocation.proceed();
               System.out.println("advice3 after...");
               return result;
           };
       }*/
   }
}

收获💡

AnnotationAwareAspectJAutoProxyCreator 的作用

  • 将高级 @Aspect 切面统一为低级 Advisor 切面

  • 在合适的时机创建代理

findEligibleAdvisors 找到有【资格】的 Advisors

  • 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如本例 A17 中的 advisor3

  • 有【资格】的 Advisor 另一部分是高级的, 由解析 @Aspect 后获得

wrapIfNecessary

  • 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理

  • 它的调用时机通常在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行

演示2 - 代理创建时机

public class A17_1 {
   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()");
       }
   }
}

收获💡

代理的创建时机

  • 初始化之后 (无循环依赖时)

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

依赖注入与初始化不应该被增强, 仍应被施加于原始对象

演示3 - @Before 对应的低级通知

public class A17_2 {
   static class Aspect {
       @Before("execution(* foo())")
       public void before1() {
           System.out.println("before1");
       }
       @Before("execution(* foo())")
       public void before2() {
           System.out.println("before2");
       }
       public void after() {
           System.out.println("after");
       }
       public void afterReturning() {
           System.out.println("afterReturning");
       }
       public void afterThrowing() {
           System.out.println("afterThrowing");
       }
       public Object around(ProceedingJoinPoint pjp) throws Throwable {
           try {
               System.out.println("around...before");
               return pjp.proceed();
           } finally {
               System.out.println("around...after");
           }
       }
   }
   static class Target {
       public void foo() {
           System.out.println("target foo");
       }
   }
   @SuppressWarnings("all")
   public static void main(String[] args) throws Throwable {
       AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());
       // 高级切面转低级切面类
       List<Advisor> list = 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);
               // 切面
               Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
               list.add(advisor);
           }
       }
       for (Advisor advisor : list) {
           System.out.println(advisor);
       }
       /*
           @Before 前置通知会被转换为下面原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息
               a. 通知代码从哪儿来
               b. 切点是什么(这里为啥要切点, 后面解释)
               c. 通知对象如何创建, 本例共用同一个 Aspect 对象
           类似的通知还有
               1. AspectJAroundAdvice (环绕通知)
               2. AspectJAfterReturningAdvice
               3. AspectJAfterThrowingAdvice
               4. AspectJAfterAdvice (环绕通知)
        */
   }
}

收获💡

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

  • 通知代码从哪儿来

  • 切点是什么(这里为啥要切点, 后面解释)

  • 通知对象如何创建, 本例共用同一个 Aspect 对象

类似的还有

  • AspectJAroundAdvice (环绕通知)

  • AspectJAfterReturningAdvice

  • AspectJAfterThrowingAdvice (环绕通知)

  • AspectJAfterAdvice (环绕通知)

来源:https://blog.csdn.net/qq_61313896/article/details/128824383

标签:Spring,Aspect,Advisor
0
投稿

猜你喜欢

  • 基于ClasspathResource路径问题的解决

    2022-03-29 21:23:22
  • spring-boot-maven-plugin:打包时排除provided依赖问题

    2023-07-18 02:12:11
  • Java并发CopyOnWrite容器原理解析

    2023-08-15 09:06:18
  • 在idea中将创建的java web项目部署到Tomcat中的过程图文详解

    2022-10-24 23:58:25
  • C#生成单页静态页简单实例

    2022-01-22 20:00:57
  • C#对多个集合和数组的操作方法(合并,去重,判断)

    2021-12-11 14:02:44
  • Spring spel表达式使用方法示例

    2023-08-25 00:43:32
  • Java使用OpenCV3.2实现视频读取与播放

    2023-11-23 06:14:02
  • Android TextView中文字通过SpannableString设置属性用法示例

    2023-07-26 07:11:51
  • Java8通过Function获取字段名的步骤

    2022-07-14 14:06:23
  • C++右值引用与move和forward函数的使用详解

    2023-07-05 19:27:33
  • 解决BigDecimal转long丢失精度的问题

    2022-07-16 13:44:22
  • Java俄罗斯方块小游戏

    2021-12-01 04:36:49
  • 详解MyBatis逆向工程

    2021-12-12 02:38:04
  • android TextView中识别多个url并分别点击跳转方法详解

    2023-06-21 04:42:32
  • 关于线程池你不得不知道的一些设置

    2021-06-08 11:34:45
  • Java文件读写IO/NIO及性能比较详细代码及总结

    2021-11-28 12:56:30
  • C#递归实现回文判断算法

    2022-06-14 13:45:16
  • Apache Commons Math3探索之多项式曲线拟合实现代码

    2023-11-16 22:01:56
  • Java集合之Set接口及其实现类精解

    2022-01-23 17:27:44
  • asp之家 软件编程 m.aspxhome.com