目 录CONTENT

文章目录

容器功能扩展

FatFish1
2025-01-09 / 0 评论 / 0 点赞 / 93 阅读 / 0 字 / 正在检测是否收录...

容器与上下文

BeanFactory家族是用来做容器创建和初始化的类,同时spring还提供了ApplicationContext接口用于扩展BeanFactory中的现有功能。一般在绝大多数场景,ApplicationContext就是首选的。

ApplicationContext是Spring框架中重要的容器之一,它是BeanFactory的超集,提供了更多的企业级特性和功能。ApplicationContext具有以下优势:

  • 更快的启动速度。

  • 监听和响应Bean生命周期事件。

  • 支持模块化编程(例如通过不同的XML文件或Java类定义不同的bean)。

  • 内置支持AOP、数据校验和事件发现等框架。

  • 提供覆盖框架默认设置的能力。

  • 允许开发者通过参数化配置很容易地管理多个环境下的部署。

背后的原理是ApplicationContext在启动时实例化Bean并注入它们,同时负责管理对象的整个生命周期。当需要获取一个Bean时,ApplicationContext会检查是否已经存在该Bean实例,如果不存在,则创建新实例并返回该实例给调用方。ApplicationContext还支持在构造函数参数或方法参数中注入Bean、解析属性占位符和SpEL表达式等高级设置

ApplicationContext应用场景非常广泛。

例如,在使用Spring MVC框架开发Web应用程序时,我们可以使用XmlWebApplicationContext或AnnotationConfigWebApplicationContext来加载Spring配置文件。参考以下链接:

http://www.chymfatfish.cn/archives/spring-mvc#configureandrefreshwebapplicationcontext

还可以使用ClassPathXmlApplicationContext加载类路径下的XML文件。另外,在需要动态注册组件的情况下,我们可以使用GenericApplicationContext来自定义Bean

使用ApplicationContext加载XML生成bean的流程如下:

// 使用BeanFactory
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("spring-beans.xml"));
MyTestBean bean = (MyTestBean) bf.getBean("myTestBean");
 // 使用ApplicationContext
ApplicationContext bf = new ClassPathXmlApplicationContext("beanFactoryTest.xml");

从这段代码中可以看出,二者提供的用法是基本一致的

上下文的加载流程

ClassPathXmlApplicationContext

核心成员变量

// xml配置文件的路径,继承自AbstractRefreshableConfigApplicationContext
private String[] configLocations;
// 继承自AbstractApplicationContext,是一个监控refresh方法和destory方法的同步锁
private final Object startupShutdownMonitor = new Object();
// 继承自AbstractApplicationContext,是BeanFactoryPostProcessors合集
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>()

构造函数

// 使用ApplicationContext
ApplicationContext bf = new ClassPathXmlApplicationContext("beanFactoryTest.xml");

从这行源码入手,找到了下面这个构造函数:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
       throws BeansException {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
       refresh();
    }
}

这里做了三件事:

一直追溯到父类构造函数

public AbstractApplicationContext(@Nullable ApplicationContext parent) {
    this();
    setParent(parent);
}

在这个场景下,parent = null,忽略,继续看

public AbstractApplicationContext() {
    this.resourcePatternResolver = getResourcePatternResolver();
}

是在给资源解析器赋值,跟进getResourcePatternResolver方法

protected ResourcePatternResolver getResourcePatternResolver() {
    return new PathMatchingResourcePatternResolver(this);
}

原来是PathMatchingResourcePatternResolver,是老朋友了

http://www.chymfatfish.cn/archives/springxml#pathmatchingresourcepatternresolver

setConfigLocation

public void setConfigLocations(@Nullable String... locations) {
    if (locations != null) {
       Assert.noNullElements(locations, "Config locations must not be null");
       this.configLocations = new String[locations.length];
       for (int i = 0; i < locations.length; i++) {
          this.configLocations[i] = resolvePath(locations[i]).trim();
       }
    }
    ……
}

核心是这部分,运行传多个配置文件路径,会以数组形式存储到configLocations属性,然后遍历每一个路径,调用resolvePath方法解析给定的路径数组,当然,如果数组中包含特殊符号,如${var},那么在resolvePath中会搜寻匹配的系统变量并替换。

refresh - 上下文刷新核心方法

继承自AbstractApplicationContext,是所有上下文执行refresh时候的统一模板方法,定义了整个 Spring 上下文加载的流程。

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        ……
    }
}

首先可以看到,整个refresh方法都是在同步锁startupShutdownMonitor的监控下完成的其中的方法可知是原子性的。其中的步骤包括:

准备环境

prepareRefresh();

prepare工作,对系统属性或者环境变量进行准备和验重,见prepareRefresh方法

xml文件读取

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

初始化BeanFactory,并进⾏XML⽂件读取,见obtainFreshBeanFactory方法

填充BeanFactory功能

prepareBeanFactory(beanFactory);

对BeanFactory进行各种功能填充,见prepareBeanFactory方法

处理子类覆盖方法

postProcessBeanFactory(beanFactory);

处理子类的覆盖方法,见postProcessBeanFactory方法

注册各类BeanFactory处理器

StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
invokeBeanFactoryPostProcessors(beanFactory);

激活各种beanFactory处理器,见invokeBeanFactoryPostProcessors方法

注册Bean创建过程中的可插入式处理器

registerBeanPostProcessors(beanFactory);
beanPostProcess.end();

