前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring5.0源码深度解析之容器的功能扩展

Spring5.0源码深度解析之容器的功能扩展

作者头像
须臾之余
发布2019-08-06 14:33:28
4820
发布2019-08-06 14:33:28
举报
文章被收录于专栏:须臾之余

版权所有:https://my.oschina.net/u/3995125,禁止转载

写在前面:本篇源码分析文章:适合有三年开发经验的IT人员(中高级水平)参考,小白就别浪费自己宝贵的时间啦~~~

容器的功能扩展

前期准备:

同样,我们还是以 AnnotationConfigApplicationContext 作为切入点,开始对整体功能进行分析。

代码语言:javascript
复制
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
代码语言:javascript
复制
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
   this();
   register(annotatedClasses);
   refresh();
}

一:创建IOC容器

进入this();

代码语言:javascript
复制
public AnnotationConfigApplicationContext() {
   this.reader = new AnnotatedBeanDefinitionReader(this);
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

先执行父类的初始化方法,创建IOC容器

代码语言:javascript
复制
public GenericApplicationContext() {
   this.beanFactory = new DefaultListableBeanFactory();
}

2.进入AnnotatedBeanDefinitionReader方法执行初始化方法创建BeanDefinition读取器

代码语言:javascript
复制
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   Assert.notNull(environment, "Environment must not be null");
   this.registry = registry;
   this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
   AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

AnnotationConfigUtils获取所有BeanPostProcessor的Bean,把下面6个对象注入到IOC容器中了

这里用到了CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 、AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME 等几个常量

常量

对应的BeanPostProcessor

对应的注解

CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME

ConfigurationClassPostProcessor

@Configuration

AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME

AutowiredAnnotationBeanPostProcessor

@AutoWired

REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME

RequiredAnnotationBeanPostProcessor

@Required

COMMON_ANNOTATION_PROCESSOR_BEAN_NAME

CommonAnnotationBeanPostProcessor

@javax.annotation.PostConstruct、@javax.annotation.PreDestroy

等等,还有几个,就不列了。

3.进入ClassPathBeanDefinitionScanner方法创建classPath下扫描器

代码语言:javascript
复制
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
      Environment environment, @Nullable ResourceLoader resourceLoader) {

   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   this.registry = registry;

   if (useDefaultFilters) {
      registerDefaultFilters();
   }
   setEnvironment(environment);
   setResourceLoader(resourceLoader);
}

二:注册配置类

代码语言:javascript
复制
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
   this();
   register(annotatedClasses);
   refresh();
}
代码语言:javascript
复制
public void register(Class<?>... annotatedClasses) {
   Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
   this.reader.register(annotatedClasses);
}
代码语言:javascript
复制
public void register(Class<?>... annotatedClasses) {
   for (Class<?> annotatedClass : annotatedClasses) {
      registerBean(annotatedClass);
   }
}
代码语言:javascript
复制
public void registerBean(Class<?> annotatedClass) {
   doRegisterBean(annotatedClass, null, null, null);
}
代码语言:javascript
复制
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);//创建BeanDefinition对象
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {    //处理 @Condition注解
      return;
   }

   abd.setInstanceSupplier(instanceSupplier); //设置对象是单例模式还是多例模式,默认单例
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   abd.setScope(scopeMetadata.getScopeName());    //获取BeanName,设置的化就采用默认值,否则类名第一个字母小写
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); //处理Lazy,primary等注解
   .....

   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//判断对象是否需要代理,不需要直接返回,需要的化,重新创建BeanDefinition加入代理的信息
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);    //注册配置类到IOC容器
}

扩展功能

进入 refresh()方法,可以说refresh函数中包括了几乎ApplicationContext中提供的全部功能,而且此函数中逻辑非常清晰明了。

代码语言:javascript
复制
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
   this();
   register(annotatedClasses);
   refresh();
}
代码语言:javascript
复制
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();//准备刷新上下文环境

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//初始化BeanFacgtory

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);//初始化BeanFactory进行各种功能填充

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);//子类覆盖方法做额外的处理

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);//激活各种BeanFactory处理器

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);//注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean的时候

         // Initialize message source for this context.
         initMessageSource();//为上下文初始化Message源,集不同语言的消息体,国际化处理

         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();//初始化应用消息广播器,并放入applicationEventMulticaster bean中

         // Initialize other special beans in specific context subclasses.
         onRefresh();//留给子类来初始化其它的Bean

         // Check for listener beans and register them.
         registerListeners();//在所有注册的Bean中查找Listener bean,注册到消息广播器中

         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);//初始化剩下的单实例(非惰性)

         // Last step: publish corresponding event.
         finishRefresh();//完成刷新过程,通知生命周期处理器 LifecycleProcessor刷新过程,同时发出 ContextRefreshedEvent 通知别人
      }

      catch (BeansException ex) {
       
         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();//销毁Bean

         // Reset 'active' flag.
         cancelRefresh(ex);//更改活跃状态

         // Propagate exception to caller.
         throw ex;
      }
   }
}

