Spring 深入源码学习

1.BeanFactory 与 Application的区别

//springboot的启动方法返回的就是applicationContext实现对象
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
  • 到底什么是 BeanFactory

                - 它是 ApplicationContext 的父接口
                - 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能

  • BeanFactory能干点啥

                - 表面上只有 getBean
                - 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供

        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Map map = (Map) singletonObjects.get(beanFactory);
        map.entrySet().stream().forEach(e -> {
                    //打印spring容器中的单例Bean
                    System.out.println(e.getKey() + "=" + e.getValue());
                });
  • ApplicationContext 比 BeanFactory 功能多点啥

Spring 深入源码学习_第1张图片

1)国家化

如果需要配置请参考SpringBoot 国际化_naki_bb的博客-CSDN博客

        System.out.println(context.getMessage("hi", null, Locale.CHINA));
        System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
        System.out.println(context.getMessage("hi", null, Locale.JAPANESE))

2)加载资源

        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }

3)获取环境资源

        System.out.println(context.getEnvironment().getProperty("java_home"));
        System.out.println(context.getEnvironment().getProperty("server.port"));

4)事件发布,新解耦方式

//自定义事件
class MyEvent extends ApplicationEvent {
    MyEvent(Object source) {
        super(source);
    }
}

//发布自定义事件
@Component
public class MyEventPublisher {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void publish() {
        publisher.publishEvent(new MyEvent(this));
    }
}
//监听自定义事件
@Component
public class MyEventListener {

    @EventListener
    public void aaa(MyEvent event){
        System.out.println("aaa监控到了My event事件");
    }

    @EventListener
    public void bbb(MyEvent event){
        System.out.println("bbb监控到了My event事件");
    }
}

//调用事件发布方法
        MyEventPublisher myEventPublisher = context.getBean(MyEventPublisher.class);
        myEventPublisher.publish();

2.实例化Bean的流程

  • BeanFactory加载BeanDefinition信息
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // bean 的定义(class, scope, 初始化, 销毁)
        AbstractBeanDefinition beanDefinition =
                BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
  • 给BeanFactory添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
  •  BeanFactory 后处理器主要功能,补充了一些 bean 定义
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
  •  Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
                .sorted(beanFactory.getDependencyComparator())
                .forEach(beanPostProcessor -> {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });
  • 创建的单例
        //可以查看beanFactory中所有BeanDefinition的
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        //准备好所有单例
        beanFactory.preInstantiateSingletons();

 由上可以发现

            a. beanFactory 不会做的事
                   1. 不会主动调用 BeanFactory 后处理器
                   2. 不会主动添加 Bean 后处理器
                   3. 不会主动初始化单例
                   4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
            b. bean 后处理器会有排序的逻辑

3.常见ApplicationContext实现

  • ClassPathXmlApplicationContext

经典的容器, 基于 classpath 下 xml 格式的配置文件来创建spring容器

        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("a02.xml");

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