注册拦截Bean创建的Bean处理器,这⾥只是注册,真正的调⽤是在getBean时候,见registerBeanPostProcessors方法

初始化Message源

initMessageSource();

为上下⽂初始化Message源,即不同语⾔的消息体 ,国际化处理,见initMessageSource方法

初始化应用消息广播器

initApplicationEventMulticaster();

初始化应⽤消息⼴播器,并放⼊“applicationEventMulticaster”bean中,见initApplicationEventMulticaster方法

refresh扩展点

onRefresh();

空实现,留给子类来初始化其他bean

注册消息监听器

registerListeners();

在所有注册的bean中查找Listener bean,注册到消息⼴播器中,见registerListeners方法

初始化非惰性单实例

finishBeanFactoryInitialization(beanFactory);

初始化剩下的单实例(非惰性的),见finishBeanFactoryInitialization方法

完成refresh后置任务

finishRefresh();

完成刷新过程,通知⽣命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别⼈,见finishRefresh方法

prepareRefresh - 准备阶段:准备环境

它的作用是准备预处理,功能包括:

  • 记录spring容器的启动时间startupDate

  • 标记容器为激活

  • 初始化上下文环境如文件路径信息

  • 验证必填属性是否填写

  • 初始化保存事件的集合

核心代码包括:

// 在AbstractApplicationContext中是空实现,留给子类自定义个性化的属性设置方法
initPropertySources();
// 校验配置文件的属性,合法性
getEnvironment().validateRequiredProperties();
// 初始化保存事件的集合
if (this.earlyApplicationListeners == null) {
	this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}

在实际的工程应用中,可以通过继承ClassPathXmlApplicationContext,重写initPropertySources方法来自定义一些属性规则,例如使用以下逻辑给VAR属性添加了一条必填的验证规则:

getEnvironment().setRequiredProperties("VAR");

obtainFreshBeanFactory - 准备阶段:创建BeanFactory加载DB

它的作用包括获取BeanFactory,解析配置文件,生成beanDefinition

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory();
}

代码框架很简单,先调用refreshBeanFactory加载,然后调用getBeanFactory获取

getBeanFactory是很简单的,看AbstractRefreshableApplicationContext#getBeanFactory 中的实现:

public final ConfigurableListableBeanFactory getBeanFactory() {
    DefaultListableBeanFactory beanFactory = this.beanFactory;
    ……
    return beanFactory;
}

就是取成员变量直接获取

prepareBeanFactory - 准备阶段:准备BeanFactory功能

该方法主要负责对BeanFactory的预准备工作,配置beanFactory的基础属性,比如ClassLoader和一些PostProcessor等,包括:

  • 设置BeanFactory的类加载器、支持表达式解析器…

  • 添加部分BeanPostProcessor(例如ApplicationContextAwareProcessor)

  • 设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware、xxx;

  • 注册可以解析的自动装配;我们能直接在任何组件中自动注入:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext

  • 添加BeanPostProcessor(例如ApplicationListenerDetector)

  • 添加编译时的AspectJ;

  • 给BeanFactory中注册一些能用的组件;

步骤一、类加载器

//设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());

首先设置类加载器,设置beanFactory的classLoader为当前context的classLoader

步骤二、表达式解析器和资源编辑注册器

  //设置bean表达式解析器
  if (!shouldIgnoreSpel) {
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  }
  //资源编辑注册器
  beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

表达式解析器是SpEL语言解析器。SpEL使⽤#{…}作为定界符,所有在⼤框号中的字符都将被认为是SpEL。例如以下SpEL解析器实例:

public class SpelTest {
    @Test
    public void test1() {
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)");
        EvaluationContext context = new StandardEvaluationContext();
        context.setVariable("end", "!");
        System.out.println(expression.getValue(context));
    }
}

这是一个Spel解析器的实例,可以看出来其作用主要是做解析和变量填充

表达式解析器的调用点在AbstractAutowireCapableBeanFactory#populateBean的流程中,比较深,在属性注入里面需要注入属性值,调用AbstractAutowireCapableBeanFactory#applyPropertyValues,构造了一个BeanDefinitionValueResolver实例,在BeanDefinitionValueResolver#doEvaluate 方法中就调用了AbstractBeanFactory#evaluateBeanDefinitionString 方法,借助BeanExpressionResolver解析SpEL表达式

具体可以看:

http://www.chymfatfish.cn/archives/spring-beansgetfromfactory#applypropertyvalues

资源编辑注册的目的是为了使spring可以解析一些非String类型的注入。

但是这里只注册了一个默认注册的ResourceEditorRegistrar,它提供了String解析成Resource、Path、Class等复杂类型的能力,但是如果是想解析别的,那就不行了,例如Date类型:

@Data
public class DateTest {
    private Date date;
}

有一个属性为Date类型的DTO,需要以bean的形式注入,写xml文件如下:

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http">
<bean id="dateTest" class="com.huawei.cbc.udrmetricservice.DateTest">
    <property name="date" value="2023-12-15" />
</bean>
</beans>

这时候想要获取bean就会报错:

@Test
public void test() throws ExecutionException, IOException, ClassNotFoundException, SQLException {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
    DateTest dateTest = (DateTest) ctx.getBean("dateTest");
    System.out.println(dateTest);
}

// Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date' for 
// property 'date': no matching editors or conversion strategy found
//	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:262)
//	at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:590)
//	... 86 more