准备刷新上下文环境

prepareRefresh();函数主要作用是对系统属性及环境变量的初始化及验证

代码语言:javascript
复制
/**
 * Prepare this context for refreshing, setting its startup date and
 * active flag as well as performing any initialization of property sources.
 */
protected void prepareRefresh() {
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);

   if (logger.isInfoEnabled()) {
      logger.info("Refreshing " + this);
   }

   // Initialize any placeholder property sources in the context environment
   initPropertySources();//留给子类覆盖

   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties
   getEnvironment().validateRequiredProperties();//验证需要的属性文件是否都已经放入环境中去了

   // Allow for the collection of early ApplicationEvents,
   // to be published once the multicaster is available...
   this.earlyApplicationEvents = new LinkedHashSet<>();
}

initPropertySources是空的,没有任何逻辑处理,getEnvironment().validateRequiredProperties()也是因为没有需要验证的属性而没有做任何处理,然而这两个方法作用还是很大的。那么该怎么用呢?

1.initPropertySources正符合Spring的开放式结构设计,给用户最大的扩展Spring的能力。 2.validateRequiredProperties则是对属性进行验证,那么如何验证呢?我们举个例子来说明下:

代码语言:javascript
复制
public class MyAnnotationConfigApplication extends AnnotationConfigApplicationContext {
    public MyAnnotationConfigApplication(Class<?>... annotatedClasses){
        super(annotatedClasses);
    }
    @Override
    protected void initPropertySources(){
        //添加验证要求
        getEnvironment().setRequiredProperties("VAR");
    }
}

我们自定义了继承自AnnotationConfigApplicationContext的MyAnnotationConfigApplication,并重写了initPropertySources方法,在方法中添加了我们的个性化需求,那么在验证的时候也就是程序走到 validateRequiredProperties()代码的时候,我们还需要替换掉原有的AnnotationConfigApplicationContext为我们自定义的MyAnnotationConfigApplication。

代码语言:javascript
复制
public class Test002 {
    public static void main(String[] args) {
       ApplicationContext context = new MyAnnotationConfigApplication(MyConfig.class);
       Object payEntity = context.getBean("payEntity");
       System.out.println(payEntity);
    }
}

如果系统并没有检测到对应的VAR环境变量,那么就会抛出异常:

初始化BeanFacgtory

obtainFreshBeanFactory()方法的作用是:经过这个方法,ApplicationContext就已经拥有了BeanFactory的全部功能。

代码语言:javascript
复制
/**
 * Tell the subclass to refresh the internal bean factory.
 * @return the fresh BeanFactory instance
 * @see #refreshBeanFactory()
 * @see #getBeanFactory()
 */
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //初始化BeanFactory
   refreshBeanFactory();
    //返回当前实体的BeanFactory属性
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
   }
   return beanFactory;
}

方法中将核心实现委托给了refreshBeanFactory:

