首页 > 编程语言 >Spring源码第十七讲 @Aspect 到 Advisor

Spring源码第十七讲 @Aspect 到 Advisor

时间:2024-08-27 20:21:50浏览次数:11  
标签:Spring void System class 源码 Advisor println public out

先做一些准备工作

public class A017 {
    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.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    static class Target1 {
        public void foo() {
            System.out.println("target1 foo");
        }
    }

    static class Target2 {
        public void bar() {
            System.out.println("target2 bar");
        }
    }

    @Aspect // 高级切面类
    static class Aspect1 {
        @Before("execution(* foo())")
        public void before() {
            System.out.println("aspect before...");
        }

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

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

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

表示 准备工作做好了

1.findEligibleAdvisors

context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);

        context.refresh();
        // for (String name : context.getBeanDefinitionNames()) {
        //     System.out.println(name);
        // }
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        List<Advisor> advisors = creator.findEligibleAdvisors(Target1.class, "target1");
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }

 

第一个是Spring给所有代理添加的,第二个是Config里的低级切面。

第三第四是高级切面里拆出来的before和after。

2.wrapIfNecessary

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();

 

 总结:

  1. findEligibleAdvisors 找到有【资格】的 Advisors

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

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

  2. wrapIfNecessary

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

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

3. 创建时机

package org.springframework.aop.framework.autoproxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
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.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;

/**
 * ClassName: A17_1copy
 * Package: org.springframework.aop.framework.autoproxy
 * Description:
 *
 * @Author: 1043
 * @Create: 2024/8/27 - 19:50
 * @Version: v1.0
 */
public class A17_1copy {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(Config.class);
        context.refresh();
        context.close();
        // 创建 -> (*) 依赖注入 -> 初始化 (*)
    }

    @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()");
        }

        @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()");
        }
    }
}

此时Bean单向依赖Bean1输出

 可见先初始化再生成代理

将Bean1改为依赖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()");
        }
    }

 

 此时先生成Bean1的代理再初始化。

4.

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

标签:Spring,void,System,class,源码,Advisor,println,public,out
From: https://blog.csdn.net/m0_56369671/article/details/141573020

相关文章

  • 基于Java Springboot高校教师工作量管理系统
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • 基于Java Springboot闲置物品共享平台
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • 基于Java Springboot母婴全程服务管理系统
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • 基于Java Springboot失物招领系统
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • 基于Java Springboot个人健康管理系统
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • 基于Java Springboot个人健康管理系统
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • 基于Java Springboot失物招领系统
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • 基于Java Springboot母婴全程服务管理系统
    一、作品包含源码+数据库+设计文档万字+PPT+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css、Js、Vue、Element-ui数据库:MySQL后端技术:Java、SpringBoot、MyBatis三、运行环境开发工具:IDEA/eclipse数据库:MySQL5.7数据库管理工具:Navicat10以上版本环境......
  • Spring 各版本发布时间与区别
    版本版本特性SpringFramework1.01.所有代码都在一个项目中2.支持核心功能IoC、AOP3.内置支持Hibernate、iBatis等第三方框架4.对第三方技术简单封装。如:JDBC、Mail、事务等5.只支持XML配置方式。6.主要通过XML配置文件来管理对象和依赖关系,配置工作较为繁......
  • springBoot应用使用exe4j与innosetup打包为exe可执行程序手把手教学
    文章目录1.welecome2.选择JARinEXEmode3.应用信息4.Executableinfo5.启动配置6.JRE7.生成可执行exe文件8.点击exe启动查看进程9.查看日志10.使用innosetup工具进行二次打包10.1安装innosetup10.2编译后exe文件安装界面乱码解决10.3安装及验证11.总结1.welecome......