就是因为将String类型注入date类型导致的为了解决这类异常,spring提供了两种方案,都是基于CustomEditorConfigurer的

看CustomEditorConfigurer有两个核心属性:

@Nullable
private PropertyEditorRegistrar[] propertyEditorRegistrars;
@Nullable
private Map<Class<?>, Class<? extends PropertyEditor>> customEditors;

对应了spring提供的两种解决方案:自定义属性解析器并注册进环境、把spring预置的一些属性解析器注册进环境

自定义属性解析器

如果自定义属性解析器,则要继承PropertyEditorSupport方法,同时配置到CustomEditorConfigurer中并注入CustomEditorConfigurer的customEditors属性

PropertyEditorSupport的用法在前面也以ResourceArrayPropertyEditor为例已经看过了,最核心就是setAsText方法,将Stirng类型的注入值,做了一步转换:

http://www.chymfatfish.cn/archives/spring-beansgetfromfactory#setastext

例如我们自定义了DatePropertyEditor类,只需要重写setAsText即可

public class DatePropertyEditor extends PropertyEditorSupport {
    private String format = "yyyy-MM-dd";
    public void setFormat(String format) {
        this.format = format;
    }
    public void setAsText(String arg0) throws IllegalArgumentException {
        System.out.println("arg0: " + arg0);
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            Date d = sdf.parse(arg0);
            this.setValue(d);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

然后在xml中注册

<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.util.Date">
                <bean class="com.test.DatePropertyEditor">
                    <property name="format" value="yyyy-MM-dd"/>
                </bean>
            </entry>
        </map>
    </property>
</bean>
使用spring预置的解析器

这需要我们重写下PropertyEditorRegistrar,可以先看下spring预置的重写:ResourceEditorRegistrar,上面也看到了它加载的地方

public void registerCustomEditors(PropertyEditorRegistry registry) {
    ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
    doRegisterEditor(registry, Resource.class, baseEditor);
    doRegisterEditor(registry, ContextResource.class, baseEditor);
    doRegisterEditor(registry, WritableResource.class, baseEditor);
    doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
    doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
    doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
    doRegisterEditor(registry, Path.class, new PathEditor(baseEditor));
    doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
    doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
    ClassLoader classLoader = this.resourceLoader.getClassLoader();
    doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
    doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
    doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
    if (this.resourceLoader instanceof ResourcePatternResolver) {
       doRegisterEditor(registry, Resource[].class,
             new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
    }
}

可以看出来,spring是为了注册一些可以解析Resource、Path等类型的特殊属性,里面是没有对Date类型进行解析的,因此我们做对应实现:

public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar{
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat ("yyyy-MM-dd"),true));
    }
}

然后通过xml注入

<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <bean class="com.test.DatePropertyEditorRegistrar"></bean>
        </list>
    </property>
</bean>

但是上面在prepareBeanFactory的流程中,只是硬编码加载了那个默认的ResourceEditorRegistrar,那自定义的DatePropertyEditorRegistrar是在哪里被加载到环境中的呢?通过PropertyEditorRegistrar#registerCustomEditors 向上查找调用点:

这个AbstractBeanFactory#initBeanWrapper 方法就很明确了,是在AbstractAutowireCapableBeanFactory#instantiateBean 调用的,这里就是doCreateBean核心三步骤中的第一步了,上面的调用点就是bean的加载流程

http://www.chymfatfish.cn/archives/spring-beansgetfromfactory#%E8%A7%A3%E6%9E%90%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%B5%81%E7%A8%8B

步骤三、配置aware初始化时前置处理器

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

这个ApplicationContextAwareProcessor是BeanPostProcessor的实现

class ApplicationContextAwareProcessor implements BeanPostProcessor

BeanPostProcessor前面见过,是一个bean创建时的可插入式扩展

http://www.chymfatfish.cn/archives/springknowledge#%E5%9C%A8docreatebean%E6%B5%81%E7%A8%8B%E4%B8%AD%E5%AF%B9bean%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B%E7%9A%84%E5%89%8D%E7%BD%AE%E6%89%A9%E5%B1%95---beanpostprocessor%23postprocessbeforeinitialization

ApplicationContextAwareProcessor实现了BeanPostProcessor#postProcessBeforeInitialization 说明它是初始化前调用的,回顾它的调用点实际上不止一个,比较典型的就是doCreateBean三步骤最后一步initializeBean

http://www.chymfatfish.cn/archives/spring-beansgetfromfactory#initializebean---%E5%88%9D%E5%A7%8B%E5%8C%96bean

这里只加了ApplicationContextAwareProcessor一个处理器,说明了几个问题:

  1. 其他BeanPostProcessor还有其他插入点,其实就在下面registerBeanPostProcessors方法

  2. ApplicationContextAwareProcessor是一个预置且必选的处理器

它的功能是让实现Aware接口的类具备感知能力,前面也说是,Aware是意识,即能够意识到一些东西,比如ApplicationContextAware的实现类能够意识到ApplicationContext,其实就是通过这个ApplicationContextAwareProcessor实现的

参考ApplicationContextAwareProcessor#postProcessBeforeInitialization点我跳转

步骤四、忽略&主动设置依赖注入

有七类bean需要在步骤三添加的postProcessBeforeInitialization 中已处理,因此忽略依赖注入:

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.ignoreDependencyInterface(ApplicationStartupAware.class);

另外一些设置依赖注入:

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