代码语言:javascript
复制
/**
 * This implementation performs an actual refresh of this context's underlying
 * bean factory, shutting down the previous bean factory (if any) and
 * initializing a fresh bean factory for the next phase of the context's lifecycle.
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();//创建DefaultListableBeanFactory 
      beanFactory.setSerializationId(getId());//序列化id
      customizeBeanFactory(beanFactory);//定制BeanFactory,设置相关属性,是否允许循环依赖,是否允许覆盖
      loadBeanDefinitions(beanFactory);//加载BeanDefinition
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}
1.定制BeanFactory
代码语言:javascript
复制
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    //如果属性不为空,则设置给beanFactory对象相应属性,此属性的含义是:是否允许覆盖同名称的不同定义的对象
   if (this.allowBeanDefinitionOverriding != null) {
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
    //如果属性不为空,设置给beanFactory对象相应的属性,这块属性的含义是:是否允许Bean之间存在循环依赖
   if (this.allowCircularReferences != null) {
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
}

对于允许覆盖和允许循环依赖的设置这里只是进行了非空判断,如果不为空的化要进行设置,但是这里没有设置,所以还是那个套路,使用子类覆盖方法。

代码语言:javascript
复制
public class MyAnnotationConfigApplication extends AnnotationConfigApplicationContext {
    public MyAnnotationConfigApplication(Class<?>... annotatedClasses){
        super(annotatedClasses);
    }
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory){
        super.setAllowBeanDefinitionOverriding(false);//是否允许覆盖同名称的不同定义的对象
        super.setAllowCircularReferences(false);//是否允许Bean之间存在循环依赖
    }
}
2.加载BeanDefinition
代码语言:javascript
复制
/**
 * Loads the bean definitions via an XmlBeanDefinitionReader.
 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
 * @see #initBeanDefinitionReader
 * @see #loadBeanDefinitions
 */
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);//为指定的beanFactory创建XmlBeanDefinitionReader

   // Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(this.getEnvironment());//对beanDefinitionReader进行环境变量的设置
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);//进行设置可以覆盖
   loadBeanDefinitions(beanDefinitionReader);
}

在初始化了DefaultListableBeanFactoryXmlBeanDefinitionReader后就可以进行配置文件的读取了

代码语言:javascript
复制
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}
代码语言:javascript
复制
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
   Assert.notNull(resources, "Resource array must not be null");
   int counter = 0;
   for (Resource resource : resources) {
      counter += loadBeanDefinitions(resource);
   }
   return counter;
}

经过此步骤,类型DefaultListableBeanFactory的变量beanFactory已经包含了所有已经解析好的配置

功能扩展

进入函数prepareBeanFactory前,Spring已经完成了对配置的解析,而ApplicationContext在功能上的扩展也由此展开。

代码语言:javascript
复制
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   beanFactory.setBeanClassLoader(getClassLoader());//设置BeanFactory的classLoader为当前context的classLoader
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//设置beanFactory的表达式语言处理器,默认可以使用#{bean.xx}的形式来调用相关的属性值。
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));//为BeanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具

   // Configure the bean factory with context callbacks.
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//添加BeanPostProcessor

    //设置了几个忽略自定装配的接口
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    //设置了几个自定装配的规则
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // 增加了对AspectJ的支持
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // 添加了默认的系统环境bean
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

上面函数中主要进行了几个方面的扩展

  • 增加了对SpEL语言的支持
  • 增加对属性编辑器的支持
  • 增加了对一些内置类,比如实现了Aware接口的类信息注入
  • 设置了依赖功能可忽略接口
  • 注册一些固定依赖的属性
  • 增加了AspectJ的支持,后面再去分析
  • 将相关环境变量及属性注册以单例模式注册

上面可扩展功能很多,我就不一一介绍了,下面我们来挑几个我们感兴趣的函数来分析下:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)),其主要目的就是注册个BeanPostProcessor,而真正的逻辑还是在ApplicationContextAwareProcessor中

ApplicationContextAwareProcessor实现了BeanPostProcessor接口,我们回顾下之前讲解的内容,在Bean实例化的时候,也就是Spring激活Bean的init-method方法前后, 会调用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法。所以我们也就去看看ApplicationContextAwareProcessor对这两个方法的实现。

代码语言:javascript
复制
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
   return bean;
}

对于后置处理器BeanPostProcessor的后置处理方法中并没有做任何逻辑处理,那么我们转向后置处理器的前置处理

