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

 更新时间:2023年02月08日 08:39:18   作者:tanglin_030907031026  
这篇文章主要介绍了Spring从@Aspect到Advisor使用演示实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

演示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 (环绕通知)

到此这篇关于Spring从@Aspect到Advisor使用演示实例的文章就介绍到这了,更多相关Spring @Aspect Advisor内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现顺序栈原理解析

    Java实现顺序栈原理解析

    这篇文章主要介绍了Java实现顺序栈原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java利用InputStream类实现文件读取与处理

    Java利用InputStream类实现文件读取与处理

    在Java开发中,输入流(InputStream)是一个非常重要的概念,它涉及到文件读写、网络传输等多个方面,InputStream类是Java中输入流的抽象基类,定义了读取输入流数据的方法,本文将以InputStream类为切入点,介绍Java中的输入流概念及其应用,需要的朋友可以参考下
    2023-11-11
  • SpringBoot指标监控功能实现

    SpringBoot指标监控功能实现

    这篇文章主要介绍了SpringBoot指标监控功能实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • 利用Jacob将Excel转换PDF的问题汇总

    利用Jacob将Excel转换PDF的问题汇总

    项目中经常会遇到将excel转换成PDF的需求,下面这篇文章主要给大家介绍了关于如何利用Jacob将Excel转换PDF问题的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • 对spring task和线程池的深入研究

    对spring task和线程池的深入研究

    这篇文章主要介绍了对spring task和线程池的深入研究,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Spring Boot 3.0升级指南

    Spring Boot 3.0升级指南

    这篇文章主要为大家介绍了Spring Boot 3.0升级指南,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • java中的类URL与URLConnection使用介绍

    java中的类URL与URLConnection使用介绍

    这篇文章主要为大家介绍了java中的类URL与URLConnection使用介绍,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • Java 使用反射调用jar包中的类方式

    Java 使用反射调用jar包中的类方式

    这篇文章主要介绍了Java 使用反射调用jar包中的类方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • 详解Java动态字节码技术

    详解Java动态字节码技术

    Java字节码增强指的是在Java字节码生成之后,对其进行修改,增强其功能,可减少冗余代码,提高性能等。本文将详细介绍Java动态字节码技术。
    2021-05-05
  • springmvc使用JSR-303进行数据校验实例

    springmvc使用JSR-303进行数据校验实例

    本篇文章主要介绍了详解springmvc使用JSR-303进行数据校验,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-02-02

最新评论