步骤五、其他的BeanPostProcessor

// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (!NativeDetector.inNativeImage() && 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

// Register default environment beans.
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());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
    beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}

postProcessBeanFactory - 准备阶段:空实现做BeanFactory的可选后置处理

空实现,给特殊的applicationContext用,比如GenericWebApplicationContext#postProcessBeanFactory

invokeBeanFactoryPostProcessors - 准备阶段:注册并激活BeanFactoryPostProcessor

虽然这里名字叫BeanFactoryPostProcessors,但是实际上整体流程处理了两类:BeanFactoryPostProcessors和BeanPostProcessor

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 激活BeanFactoryPostProcessor和BeanPostProcessor
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
   
    if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null &&
          beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
       // 添加一类默认的BeanPostProcessor
       beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
       beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

整体方法可见分成两部分,一部分调用PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors,另一部分硬编码添加了一个默认的BeanPostProcessor,同样其他BeanPostProcessor还有其他插入点,其实就在下面registerBeanPostProcessors方法

核心在PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 方法中,点我跳转

registerBeanPostProcessors - 准备阶段:注册BeanPostProcessor

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

核心在PostProcessorRegistrationDelegate.registerBeanPostProcessors方法中,点我跳转

initMessageSource - 准备阶段:初始化国际化资源

这一步为ApplicationContext 添加 messageSource 成员,实现国际化功能。去 beanFactory 内找名为 messageSource 的 bean,如果没有,则提供空的 MessageSource 实现

initApplicationEventMulticaster - 准备阶段:注册广播器

准备初始化应⽤消息⼴播器

spring的广播机制包括广播器AbstractApplicationEventMulticaster、事件ApplicationEvent、监听器ApplicaitonListener。用法如下:

// 定义event,必须适配ApplicationEvent中的构造方法
public class MyTest extends ApplicationEvent {
    public String msg;
    public MyTest (Object source) {
        super(source);
    }
    public MyTest (Object source, String msg) {
        super(source);
        this.msg = msg;
    }
    public void print(){
        System.out.println(msg);
    }
}

// 定义监听器,重写onApplicationEvent方法
@Service
public class MyTest implements ApplicationListener {
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof MyTest){
            MyTest testEvent = (MyTest)event;
            testEvent .print();
        }
    }
}

// 无需实现广播器,因为spring提供了默认的,直接写事件触发流程
public class MyTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath: applicationContext.xml"); 
        MyTest event = new MyTest("hello", "msg");
        context.publishEvent(event);
    }
}

可以看到这种模式即观察者模式的典型代表

再来看initApplicationEventMulticaster中的逻辑:

  • 如果⽤户⾃定义了事件⼴播器,那么使⽤⽤户⾃定义的事件⼴播器。

  • 如果⽤户没有⾃定义事件⼴播器,那么使⽤默认的ApplicationEventMulticaster。

默认广播器的流程在:

else {
    this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    if (logger.isTraceEnabled()) {
       logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
             "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
    }
}

可见这里注册的默认广播器就是SimpleApplicationEventMulticaster,这个类的具体用法参考SimpleApplicationEventMulticaster部分

onRefresh - 准备阶段:空实现

空实现,给子类做对应的功能

registerListeners - 准备阶段:注册监听器

注册监听器,上面看了广播器的注册,这里就该注册监听器了

硬编码形式注册监听器:

for (ApplicationListener<?> listener : getApplicationListeners()) {
    getApplicationEventMulticaster().addApplicationListener(listener);
}

配置文件读取注册监听器:

String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
	  getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

注册好之后立刻激活广播器的钩子方法,让广播器开始广播event,这里同样以SimpleApplicationEventMulticaster#multicastEvent为例,点我跳转

for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
	  getApplicationEventMulticaster().multicastEvent(earlyEvent);
}

finishBeanFactoryInitialization - 初始化阶段:初始化bean

这一步会将beanFactory的成员补充完毕,并初始化所有非懒加载的bean

步骤一、加载ConversionService

// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
       beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
    beanFactory.setConversionService(
          beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}

Conversion也是一个类型转换器,作为PropertyEditor的补充存在。

前面了解过PropertyEditorSupport自定义属性解析器,这里的Conversion是spring提供的另一种属性转换的工具,而且似乎更简单一点,它的使用逻辑如下:

  • 定义一个转换器

public class String2DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String arg0) {
        try {
            return DateUtils.parseDate(arg0, new String[] { "yyyy-MM-dd HH:mm:ss" });
        } catch (ParseException e) {
            return null;
        }
    }
}
  • 注册bean

<bean id="conversionService" class="org.Springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="String2DateConverter" />
        </list>
    </property>
</bean>
  • 测试类型转换

public void testStringToPhoneNumberConvert() {
    DefaultConversionService conversionService = new DefaultConversionService();
    conversionService.addConverter(new StringToPhoneNumberConverter());
    String phoneNumberStr = "010-12345678";
    PhoneNumberModel phoneNumber = conversionService.convert(phoneNumberStr, PhoneNumber Model.class);
    Assert.assertEquals("010", phoneNumber.getAreaCode());
}

想要探究其用法,可以深入了解ConversionService#convert方法即可

步骤二、加载内嵌值解析器

if (!beanFactory.hasEmbeddedValueResolver()) {
    beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}

步骤三、初始化LoadTimeWeaverAwareTime类型的bean

// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
    getBean(weaverAwareName);
}

