zoukankan      html  css  js  c++  java
  • 细读Spring源码(六)Spring源码设计架构

    往期回顾:

    今天早上又回顾了一下源码,总结出了下面的这张Spring设计思想图,其实网上有很多相关的图,我主要还是按照核心方法refesh的流程总结的,因为这也是Spring容器启动过程中初始化的核心,话不多说,直接上图:

    我将容器的启动过程粗略地分成了上面的五个阶段,首先可以看到从始至终都要与BeanFactory进行交互,所以先来看看BeanFactory这个接口:

    在源码中是这样描述的:

     1 /**
     2  * The root interface for accessing a Spring bean container.
     3  * 访问Spring bean容器的根接口
     4  *
     5  * <p>This is the basic client view of a bean container;
     6  * further interfaces such as {@link ListableBeanFactory} and
     7  * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
     8  * are available for specific purposes.
     9  * BeanFactory是访问Spring bean容器的根接口,这是一个bean容器基本的客户端视图,
    10  * 此外还有像ListableBeanFactory和ConfigurableBeanFactory这种为了特定目标使用的接口
    11  *
    12  * <p>This interface is implemented by objects that hold a number of bean definitions,
    13  * each uniquely identified by a String name. Depending on the bean definition,
    14  * the factory will return either an independent instance of a contained object
    15  * (the Prototype design pattern), or a single shared instance (a superior
    16  * alternative to the Singleton design pattern, in which the instance is a
    17  * singleton in the scope of the factory). Which type of instance will be returned
    18  * depends on the bean factory configuration: the API is the same. Since Spring
    19  * 2.0, further scopes are available depending on the concrete application
    20  * context (e.g. "request" and "session" scopes in a web environment).
    21  * 该接口会被持有大量bean定义的对象实现,每一个都是通过一个字符串类型的name进行唯一标识。
    22  * 根据bean的定义信息,工厂既可以返回一个已经存在对象的单独实例实例(原型设计模式),还可以返回一个能够被共享的单例实例(单例模式)
    23  * 返回什么类型的实例,将依赖bean工厂中scope的配置:具有相同的API。从Spring2.0开始,可以根据具体的应用上下文使用其他的scope,
    24  * 比如web应用中的request和session等
    25  *
    26  * <p>The point of this approach is that the BeanFactory is a central registry
    27  * of application components, and centralizes configuration of application
    28  * components (no more do individual objects need to read properties files,
    29  * for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design and
    30  * Development" for a discussion of the benefits of this approach.
    31  * 这种实现方式的精髓在于它让BeanFactory成为应用组件的注册和配置中心,比如单个对象将不再需要去读取属性文件
    32  * 在《Expert One-on-One J2EE Design and Development》这本书的第4~11节就能讨论了该方法的优势
    33  *
    34 /

    从上面注释中可以获取三点重要信息:

    1、这是访问Spring容器的根接口

    2、这个接口被维护BeanDefinition信息的接口所继承,提供了对bean定义信息的管理,通过该接口,可以返回单例或多例的bean实例

    3、它就像一个应用组件的注册和配置中心,集中管理容器中的bean,而不需要为了某个单独的bean单独读取配置文件

    下面这种图中右边部分是该接口中的所有方法,左边注释部分说明实现该接口的工厂必须尽可能地支持标准bean生命周期的接口,同时给出了全部的初始化方法和它们的标准执行顺序,其实主要就是在实例化前后执行的BeanPostProcessor及它们的执行顺序。

    接下来看看每个阶段在容器内都发生了什么事情:

    第一阶段:注册BeanDefinition

    BeanDefinition是一个接口,继承了AttributeAccessor, BeanMetadataElement ,用来管理Bean的属性和元数据,管理的数据有属性、构造器、参数、是否单例、是否懒加载等这些我们平时定义的信息。在这个阶段,主要是扫描我们定义的Java类,定义的方式有基于XML和基于注解两种方式,将每个类的描述信息封装成一个BeanDefinition对象,注册到工厂中,生成一个beanName->BeanDefinition的映射关系,以便后续使用。

    第二阶段:执行BeanFactoryPostProcessor

    在BeanDefinition中有下面这样一段注释信息:

    This is just a minimal interface: The main intention is to allow a BeanFactoryPostProcessor to introspect and modify property values and other bean metadata.

    翻译过来意思就是说:BeanDefinition只是一个最小的接口,设计它的主要目的是为了让BeanFactoryPostProcessor内省并修改属性值和其他bean的元信息,所以执行BeanFactoryPostProcessor的主要目的就是可以通过自定义实现对bean定义信息的修改,比如修改属性等。其实这个接口是bean工厂的后置处理器,它的操作范围是整个工厂,通过实现该接口,我们可以获取到工厂中已经注册的所有bean的定义信息,并对任意信息进行修改,下面举个例子:

     首先,定义一个bean

     1 package com.spring.reading.bd.processor;
     2 
     3 import lombok.AllArgsConstructor;
     4 import lombok.Data;
     5 import lombok.NoArgsConstructor;
     6 import lombok.ToString;
     7 import org.springframework.beans.factory.config.BeanDefinition;
     8 import org.springframework.context.annotation.Scope;
     9 import org.springframework.stereotype.Component;
    10 
    11 /**
    12  * @author: cyhua
    13  * @createTime: 2021/12/6
    14  * @description: 定义一个普通的bean,含有一个属性,scope手动设置原型
    15  */
    16 @Data
    17 @Component
    18 @ToString
    19 @NoArgsConstructor
    20 @AllArgsConstructor
    21 @Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
    22 public class Company {
    23 
    24     private String name;
    25 
    26 
    27 }

    注意:上面的第21行代码,将scope自定义为原型,即多例,为了在BeanFactoryPostProcessor中对它进行修改!!!

    其次,自定义一个BeanFactoryPostProcessor

     1 package com.spring.reading.bd.processor;
     2 
     3 import org.apache.commons.lang3.StringUtils;
     4 import org.springframework.beans.BeansException;
     5 import org.springframework.beans.factory.FactoryBean;
     6 import org.springframework.beans.factory.config.BeanDefinition;
     7 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
     8 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
     9 import org.springframework.beans.factory.config.ConstructorArgumentValues;
    10 import org.springframework.beans.factory.support.AbstractBeanDefinition;
    11 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    12 import org.springframework.stereotype.Component;
    13 
    14 /**
    15  * @author: cyhua
    16  * @createTime: 2021/12/5
    17  * @description: bean工厂后置处理器
    18  */
    19 @Component
    20 public class ReadingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    21     @Override
    22     public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    23         AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) configurableListableBeanFactory.getBeanDefinition("company");
    24         //获取构造函数的参数值
    25         ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
    26         //获取是否懒加载配置
    27         Boolean lazyInit = beanDefinition.isLazyInit();
    28         //获取scope配置
    29         String scope = beanDefinition.getScope();
    30         //获取注入模式配置:byName或byType
    31         int autowireMode = beanDefinition.getAutowireMode();
    32         //scope如果为空或多例,则修改scope为单例
    33         if (StringUtils.isBlank(scope) || scope.equals(BeanDefinition.SCOPE_PROTOTYPE)) {
    34             beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
    35         }
    36     }
    37 
    38 }

    上面代码中获取了几个比较常见的BeanDefinition信息,最后当scope为空或者为多例时,修改为单例。

    接下来,写一个测试类,获取两个Company对象,并进行比较

     1 package com.spring.reading.bd.processor;
     2 
     3 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
     4 
     5 /**
     6  * @author: cyhua
     7  * @createTime: 2021/12/5
     8  * @description:
     9  */
    10 public class BeanDefinitionCaller {
    11 
    12 
    13     public static void main(String[] args) {
    14         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanDefinitionConfig.class);
    15         Company company1 = context.getBean("company", Company.class);
    16         Company company2 = context.getBean("company", Company.class);
    17         //比较两个对象是否相同:按道理已经设置成单例,会返回true
    18         System.out.println(company1 == company2);
    19     }
    20 }

    上面15、16行代码通过相同的beanName获取了两次bean实例

    下面进行debug,看看在BeanFactoryPostProcessor中是否能获取到bean定义信息?

     可以看当程序成功进入自定义的bean工厂后置处理器,也获取到了具体的BeanDefinition,下面看下执行结果:

     可以看到获取到了两个相同的对象,说明bean工厂后置处理器生效,修改bean定义成功,这就是执行BeanFactoryPostProcessor的作用,主要还是为了处理自定义的逻辑,方便开发者进行扩展,而且整个扩展过程完全满足OCP原则,忍不住想说一句:妙!

    第三阶段:注册BeanPostProcessors、监听器等

    第三个阶段主要还是准备一些后续需要的特殊bean,比如bean的后置处理器BeanPostProcessor、用户处理国际化的MessageSource、发布事件的广播器ApplicationEventMulticaster以及监听事件的监听器,下面针对这四种特殊的bean进行说明:

    1.BeanPostProcessor

    BeanPostProcessor就是一个接口,包含两个方法:

     1    /**
     2      * 在bean实例化之后,初始化之前使用,可以对返回对实例进行修改,比如修改属性值
     3      * @param bean   要处理的bean实例
     4      * @param beanName  要处理的bean名称
     5      * @return     返回处理后的实例,默认返回传进来的实例
     6      * @throws BeansException
     7      */
     8     @Nullable
     9     default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    10         return bean;
    11     }
    12 
    13    /**
    14      * 在bean初始化之后执行,可以对完成初始化的对象进行进一步的处理,比如生成代理对象,AOP中使用
    15      * @param bean 要处理的bean
    16      * @param beanName 要处理的bean名称
    17      * @return
    18      * @throws BeansException 返回处理后的实例,默认返回传进来的实例
    19      */
    20     @Nullable
    21     default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    22         return bean;
    23     }

    如注释所述,该接口提供了两个默认实现的方法,用于在初始化前后,对已经完成实例化的对象进行处理,虽然是接口,但是因为有了默认实现,开发时无需实现,但是可以通过自定义的后置处理器对bean进行特殊的处理,在AOP中,代理对象的生成就是利用了这里的postProcessAfterInitialization方法。

     可以看到在spring中,已经又了很多该接口的实现类!

    2.MessageSource

    用于处理国际化的接口,源码中是这样描述的:

     1 /**
     2  * Strategy interface for resolving messages, with support for the parameterization
     3  * and internationalization of such messages.
     4  *
     5  * <p>Spring provides two out-of-the-box implementations for production:
     6  * <ul>
     7  * <li>{@link org.springframework.context.support.ResourceBundleMessageSource}: built
     8  * on top of the standard {@link java.util.ResourceBundle}, sharing its limitations.
     9  * <li>{@link org.springframework.context.support.ReloadableResourceBundleMessageSource}:
    10  * highly configurable, in particular with respect to reloading message definitions.
    11  * </ul>
    12 /

    1、解析消息的策略接口,能够支持消息的参数化和国际化。

    2、在Spring中提供了两个开箱即用的实现类:

    一个构建在Java标准ResourceBundle之上的类ResourceBundleMessageSource

    一个高度可配置的ReloadableResourceBundleMessageSource,值得一提的就是它能够重载消息定义

    一般在支持国际化的项目中需要用到,知道有这么个接口即可!

    3.ApplicationEventMulticaster

    用户发布事件的接口,它的继承关系图如下:

     有两个存在继承关系的实现类,这个在之前spring中的设计模式一文中有分析其源码,使用的是观察者模式,这里不再赘述。

    4.ApplicationListener

    有事件发布,就有事件监听,这个接口跟上面的广播器构成了观察者模式,用来处理spring中各种事件, 在设计模式中也讲过,这里不再赘述!

    第四阶段:创建bean(实例化-初始化-放入容器)

    下面来到第四个阶段,也是最重要、最复杂的一个阶段,前三个阶段都是在为这个阶段做准备的,在这个阶段,需要有一个意识:就是spring创建一个完整的对象需要经过三个大的步骤:

    实例化-->属性填充-->初始化,而在初始化前后又可能会执行一些后置处理器

    实例化阶段:只是在内存中开辟了一块空间,底层是通过bean定义信息推断出无参构造函数,然后选择合适的策略进行实例化,最后返回一个被Wrapper包装的实例,核心代码如下,一个位于BeanUtils类中的静态方法:

     1 /**
     2      * Convenience method to instantiate a class using the given constructor.
     3      * <p>Note that this method tries to set the constructor accessible if given a
     4      * non-accessible (that is, non-public) constructor, and supports Kotlin classes
     5      * with optional parameters and default values.
     6      * 使用给定的构造器调用实例化方法,需要注意的是,如果传递的是一个无访问全县的构造器,比如非public的,这个方法首先会尝试开启访问权限
     7      *,而且通过可选参数支持Kotlin类和默认值
     8      * @param ctor the constructor to instantiate  实例化构造器
     9      * @param args the constructor arguments to apply (use {@code null} for an unspecified 构造器参数
    10      * parameter, Kotlin optional parameters and Java primitive types are supported)
    11      * @return the new instance
    12      * @throws BeanInstantiationException if the bean cannot be instantiated
    13      * @see Constructor#newInstance
    14      */
    15     public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
    16         Assert.notNull(ctor, "Constructor must not be null");
    17         try {
    18             //尝试将构造函数设置为可访问的
    19             ReflectionUtils.makeAccessible(ctor);
    20             if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
    21                 return KotlinDelegate.instantiateClass(ctor, args);
    22             }
    23             else {
    24                 //获取构造器中的参数
    25                 Class<?>[] parameterTypes = ctor.getParameterTypes();
    26                 //判断构造器中的参数个数是否比传进来的参数个数少,多则抛异常
    27                 Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
    28                 Object[] argsWithDefaultValues = new Object[args.length];
    29                 //组装构造器的参数
    30                 for (int i = 0 ; i < args.length; i++) {
    31                     if (args[i] == null) {
    32                         Class<?> parameterType = parameterTypes[i];
    33                         argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
    34                     }
    35                     else {
    36                         argsWithDefaultValues[i] = args[i];
    37                     }
    38                 }
    39                 //通过构造方法创建一个bean实例
    40                 return ctor.newInstance(argsWithDefaultValues);
    41             }
    42         }
    43         catch (InstantiationException ex) {
    44             throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
    45         }
    46         catch (IllegalAccessException ex) {
    47             throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
    48         }
    49         catch (IllegalArgumentException ex) {
    50             throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
    51         }
    52         catch (InvocationTargetException ex) {
    53             throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
    54         }
    55     }

    属性填充阶段:该阶段是在完成实例化之后,初始化之前执行的,填充属性,就是给属性赋值,比如数据库连接信息中有很多初始化值,就是在这个阶段进行填充

    初始化阶段:该阶段是在完成实例化及属性填充之后执行的,而且在执行真正的初始化前后又要执行一些BeanPostProcessor的后置处理器,核心代码如下,调用AbstractAutowireCapableBeanFactory#initializeBean方法:

     1 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
     2         if (System.getSecurityManager() != null) {
     3             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
     4                 invokeAwareMethods(beanName, bean);
     5                 return null;
     6             }, getAccessControlContext());
     7         }
     8         else {
     9             //执行aware:回调实现了Aware接口的方法:设置beanName、classLoader、beanFactory等
    10             invokeAwareMethods(beanName, bean);
    11         }
    12 
    13         //初始化之前执行
    14         Object wrappedBean = bean;
    15         if (mbd == null || !mbd.isSynthetic()) {
    16             wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    17         }
    18 
    19         try {
    20             //执行自定义初始化方法
    21             invokeInitMethods(beanName, wrappedBean, mbd);
    22         }
    23         catch (Throwable ex) {
    24             throw new BeanCreationException(
    25                     (mbd != null ? mbd.getResourceDescription() : null),
    26                     beanName, "Invocation of init method failed", ex);
    27         }
    28         //初始化之后执行
    29         if (mbd == null || !mbd.isSynthetic()) {
    30             wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    31         }
    32 
    33         return wrappedBean;
    34     }

    第16行,会执行BeanPostProcessor的postProcessBeforeInitialization方法

    第21行,会执行初始化方法,这个方法可以自定义,就是在bean定义是指定的init-method

    第30行,会执行BeanPostProcessor的postProcessAfterInitialization方法

    下面是完成最终初始化的核心代码,调用AbstractAutowireCapableBeanFactory#invokeInitMethods方法:

     1 /**
     2      * Give a bean a chance to react now all its properties are set,
     3      * and a chance to know about its owning bean factory (this object).
     4      * This means checking whether the bean implements InitializingBean or defines
     5      * a custom init method, and invoking the necessary callback(s) if it does.
     6      * 给bean一个反应它所有的属性都完成设置和了解它所属工厂的机会,这意味着不管bean实现了InitializingBean接口还是自定义了一个初始化方法,都会在这个地方被调用
     7      * @param beanName the bean name in the factory (for debugging purposes) :bean在工厂中的名称
     8      * @param bean the new bean instance we may need to initialize:准备去初始化的实例对象
     9      * @param mbd the merged bean definition that the bean was created with 创建该bean的合并bean定义信息
    10      * (can also be {@code null}, if given an existing bean instance)
    11      * @throws Throwable if thrown by init methods or by the invocation process
    12      * @see #invokeCustomInitMethod
    13      */
    14     protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
    15             throws Throwable {
    16 
    17         //判断是否实现了InitializingBean接口,如果实现了就去执行afterPropertiesSet方法
    18         boolean isInitializingBean = (bean instanceof InitializingBean);
    19         if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
    20             if (logger.isTraceEnabled()) {
    21                 logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
    22             }
    23             if (System.getSecurityManager() != null) {
    24                 try {
    25                     AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
    26                         ((InitializingBean) bean).afterPropertiesSet();
    27                         return null;
    28                     }, getAccessControlContext());
    29                 }
    30                 catch (PrivilegedActionException pae) {
    31                     throw pae.getException();
    32                 }
    33             }
    34             else {
    35                 ((InitializingBean) bean).afterPropertiesSet();
    36             }
    37         }
    38 
    39         //执行自定义的初始化方法
    40         if (mbd != null && bean.getClass() != NullBean.class) {
    41             String initMethodName = mbd.getInitMethodName();
    42             if (StringUtils.hasLength(initMethodName) &&
    43                     !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
    44                     !mbd.isExternallyManagedInitMethod(initMethodName)) {
    45                 invokeCustomInitMethod(beanName, bean, mbd);
    46             }
    47         }
    48     }

    如注释所述,初始化其实就是调用用户自定义的init-method方法和afterPropertiesSet方法!

    第五阶段:管理生命周期、发布刷新事件 

    这是最后一个阶段,应该说是容器启动过程,或容器实例化过程中的最后一个阶段,因为完整的过程中最后应该是要执行bean的销毁。

    这个阶段主要就是给上下文设置生命周期处理器,以管理这个上下文中bean的生命周期,如果工厂中有,就直接赋值,工厂中没有,就new一个再赋值,核心代码如下,AbstractApplicationContext#initLifecycleProcessor方法:

     1 /**
     2      * Initialize the LifecycleProcessor.
     3      * Uses DefaultLifecycleProcessor if none defined in the context.
     4      *
     5      * @see org.springframework.context.support.DefaultLifecycleProcessor
     6      */
     7     protected void initLifecycleProcessor() {
     8         ConfigurableListableBeanFactory beanFactory = getBeanFactory();
     9         if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
    10             this.lifecycleProcessor =
    11                     beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
    12             if (logger.isTraceEnabled()) {
    13                 logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
    14             }
    15         } else {
    16             DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
    17             defaultProcessor.setBeanFactory(beanFactory);
    18             this.lifecycleProcessor = defaultProcessor;
    19             beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
    20             if (logger.isTraceEnabled()) {
    21                 logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
    22                         "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
    23             }
    24         }
    25     }

    然后将上下文刷新事件通过第三阶段注册的广播器进行广播,在广播方法中,实际调用的是监听器的方法,核心代码如下:

     1 protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
     2         Assert.notNull(event, "Event must not be null");
     3 
     4         // Decorate event as an ApplicationEvent if necessary
     5         ApplicationEvent applicationEvent;
     6         if (event instanceof ApplicationEvent) {
     7             applicationEvent = (ApplicationEvent) event;
     8         } else {
     9             applicationEvent = new PayloadApplicationEvent<>(this, event);
    10             if (eventType == null) {
    11                 eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
    12             }
    13         }
    14 
    15         // Multicast right now if possible - or lazily once the multicaster is initialized
    16         if (this.earlyApplicationEvents != null) {
    17             this.earlyApplicationEvents.add(applicationEvent);
    18         } else {
    19             getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    20         }
    21 
    22         // Publish event via parent context as well...
    23         if (this.parent != null) {
    24             if (this.parent instanceof AbstractApplicationContext) {
    25                 ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
    26             } else {
    27                 this.parent.publishEvent(event);
    28             }
    29         }
    30     }

    第19行,获取广播器并广播事件,广播事件接口会传事件和事件类型:

     1 public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
     2         //第一步:调用resolveDefaultEventType方法解析事件的类型,会返回类的全限定名
     3         ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
     4         Executor executor = getTaskExecutor();
     5         //根据事件和事件类型获取监听器
     6         for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
     7             if (executor != null) {
     8                 //异步执行监听任务
     9                 executor.execute(() -> invokeListener(listener, event));
    10             }
    11             else if (this.applicationStartup != null) {
    12                 StartupStep invocationStep = this.applicationStartup.start("spring.event.invoke-listener");
    13                 invokeListener(listener, event);
    14                 invocationStep.tag("event", event::toString);
    15                 if (eventType != null) {
    16                     invocationStep.tag("eventType", eventType::toString);
    17                 }
    18                 invocationStep.tag("listener", listener::toString);
    19                 invocationStep.end();
    20             }
    21             else {
    22                 //将事件event通知给监听器listener
    23                 invokeListener(listener, event);
    24             }
    25         }
    26     }

    如上代码所示,通过invokeListener(listener, event)完成了事件的监听,具体的逻辑就交给具体的监听器处理了。

    到此为止,spring的设计思想梳理的也差不多了,知道了这些,就会对spring有一个更加具体的整体把控了,可能有些地方描述的不够清楚,都是凭自己的理解写的,仅供参考,我也会继续向前深入研究,向后回头反思!

    本文来自博客园,作者:bug改了我,转载请注明原文链接:https://www.cnblogs.com/hellowhy/p/15638373.html

  • 相关阅读:
    Spark Scala 读取GBK文件的方法
    Mac OS X 系统下自带的文本文件格式转换工具iconv
    报到
    java 字符串中含有双引号" "与单引号' '问题
    div1嵌套div2,div2居中的解决办法
    ionic4 创建 angular项目 ReactNative下载第三方库出错解决Error: EPERM: operation not permitted, rename
    ionic+cordova 创建项目+打包
    jxl读取excel文件异常:Unable to recognize OLE stream 的解决方法
    学习 javascript (一)javascript 简介
    学习 JavaScript (四)核心概念:操作符
  • 原文地址:https://www.cnblogs.com/hellowhy/p/15638373.html
Copyright © 2011-2022 走看看