基于磁盘路径下 xml 格式的配置文件来创建

 FileSystemXmlApplicationContext context =
                new FileSystemXmlApplicationContext(
                        "src\\main\\resources\\a02.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
  • AnnotationConfigApplicationContext

经典的容器, 基于 java 注解配置类来创建

        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
  • AnnotationConfigServletWebServerApplicationContext

经典的容器, 基于 java 配置类来创建, 用于 web 环境

        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

    @Configuration
    static class WebConfig {
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }

4.Spring自带Bean后处理器

GenericApplicationContext 是一个【干净】的容器 

当需要让这个容器可以识别@Autowired,@Value时,需要添加如下后处理器

context.getDefaultListableBeanFactory()
     .setAutowireCandidateResolver(
        new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class); // @Autowired @Value

当需要让这个容器可以识别@Resource @PostConstruct @PreDestroy

context.registerBean(CommonAnnotationBeanPostProcessor.class);

当需要让这个容器可以识别@ConfigurationProperties

ConfigurationPropertiesBindingPostProcessor
    .register(context.getDefaultListableBeanFactory());

初始化容器,执行beanFactory后处理器, 执行bean后处理器,

context.refresh(); 

销毁容器

context.close();

5.模拟解析@Bean和@CompentScan的后处理器

配置类如下:

@Configuration
@ComponentScan("com.itheima.a05.component")
public class Config {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean(initMethod = "init")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}

@Bean解析注入容器


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;

public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
			//获取Config的源数据
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/itheima/a05/Config.class"));
			//获取所有使用@Bean的方法
            Set methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method : methods) {
                //解析包含@Bean包含initMethod属性值
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
				//根据容器中已经存在名为config的Bean的方法名实例化Bean
                builder.setFactoryMethodOnBean(method.getMethodName(), "config");
				//在使用构造器方式注入
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (initMethod.length() > 0) {
					builder.setInitMethodName(initMethod);
                }
				//根据builder生成BeanDefinition信息
                AbstractBeanDefinition bd = builder.getBeanDefinition();
				//实例化Bean根据BeanDefinition,spring的id为方法名
                beanFactory.registerBeanDefinition(method.getMethodName(), bd);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@ComponentScan

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;

public class ComponentScanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override // context.refresh
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
			//获取Config实例中的ComponentScan注解
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                for (String p : componentScan.basePackages()) {
					//配置的包信息为“.”,Resource则加载文件“/”分割
                    // com.itheima.a05.component -> classpath*:com/itheima/a05/component/**/*.class
                    String path = "classpath*:" + p.replace(".", "/") + "/**/*.class";
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
					//根据路径,获取所有的.class
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources) {
                        //获取Resource的源数据
                        MetadataReader reader = factory.getMetadataReader(resource);
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
						//因为@Service,@Controller等都是@Component的派生类,则需要两个都判断
                        // System.out.println("是否加了 @Component:" + annotationMetadata.hasAnnotation(Component.class.getName()));
                        // System.out.println("是否加了 @Component 派生:" + annotationMetadata.hasMetaAnnotation(Component.class.getName()));
                        if (annotationMetadata.hasAnnotation(Component.class.getName())
                            || annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            AbstractBeanDefinition bd = BeanDefinitionBuilder
                                    .genericBeanDefinition(reader.getClassMetadata().getClassName())
                                    .getBeanDefinition();
                            String name = generator.generateBeanName(bd, beanFactory);
                            beanFactory.registerBeanDefinition(name, bd);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

将自定义的后处理器注册给Spring容器

context.registerBean(AtBeanPostProcessor.class); // 解析 @Bean
context.registerBean(ComponentScanPostProcessor.class); // 解析 @Component

6.Aware接口及InitializingBean 接口

Aware 接口提供了一种【内置】 的注入手段,例如

  • BeanNameAware 注入 bean 的名字

  • BeanFactoryAware 注入 BeanFactory 容器

  • ApplicationContextAware 注入 ApplicationContext 容器

  • EmbeddedValueResolverAware 注入 ${} 解析器

InitializingBean 接口提供了一种【内置】的初始化手段

对比

  • 内置的注入和初始化不受扩展功能的影响,总会被执行

  • 而扩展功能受某些情况影响可能会失效

  • 因此 Spring 框架内部的类常用内置注入和初始化

配置类 @Autowired 失效分析

Java 配置类不包含 BeanFactoryPostProcessor 的情况

Spring 深入源码学习_第2张图片

Java 配置类包含 BeanFactoryPostProcessor 的情况,因此要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效

Spring 深入源码学习_第3张图片

 对应的代码:

@Configuration
public class MyConfig1 {

    private static final Logger log = LoggerFactory.getLogger(MyConfig1.class);

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        log.debug("注入 ApplicationContext");
    }

    @PostConstruct
    public void init() {
        log.debug("初始化");
    }

    @Bean //注释或添加 beanFactory 后处理器对应上方两种情况
    public BeanFactoryPostProcessor processor1() {
        return beanFactory -> {
            log.debug("执行 processor1");
        };
    }

}

因为MyConfig1配置类中包含实例化自定义BeanFactoryPostProcessor则会先实例化这个配置类,但是因为没有设置自带的BeanFactoryPostProcessor和BeanPostProcessor则,@Autowired,@PostConstruct都没有处理的后处理器,则会注入失败。

则可以使用Aware和InitializingBean接口的内置注入手段,使其一定会先被执行


@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {

    private static final Logger log = LoggerFactory.getLogger(MyConfig2.class);

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.debug("注入 ApplicationContext");
    }

    @Bean //  beanFactory 后处理器
    public BeanFactoryPostProcessor processor2() {
        return beanFactory -> {
            log.debug("执行 processor2");
        };
    }
}

注意

解决方法:

  • 用内置依赖注入和初始化取代扩展依赖注入和初始化

  • 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建

7.初始化和销毁

初始化

Spring 提供了多种初始化手段, @PostConstruct,@Bean(initMethod) 之外,还可以实现 InitializingBean 接口来进行初始化,如果同一个 bean 用了以上手段声明了 3 个初始化方法,那么它们的执行顺序是

  1. @PostConstruct 标注的初始化方法

  2. InitializingBean 接口的初始化方法

  3. @Bean(initMethod) 指定的初始化方法

    @Bean(initMethod = "init3")
    public Bean1 bean1() {
        return new Bean1();
    }

public class Bean1 implements InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    @PostConstruct
    public void init1() {
        log.debug("初始化1");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("初始化2");
    }

    public void init3() {
        log.debug("初始化3");
    }
}