步骤四、冻结配置

// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();

步骤五、初始化非懒加载的bean

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

这里调用就到了DefaultListableBeanFactory#preInstantiateSingletons 是老熟人了

这里直接看下对应方法:

public void preInstantiateSingletons() throws BeansException {
    ……
    for (String beanName : beanNames) {
       // 1. 合并BD
       RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
       // 2. 加载bean
       if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
          if (isFactoryBean(beanName)) {
             ……
          }
          else {
             getBean(beanName);
          }
       }
    }
    // 3. 激活SmartInitializingSingleton扩展点
    for (String beanName : beanNames) {
       Object singletonInstance = getSingleton(beanName);
       if (singletonInstance instanceof SmartInitializingSingleton) {
          StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
                .tag("beanName", beanName);
          SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
          if (System.getSecurityManager() != null) {
             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                smartSingleton.afterSingletonsInstantiated();
                return null;
             }, getAccessControlContext());
          }
          else {
             smartSingleton.afterSingletonsInstantiated();
          }
          smartInitialize.end();
       }
    }
}

可以看到有三个步骤:

  1. 合并BD

  2. 加载bean

  3. 激活SmartInitializingSingleton扩展点

合并BD这块前面已经了解过MergedBeanDefinitionPostProcessor

第二部分加载bean,本质上就到了前面从BeanFactory中获取bean的流程了,包括从FactoryBean中获取,和最近的获取,参考下面链接:

http://www.chymfatfish.cn/archives/spring-beansgetfromfactory#getbean(string-name)

第三部分激活SmartInitializingSingleton扩展点,这是一个bean完全加载完后的最后一步的扩展点,可以参考以下部分:

http://www.chymfatfish.cn/archives/springknowledge#docreatebean%E5%AE%8C%E6%88%90%E5%90%8E%E7%9A%84%E6%89%A9%E5%B1%95%E6%93%8D%E4%BD%9C---smartinitializingsingleton%23aftersingletonsinstantiated

finishRefresh - 初始化后处理:添加lifecycle成员

这一步会为 ApplicationContext 添加 lifecycleProcessor 成员,用来控制容器内需要生命周期管理的 bean。准备好生命周期管理器,就可以实现

  • 调用 context 的 start,即可触发所有实现 LifeCycle 接口 bean 的 start

  • 调用 context 的 stop,即可触发所有实现 LifeCycle 接口 bean 的 stop

最后再发布ContextRefreshed事件,整个refresh执行完成。

步骤一、清理类资源记录

// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();

DefaultResourceLoader是ResourceLoader接口的默认实现,内部维护了一个ConcurrentHashMap用来缓存class的resource。这里即清理前面记录的类资源(因为已经有了BeanDefinition)

初始化生命周期处理器

生命周期处理器是为了开启一些实现Lifecycle的bean,有明确的生命周期,激活它们的start方法,让他们开始工作,例如spring-test测试架构中的环境bean,我想启动一个内存redis服务器,就要在上下文加载完成后,启动redisServer,这里就可以利用Lifecycle的能力,让它们实现服务器自启动

http://www.chymfatfish.cn/archives/e2econstructor#%E5%90%AF%E5%8A%A8%E5%86%85%E5%AD%98redis
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// 初始化完成激活生命周期处理器的onRefresh方法
getLifecycleProcessor().onRefresh();

发布ContextRefreshedEvent事件

// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));

当监听到ContextRefreshedEvent事件,就意味着环境已经启动了,可以让我们的业务代码启动了

refreshBeanFactory

继承自AbstractRefreshableApplicationContext,核心逻辑见下面:

// 为spring应用上下文对象创建我们的beanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 为容器设置一个序列号ID,可以通过反序列化获取bean工厂
beanFactory.setSerializationId(getId());
// 自定义BeanFactory
customizeBeanFactory(beanFactory);
// 加载bean定义,这里完成了对资源模糊匹配查找的实现
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;

首先是创建beanFactory,如果没有特殊处理,在AbstractRefreshableApplicationContext#createBeanFactory的实现就是创建DefaultListableBeanFactory

protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

这个bean工厂前面已经见过

http://www.chymfatfish.cn/archives/spring-beansgetfromfactory#defaultlistablebeanfactory

然后自定义bean工厂,在AbstractRefreshableApplicationContext#customizeBeanFactory 也提供了默认实现

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    if (this.allowBeanDefinitionOverriding != null) {
       beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.allowCircularReferences != null) {
       beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}

这里配置了两个特性,即:

  • allowBeanDefinitionOverriding:是否允许覆盖同名称的不同定义的对象,它的使用位置在DefaultListableBeanFactory#registerBeanDefinition点我跳转

  • allowCircularReferences:是否允许循环依赖,它的使用位置在AbstractAutowireCapableBeanFactory#doCreateBean 方法第一步实例化的地方,判断是否需要保留早期bean提供三级缓存,点我跳转

最后就是loadBeanDefinitions做BD加载,在此方法中仅提供了一个抽象方法,在开发场景中最常用的就是通过xml配置文件加载BD,则参考AbstractXmlApplicationContext#loadBeanDefinitions 方法

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(getEnvironment());
    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);
}

在这个方法中可以看出来,就是在初始化BeanDefinitionReader,同时将ResourceEntityResolver资源解析器配置进去,它是DelegatingEntityResolver的实现,前面也见过