代码语言:javascript
复制
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
   AccessControlContext acc = null;

   if (System.getSecurityManager() != null &&
         (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
               bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
               bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
   }

   if (acc != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareInterfaces(bean);
         return null;
      }, acc);
   }
   else {
      invokeAwareInterfaces(bean);
   }

   return bean;
}
代码语言:javascript
复制
private void invokeAwareInterfaces(Object bean) {
   if (bean instanceof Aware) {
      if (bean instanceof EnvironmentAware) {
         ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
         ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
      }
      if (bean instanceof ResourceLoaderAware) {
         ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
         ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
         ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
         ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
   }
}

postProcessBeforeInitialization方法中调用了invokeAwareInterfaces。从invokeAwareInterfaces方法中,我们或许已经差不多知道了Spring的用意,实现了这些Aware接口的Bean在被初始化后,可以取到一些对于的资源。

示例:

代码语言:javascript
复制
@Component
public class MyApplicationContext implements ApplicationContextAware {
    /**
     * spring底层中为什么能够实现ApplicationContextAware接口 就能够拿到ApplicationContext
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("applicationContext:>>>>"+applicationContext);
    }
}

BeanFactory的后处理

代码语言:javascript
复制
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

   // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
   // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }
}

注册BeanPostProcessor

我们自定义MyInstantiationAwareBeanPostProcessor实现BeanPostProcessor 接口

代码语言:javascript
复制
@Component
public class MyInstantiationAwareBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization....");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization....");
        return null;
    }
}
代码语言:javascript
复制
@Import(MyInstantiationAwareBeanPostProcessor.class)

结果输出:每次初始化一个Bean就会在之前和之后处理一些自定义逻辑

postProcessBeforeInitialization.... 4.bean init方法执行.. postProcessAfterInitialization....

初始化ApplicationEventMulticaster

代码语言:javascript
复制
/**
 * Initialize the ApplicationEventMulticaster.
 * Uses SimpleApplicationEventMulticaster if none defined in the context.
 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
 */
protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
      if (logger.isDebugEnabled()) {
         logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
      }
   }
   else {
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
      if (logger.isDebugEnabled()) {
         logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
               APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
               "': using default [" + this.applicationEventMulticaster + "]");
      }
   }
}

进入SimpleApplicationEventMulticaster找到这段代码:

代码语言:javascript
复制
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      Executor executor = getTaskExecutor();
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}
代码语言:javascript
复制
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
   ErrorHandler errorHandler = getErrorHandler();
   if (errorHandler != null) {
      try {
         doInvokeListener(listener, event);
      }
      catch (Throwable err) {
         errorHandler.handleError(err);
      }
   }
   else {
      doInvokeListener(listener, event);
   }
}
代码语言:javascript
复制
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        ....
      listener.onApplicationEvent(event);
}

可以推断,当产生Spring事件的时候会默认使用SimpleApplicationEventMulticaster的multicastEvent来广播事件,遍历所有监听器,并使用监听器中的onApplicationEvent方法来进行监听事件的处理。 而对于每个监听器来说其实都可以获取到产生的事件,但是是否进行处理则由事件监听器来决定。

注册监听器

进入registerListeners函数,开始注册监听器:

代码语言:javascript
复制
protected void registerListeners() {

   for (ApplicationListener<?> listener : getApplicationListeners()) {//硬编码方式注册的监听器处理
      getApplicationEventMulticaster().addApplicationListener(listener);
   }

   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);//配置文件注册的监听器处理
   for (String listenerBeanName : listenerBeanNames) {
      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   }
   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
   this.earlyApplicationEvents = null;
   if (earlyEventsToProcess != null) {
      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
         getApplicationEventMulticaster().multicastEvent(earlyEvent);
      }
   }
}

Application下抽象子类ApplicationContextEvent的下面有4个已经实现好的事件

  • ContextClosedEvent(容器关闭时)
  • ContextRefreshedEvent(容器刷新时)
  • ContextStartedEvent(容器启动时候)
  • ContextStoppedEvent(容器停止的时候)

同样,这四个事件都继承了ApplicationEvent,如果我们想自定义事件,也可以通过继承ApplicationEvent来实现

使用示例:

1.定义监听事件

代码语言:javascript
复制
public class TestEvent extends ApplicationEvent {
    private String msg;
    public TestEvent(Object source){
        super(source);
    }
    public TestEvent(Object source,String msg){
        super(source);
        this.msg=msg;
    }
    public void print(){
        System.out.println(msg);
    }
}

2.定义监听器

代码语言:javascript
复制
public class TestListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof TestEvent){
            TestEvent testEvent= (TestEvent)event;
            testEvent.print();
        }
    }
}

注入容器

代码语言:javascript
复制
@Import(TestListener.class)

测试:

代码语言:javascript
复制
public class Test001 {

    public static void main(String[] args) {
        /**
         * IOC容器初始化单例对象都是循环遍历调用getBean方法
         */
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        TestEvent testEvent = new TestEvent("hello", "hello word");
        applicationContext.publishEvent(testEvent);
    }
}

输出结果:

我们在补充一个注解形式的例子:

代码语言:javascript
复制
public class TestEvent extends ApplicationEvent {

    private String msg;
    public TestEvent(Object source){
        super(source);
    }
    public TestEvent(Object source,String msg){
        super(source);
        this.msg=msg;
    }
    public void print(){
        System.out.println("注册监听器..,TestEvent....");
    }
}
代码语言:javascript
复制
@Component
public class MyAnnotationListener {