销毁

Spring 也提供了多种销毁手段,执行顺序为

  1. @PreDestroy 标注的销毁方法

  2. DisposableBean 接口的销毁方法

  3. @Bean(destroyMethod) 指定的销毁方法

    @Bean(destroyMethod = "destroy3")
    public Bean2 bean2() {
        return new Bean2();
    }

public class Bean2 implements DisposableBean {
    private static final Logger log = LoggerFactory.getLogger(Bean2.class);

    @PreDestroy
    public void destroy1() {
        log.debug("销毁1");
    }

    @Override
    public void destroy() throws Exception {
        log.debug("销毁2");
    }

    public void destroy3() {
        log.debug("销毁3");
    }
}

8.Scope 失效问题

在当前版本的 Spring 和 Spring Boot 程序中,支持五种 Scope

  • singleton,容器启动时创建(未设置延迟),容器关闭时销毁

  • prototype,每次使用时创建,不会自动销毁,需要调用 DefaultListableBeanFactory.destroyBean(bean) 销毁

  • request,每次请求用到此 bean 时创建,请求结束时销毁

  • session,每个会话用到此 bean 时创建,会话结束时销毁

  • application,web 容器用到此 bean 时创建,容器停止时销毁

当在单例对象中注入多例对象,直接使用@Autowired时会,导致注入的Bean始终都是同一个,不是多例的。

问题出现的原因是,对于单例对象,属性的注入只会发生一次,所以单例中注入的多例对象始终都是第一次注入的。

解决方案: 推迟多例Bean的注入

1.使@Lazy生成代理对象,每次使用时,代理对象会创建新的多例对象

@Component
public class E {
    @Lazy
    @Autowired
    private F1 f1;
}

@Scope("prototype")
@Component
public class F1 {
}

2.在多例Bean的Scope中添加 proxyMode 属性 底层也是利用代理对象

@Component
public class E {
    @Autowired
    private F2 f2;
}

@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}

3.使用ObjectFactory工厂获取多例Bean

import org.springframework.beans.factory.ObjectFactory;
@Component
public class E {
    @Autowired
    private ObjectFactory f3;

    public F3 getF3() {
        //使用时,使用getObject就可得到多例的Bean对象
        return f3.getObject();
    }
}

@Scope("prototype")
@Component
public class F3 {
}

4.使用ApplicationContext获取多例Bean

@Component
public class E {
    @Autowired
    private ApplicationContext context;

    public F4 getF4() {
        return context.getBean(F4.class);
    }
}

@Scope("prototype")
@Component
public class F4 {
}

使用代理对象对性能有影响,所以推荐3-4方式,在单例对象中获取多例对象实例 

9.AOP实现

AOP 底层实现方式之一是代理,由代理结合通知和目标,提供增强功能

Spring底层实现是基于JDK和Cglib生成代理对象

除此以外,aspectj 提供了两种另外的 AOP 底层实现:

  • 第一种是通过 ajc 编译器在编译 class 类文件时,就把通知的增强功能,织入到目标类的字节码中

  • 第二种是通过 agent 在加载目标类时,修改目标类的字节码,织入增强功能

  • 作为对比,之前学习的代理是运行时生成新的字节码

简单比较的话:

  • aspectj 在编译和加载时,修改目标字节码,性能较高

  • aspectj 因为不用代理,能突破一些技术上的限制,例如对构造、对静态方法、对 final 也能增强

  • 但 aspectj 侵入性较强,且需要学习新的 aspectj 特有语法,因此没有广泛流行

@Aspect //注意此切面并未被 Spring 管理
public class MyAspect {

    private static final Logger log = LoggerFactory.getLogger(MyAspect.class);

    @Before("execution(* com.itheima.service.MyService.*())")
    public void before() {
        log.debug("before()");
    }
}