http://www.chymfatfish.cn/archives/springxml#delegatingentityresolver---xml%E7%BA%A6%E6%9D%9F%E5%8A%A0%E8%BD%BD%E5%99%A8

然后就是loadBeanDefinitions方法,其实就是调用到XmlBeanDefinitionReader#loadBeanDefinitions方法,前面也分析过其逻辑了

http://www.chymfatfish.cn/archives/springxml#loadbeandefinitions

ApplicationContextAwareProcessor - 上下文前后置处理器

实现了BeanPostProcessor接口,但只重写了postProcessBeforeInitialization方法,并未对postProcessAfterInitialization做过多处理。

它是Aware接口实现类具备Aware能力的来源

postProcessBeforeInitialization

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
          bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
          bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
          bean instanceof ApplicationStartupAware)) {
       return bean;
    }
    ……
       invokeAwareInterfaces(bean);
    ……
    return bean;
}

非Aware接口实现类,直接返回,是的话调用invokeAwareInterfaces

private void invokeAwareInterfaces(Object bean) {
    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 ApplicationStartupAware) {
       ((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
    }
    if (bean instanceof ApplicationContextAware) {
       ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }
}

方法比较清晰,是哪一类Aware,配什么属性即可

PostProcessorRegistrationDelegate

invokeBeanFactoryPostProcessors

扫描并激活BeanFactoryPostProcessors处理器

BeanFactoryPostProcessors也是一类可插入式的处理器,用于在加载完BD和BeanFactory后,开始初始化bean之前,用于调整BD定义和BeanFactory的一类处理器,它有两类特性:

  1. 可以采用配置注册和硬编码注册

  2. 可以实现order接口控制它们的执行顺序,但是实现order接口必须采用配置注册方式

http://www.chymfatfish.cn/archives/springknowledge#%E5%9C%A8refresh%E6%B5%81%E7%A8%8B%E4%B8%AD%E5%AF%B9beanfactory%E8%BF%9B%E8%A1%8C%E6%89%A9%E5%B1%95---beanfactorypostprocessor%23postprocessbeanfactory

这块代码整体分为三个部分:if-else加一块独立部分

if (beanFactory instanceof BeanDefinitionRegistry) {
    ……
}
else {
    // Invoke factory processors registered with the context instance.
    invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}

这一部分代码是一个if-else结构,判断条件是if (beanFactory instanceof BeanDefinitionRegistry)

因为对BeanDefinitionRegistry来说,有一部分专门的BeanFactoryPostProcessor——BeanDefinitionRegistryPostProcessor

而对于普通的BeanFactoryPostProcessor和特殊的BeanDefinitionRegistryPostProcessor,都有配置注册和硬编码注册两种注册方式,即整体代码块处理了3类注册流程,如果算上order接口,实际上流程更多

  1. BeanDefinitionRegistry激活BeanDefinitionRegistryPostProcessor

  2. BeanDefinitionRegistry激活BeanFactoryPostProcessor

  3. 普通BeanFactory激活BeanFactoryPostProcessor

个人认为这块代码有很大的优化空间

为BeanDefinitionRegistry处理硬编码的BeanDefinitionRegistryPostProcessor

先看if (beanFactory instanceof BeanDefinitionRegistry) 为true的部分

for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
       BeanDefinitionRegistryPostProcessor registryProcessor =
             (BeanDefinitionRegistryPostProcessor) postProcessor;
       registryProcessor.postProcessBeanDefinitionRegistry(registry);
       registryProcessors.add(registryProcessor);
    }
    else {
       regularPostProcessors.add(postProcessor);
    }
}

这一块是在找硬编码注册的处理器,为什么说是硬编码,因为这里的循环对象beanFactoryPostProcessors是来自于AbstractApplicationContext#invokeBeanFactoryPostProcessors方法中对AbstractApplicationContext#getBeanFactoryPostProcessors的调用,点我跳转

这里对结果进行循环,找到BeanDefinitionRegistryPostProcessor,直接执行,如果是常规的BeanFactoryPostProcessor就先不执行了,添加到regularPostProcessors里面去

为BeanDefinitionRegistry处理配置的且实现PriorityOrdered接口优先级最高的BeanDefinitionRegistryPostProcessor

String[] postProcessorNames =
       beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
       currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
       processedBeans.add(ppName);
    }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

然后这一部分找配置成bean的BeanDefinitionRegistryPostProcessor实现,并且调用invokeBeanDefinitionRegistryPostProcessors激活这些处理器

这里注意到,有一个判断条件是if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) ,即优先级最高

为BeanDefinitionRegistry处理配置的且实现Ordered接口优先级次高的BeanDefinitionRegistryPostProcessor

postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
       currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
       processedBeans.add(ppName);
    }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

然后是配置的BeanDefinitionRegistryPostProcessor且实现Ordered接口的

这里注意到,有一个判断条件是if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) ,即优先级次高

为BeanDefinitionRegistry处理配置的且没有实现Ordered接口的BeanDefinitionRegistryPostProcessor

boolean reiterate = true;
while (reiterate) {
    reiterate = false;
    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
       if (!processedBeans.contains(ppName)) {
          currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
          processedBeans.add(ppName);
          reiterate = true;
       }
    }
    sortPostProcessors(currentRegistryProcessors, beanFactory);
    registryProcessors.addAll(currentRegistryProcessors);
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
    currentRegistryProcessors.clear();
}

这一部分就是优先级最低的部分了