    @EventListener
    public String listener1(TestEvent event) {
        if (event instanceof TestEvent){
            TestEvent testEvent=event;
            testEvent.print();
        }
        return "xd";
    }
}
代码语言:javascript
复制
@Import(MyAnnotationListener.class)
代码语言:javascript
复制
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
MyAnnotationListener myAnnotationListener = new MyAnnotationListener();
applicationContext.publishEvent(myAnnotationListener.listener1(new TestEvent("jj")));

输出:

初始化非延迟加载单例

进入finishBeanFactoryInitialization函数初始化所有非懒加载Bean

代码语言:javascript
复制
/**
 * Finish the initialization of this context's bean factory,
 * initializing all remaining singleton beans.
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {

   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(//定义转换器从String转为Date的方式,可以自己扩展,我就不多说了
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
   }
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   beanFactory.freezeConfiguration();//冻结所有Bean的定义,说明注册的Bean定义将不被修改或处理。

   // Instantiate all remaining (non-lazy-init) singletons.
   beanFactory.preInstantiateSingletons();//初始化剩下的单实例(非惰性)
}
冻结配置
代码语言:javascript
复制
@Override
public void freezeConfiguration() {
   this.configurationFrozen = true;
   this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
初始化非延迟加载

ApplicationContext实现的默认行为就是在启动时将所有单例bean提前进行实例化。提前实例化的好处是,在配置中任何错误就会立即被发现Z(否则的化,一旦出错,排除bug相当困难)。

代码语言:javascript
复制
public void preInstantiateSingletons() throws BeansException {
   if (this.logger.isDebugEnabled()) {
      this.logger.debug("Pre-instantiating singletons in " + this);
   }

   // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         if (isFactoryBean(beanName)) {
            final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
            boolean isEagerInit;
            if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
               isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
                     ((SmartFactoryBean<?>) factory).isEagerInit(),
                     getAccessControlContext());
            }
            else {
               isEagerInit = (factory instanceof SmartFactoryBean &&
                     ((SmartFactoryBean<?>) factory).isEagerInit());
            }
            if (isEagerInit) {
               getBean(beanName);
            }
         }
         else {
            getBean(beanName);
         }
      }
   }

finishRefresh

在Spring中还提供了Lifecycle接口,Lifecycle接口中包含start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并且在spring关闭的时候调用stop方法来结束生命周期, 通常用来配置后台程序,在启动后一直运行(such as MQ进行轮询等)。

代码语言:javascript
复制
/**
 * Finish the refresh of this context, invoking the LifecycleProcessor's
 * onRefresh() method and publishing the
 * {@link org.springframework.context.event.ContextRefreshedEvent}.
 */
protected void finishRefresh() {
   // Clear context-level resource caches (such as ASM metadata from scanning).
   clearResourceCaches();

   // Initialize lifecycle processor for this context.
   initLifecycleProcessor();//当ApplicationContext启动或者停止时,会通过LifecycleProcessor来与所有声明的bean的周期做状态更新,而在LifecycleProcessor使用前需要初始化

   // Propagate refresh to lifecycle processor first.
   getLifecycleProcessor().onRefresh();//启动所有实现了Lifecycle接口的bean

   // Publish the final event.
   publishEvent(new ContextRefreshedEvent(this));//当完成ApplicationContext初始化的时候,要通过Spring中的事件发布机制来发出ContextRefreshedEvent监听事件,以保证对应的监听器可以做进一步的逻辑处理

   // Participate in LiveBeansView MBean, if active.
   LiveBeansView.registerApplicationContext(this);
}

到这里,我们就谈完了!!!

参考书籍:Spring源码深度解析

参考链接:http://www.mayikt.com

版权所有:https://my.oschina.net/u/3995125,禁止转载

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面:本篇源码分析文章:适合有三年开发经验的IT人员(中高级水平)参考,小白就别浪费自己宝贵的时间啦~~~
  • 容器的功能扩展
    • 前期准备:
      • 一:创建IOC容器
        • 二:注册配置类
          • 扩展功能
            • 准备刷新上下文环境
            • 初始化BeanFacgtory
            • 功能扩展
            • BeanFactory的后处理
            • 注册BeanPostProcessor
            • 初始化ApplicationEventMulticaster
            • 注册监听器
            • 初始化非延迟加载单例
            • finishRefresh
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档