@Service
public class MyService {

    private static final Logger log = LoggerFactory.getLogger(MyService.class);

    final public void foo() {
        log.debug("foo()");
        this.bar();
    }

    public void bar() {
        log.debug("bar()");
    }
}

通过ajc编译器实现AOP

aspectj-maven-plugin

  1. 编译器也能修改 class 实现增强

  2. 编译器增强能突破代理仅能通过方法重写增强的限制:可以对构造方法、静态方法等实现增强

注意

  • 版本选择了 java 8, 因为目前的 aspectj-maven-plugin 1.14.0 最高只支持到 java 16

  • 一定要用 maven 的 compile 来编译, idea 不会调用 ajc 编译器

            
                org.codehaus.mojo
                aspectj-maven-plugin
                1.14.0
                
                    1.8
                    8
                    8
                    true
                    true
                    ignore
                    UTF-8
                
                
                    
                        
                            
                            compile
                            
                            test-compile
                        
                    
                
            

直接在编译阶段就会修改class文件,对其进行修改实现功能增强.在调用MyService的所有方法时,都会增强before方法

agent类加载实现AOP

VM options 里加入 -javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar

使用上面agent,MyService在编译完成时,方法已经增强

JDK生成动态代理

public class JdkProxyDemo {

    interface Foo {
        void foo();
    }

    static class Target implements Foo {
        public void foo() {
            System.out.println("target foo");
        }
    }

    public static void main(String[] param) {
        // 目标对象
        Target target = new Target();
        // 代理对象
        Foo proxy = (Foo) Proxy.newProxyInstance(
                Target.class.getClassLoader(), new Class[]{Foo.class},
                (p, method, args) -> {
                    System.out.println("proxy before...");
                    Object result = method.invoke(target, args);
                    System.out.println("proxy after...");
                    return result;
                });
        // 调用代理
        proxy.foo();
    }
}
  • jdk 动态代理要求目标必须实现接口,生成的代理类实现相同接口,因此代理与目标之间是平级兄弟关系

  1. 前 16 次反射性能较低

  2. 第 17 次调用会生成代理类,优化为非反射调用

CGLIB生成代理对象

public class CglibProxyDemo {

    static class Target {
        public void foo() {
            System.out.println("target foo");
        }
    }

    public static void main(String[] param) {
        // 目标对象
        Target target = new Target();
        // 代理对象
        Target proxy = (Target) Enhancer.create(Target.class, 
                (MethodInterceptor) (p, method, args, methodProxy) -> {
            System.out.println("proxy before...");
            Object result = methodProxy.invoke(target, args);
            // 另一种调用方法,不需要目标对象实例
//            Object result = methodProxy.invokeSuper(p, args);
            System.out.println("proxy after...");
            return result;
        });
        // 调用代理
        proxy.foo();
    }
}
  • cglib 不要求目标实现接口,它生成的代理类是目标的子类,因此代理与目标之间是子父关系

  • 限制⛔:根据上述分析 final 类无法被 cglib 增强

调用目标时有所改进,见下面代码片段

  1. method.invoke 是反射调用,必须调用到足够次数才会进行优化

  2. methodProxy.invoke 是不反射调用,它会正常(间接)调用目标对象的方法(Spring 采用)

  3. methodProxy.invokeSuper 也是不反射调用,它会正常(间接)调用代理对象的方法,可以省略目标对象

AOP通知调用

代理对象调用流程如下(以 JDK 动态代理实现为例)

代理对象调用流程如下(以 JDK 动态代理实现为例)

  • 从 ProxyFactory 获得 Target 和环绕通知链,根据他俩创建 MethodInvocation,简称 mi

  • 首次执行 mi.proceed() 发现有下一个环绕通知,调用它的 invoke(mi)

  • 进入环绕通知1,执行前增强,再次调用 mi.proceed() 发现有下一个环绕通知,调用它的 invoke(mi)

  • 进入环绕通知2,执行前增强,调用 mi.proceed() 发现没有环绕通知,调用 mi.invokeJoinPoint() 执行目标方法

  • 目标方法执行结束,将结果返回给环绕通知2,执行环绕通知2 的后增强

  • 环绕通知2继续将结果返回给环绕通知1,执行环绕通知1 的后增强

  • 环绕通知1返回最终的结果

图中不同颜色对应一次环绕通知或目标的调用起始至终结

Spring 深入源码学习_第4张图片

你可能感兴趣的:(Spring,spring,java)