为BeanDefinitionRegistry处理硬编码和配置的BeanFactoryPostProcessor

invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

最后再把配置和硬编码的BeanFactoryPostProcessor激活一下

为普通BeanFactory处理硬编码的BeanFactoryPostProcessor

else {
    // Invoke factory processors registered with the context instance.
    invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}

为普通BeanFactory处理配置的BeanFactoryPostProcessor

也是对实现PriorityOrdered、Ordered、没实现Ordered的三类处理,不再细分

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
String[] postProcessorNames =
       beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
    if (processedBeans.contains(ppName)) {
       // skip - already processed in first phase above
    }
    else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
       priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    }
    else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
       orderedPostProcessorNames.add(ppName);
    }
    else {
       nonOrderedPostProcessorNames.add(ppName);
    }
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
    orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
    nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

最后清理缓存

beanFactory.clearMetadataCache();

invokeBeanDefinitionRegistryPostProcessors

private static void invokeBeanDefinitionRegistryPostProcessors(
       Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
       StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
             .tag("postProcessor", postProcessor::toString);
       postProcessor.postProcessBeanDefinitionRegistry(registry);
       postProcessBeanDefRegistry.end();
    }
}

执行postProcessBeanDefinitionRegistry,比较简单

invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory)

private static void invokeBeanFactoryPostProcessors(
       Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    for (BeanFactoryPostProcessor postProcessor : postProcessors) {
       StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
             .tag("postProcessor", postProcessor::toString);
       postProcessor.postProcessBeanFactory(beanFactory);
       postProcessBeanFactory.end();
    }
}

执行postProcessBeanFactory方法,比较简单

beanFactoryPostProcessor的实现案例

前面说过,beanFactoryPostProcessor可以用于修改beanDefinition,例如有一个bean记录连接密码:

<bean id="simpleBean" class="com.Spring.ch04.SimplePostProcessor">
    <property name="connectionString" value="bollocks"/>
    <property name="password" value="imaginecup"/>
    <property name="username" value="Microsoft"/>
</bean>

想要去除属性的输出,可以实现BeanFactoryPostProcessor

public class MyTest implements BeanFactoryPostProcessor {
    private Set<String> obscenties;

    public MyTest() {
        this.obscenties = new HashSet<String>();
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
            StringValueResolver valueResover = new StringValueResolver() {
                public String resolveStringValue(String strVal) {
                    if (isObscene(strVal)) return "*****";
                    return strVal;
                }
            };
            BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResover);
            visitor.visitBeanDefinition(bd);
        }
    }

    public boolean isObscene(Object value) {
        String potentialObscenity = value.toString().toUpperCase();
        return this.obscenties.contains(potentialObscenity);
    }

    public void setObscenties(Set<String> obscenties) {
        this.obscenties.clear();
        for (String obscenity : obscenties) {
            this.obscenties.add(obscenity.toUpperCase());
        }
    }
}

现在配置bean的注册方式,在xml中给obscenties配置好

<bean id="bfpp" class="com.Spring.ch04.ObscenityRemovingBeanFactoryPostProcessor">
	<property name="obscenties">
		<set>
			<value>bollocks</value>
			<value>winky</value>
			<value>bum</value>
			<value>Microsoft</value>
		</set>
	</property>
</bean>

这样在加载simpleBean的时候就可以自动屏蔽掉符合配置的value

ConfigurableListableBeanFactory bf=new XmlBeanFactory(new ClassPathResource("/METAINF/BeanFactory.xml"));
BeanFactoryPostProcessor bfpp = (BeanFactoryPostProcessor)bf.getBean("bfpp");
bfpp.postProcessBeanFactory(bf);
System.out.println(bf.getBean("simpleBean"))

PropertySourcesPlaceholderConfigurer类是用来解析占位符的,就是一个典型应用

http://www.chymfatfish.cn/archives/spring-boot#propertysourcesplaceholderconfigurer---%E6%8A%8A%E5%8D%A0%E4%BD%8D%E7%AC%A6%E8%A7%A3%E6%9E%90%E5%99%A8%E5%8A%A0%E8%BD%BD%E5%88%B0beanfactory

registerBeanPostProcessors

注册BeanPostProcessor,在前面几个方法中都通过直接调用add方法硬编码了几个BeanPostProcessor,但毕竟不是通用方法,这里对大部分自定义BeanPostProcessor做了统一处理,

前面了解过它是一个bean创建时的可插入式扩展

http://www.chymfatfish.cn/archives/springknowledge#%E5%9C%A8docreatebean%E6%B5%81%E7%A8%8B%E4%B8%AD%E5%AF%B9bean%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B%E7%9A%84%E5%89%8D%E7%BD%AE%E6%89%A9%E5%B1%95---beanpostprocessor%23postprocessbeforeinitialization

它的调用点实际上不止一个,比较典型的就是doCreateBean三步骤最后一步initializeBean

http://www.chymfatfish.cn/archives/spring-beansgetfromfactory#initializebean---%E5%88%9D%E5%A7%8B%E5%8C%96bean

BeanPostProcessor也有一个子接口:MergedBeanDefinitionPostProcessor,它的作用是处理MergedBeanDefinition,但是在spring代码中并没有一个叫MergedBeanDefinition的类,因为它其实是一个抽象意义,代表父子BD合并之后的混合BeanDefinition,它也在这里做了处理

回来看该方法,和上面invokeBeanFactoryPostProcessors方法逻辑基本一致,也对Ordered接口做了适配:

首先对BeanPostProcessor的实现按Ordered接口实现分类:

分成了PriorityOrdered、Ordered和没有Ordered三类,同时从PriorityOrdered里面筛选出了MergedBeanDefinitionPostProcessor,然后第一个加载PriorityOrdered实现类

for (String ppName : postProcessorNames) {
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
       BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
       priorityOrderedPostProcessors.add(pp);
       if (pp instanceof MergedBeanDefinitionPostProcessor) {
          internalPostProcessors.add(pp);
       }
    }
    else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
       orderedPostProcessorNames.add(ppName);
    }
    else {
       nonOrderedPostProcessorNames.add(ppName);
    }
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

第二个加载Ordered的实现,同时从Ordered里面筛选出了MergedBeanDefinitionPostProcessor

// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
    BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    orderedPostProcessors.add(pp);
    if (pp instanceof MergedBeanDefinitionPostProcessor) {
       internalPostProcessors.add(pp);
    }
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

第三个加载非Ordered,同时筛选出了MergedBeanDefinitionPostProcessor

// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
    BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    nonOrderedPostProcessors.add(pp);
    if (pp instanceof MergedBeanDefinitionPostProcessor) {
       internalPostProcessors.add(pp);
    }
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

最后再加载MergedBeanDefinitionPostProcessor

// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

最后最后硬编码一个默认实现类

// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

回看该方法,可以总结出与invokeBeanFactoryPostProcessors方法的一些异同:

  • 相似点:都是对注册和硬编码两类做处理,都有各自的子类处理器,例如BeanFactoryPostProcessor的BeanDefinitionRegistryPostProcessor、BeanPostProcessor的MergedBeanDefinitionPostProcessor

  • 不同点:BeanFactoryPostProcessor的处理注册连带调用,对于硬编码处理的目的也是提前和调用;BeanPostProcessor是只注册,在后面初始化的时候才调用,硬编码的处理也只是spring为了注册一些特殊的BeanPostProcessor,不提倡用户自行硬编码注册

registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors)

private static void registerBeanPostProcessors(
       ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
    if (beanFactory instanceof AbstractBeanFactory) {
       // Bulk addition is more efficient against our CopyOnWriteArrayList there
       ((AbstractBeanFactory) beanFactory).addBeanPostProcessors(postProcessors);
    }
    else {
       for (BeanPostProcessor postProcessor : postProcessors) {
          beanFactory.addBeanPostProcessor(postProcessor);
       }
    }
}

执行addBeanPostProcessor方法,比较简单

SimpleApplicationEventMulticaster - 默认事件广播器

成员变量

成员变量比较简单:

// 线程池,用于并发启动监听者的onApplicationEvent操作,可见监听方收到事件是并行执行的
private Executor taskExecutor;
private ErrorHandler errorHandler;
private volatile Log lazyLogger;

multicastEvent

广播的核心方法,在AbstractApplicationContext#refresh流程中触发

一个特别显眼的就是在AbstractApplicationContext#refresh方法的registerListeners中,说明前面注册完了广播器,后面注册监听器时,就会触发广播。另外在AbstractApplicationContext#startAbstractApplicationContex#stop方法中也会直接触发

广播中最核心的部分就是调用getApplicationListeners方法获得并遍历ApplicationListeners,分别起线程执行invokeListerner方法。进而调用到doInvokeListener

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
       if (executor != null) {
          executor.execute(() -> invokeListener(listener, event));
       }
       else {
          invokeListener(listener, event);
       }
    }
}

找到所有的事件监听器,执行遍历

如果线程池有,就通过线程池执行invokeListener,否则遍历执行invokeListener

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

直接看doInvokeListener

invokeListener

事件广播实际上是触发监听器的onApplicationEvent方法。从这个方法中就很容易看出了。

从invokeListner方法中调用到doInvokeListner后,

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
       listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        ……

调用监听器的onApplicationEvent方法

所以spring事件广播机制的逻辑其实就是实现监听器的onApplication方法,监听对应事件即可

http://www.chymfatfish.cn/archives/springknowledge#applicationlistener

DefaultLifeCycleProcessor - 默认生命周期处理器

成员变量

// LifeCycle管理组中的成员
private final List<LifecycleGroupMember> members = new ArrayList<>();

onRefresh

public void onRefresh() {
    startBeans(true);
    this.running = true;
}

startBeans - 上下文启动入口

private void startBeans(boolean autoStartupOnly) {
    // 找到所有的Lifecycle实现类
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new TreeMap<>();
    // 存入LifecycleGroup
    lifecycleBeans.forEach((beanName, bean) -> {
       if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
          int startupPhase = getPhase(bean);
          phases.computeIfAbsent(startupPhase,
                phase -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)
          ).add(beanName, bean);
       }
    });
    // 调用start方法
    if (!phases.isEmpty()) {
       phases.values().forEach(LifecycleGroup::start);
    }
}

 start

public void start() {
    ……
    for (LifecycleGroupMember member : this.members) {
       doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
    }
}

继续向下看

doStart

private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
    Lifecycle bean = lifecycleBeans.remove(beanName);
    if (bean != null && bean != this) {
        ……
          try {
             bean.start();
          }
          catch (Throwable ex) ……
       }
    }
}

这里就看到了,激活Lifecycle生命周期bean的start方法,从而做一些bean的开始和销毁工作

0

评论区