SpringBoot构造流程源码分析:Web应用类型推断( 二 )

getSpringFactorieslnstances 方 法 依 然 是 通 过 SpringFactoriesL oader 类 的loadFactoryNames 方法来获得 ME TA-INF/spring.factories 文件中注册的对应配置 。 在Spring Boot 2.2.1 版本中 , 该文件内具体的配置代码如下 。
#应用程序上下文的初始化器配置
org. springframework. context . Applicat ionContextInitializer=\org. springframework . boot . context . Configurat ionWarningsApplicationContextInitializer,\org. springframework. boot . context . ContextIdApplicat ionContextInitializer,\org. springframework . boot. context . config . Delegat ingApplicationContextInitializer, \org. springframework . boot . rsocket . context . RSocketPortInfoApplicat ionContextInitializer,\org. springframework. boot . web . context . ServerPortInfoApplicationContextInitializer配置代码中等号后面的类为接口 ApplicationContextlnitializer 的具体实现类 。 当获取到这些配置类的全限定名之后 , 便可调用 createSpringFactoriesInstances 方法进行相应的实例化操作 。
privateList createSpringFactoriesInstances(Class type,Class[] parameterTypes, ClassLoader classLoader, Object[] args,Set names) {List instances = new ArrayList<>(names. size());//遍历加裁到的类名(全限定名)for (String name : names) {try {//获取 CassClass instanceClass = ClassUtils. forName( name, classLoader);Assert. isAssignable(type, instanceClass);//获取有参构造器Constructor constructor = instanceClass. getDeclaredConstructor (parameterTypes);//创建对象「instance = (T) BeanUtils . instantiateClass( constructor, args);instances . add(instance);} catch (Throwable ex) {throw new IllegalArgumentException("Cannot instantiate " + type +”:”+ name, ex);}return instances;}完成获取配置类集合和实例化操作之后 , 调用 setlnitializers 方法将实例化的集合添加到SprinaApplication的成员变量initializers中 , 类型为
List>,代码如下 。
private List> initializers;public void setInitializers(Collection> initializers) {this. initializers = new ArrayList<>( initializers);}setlnitializers 方法将接收到的 initializers 作为参数创建了一一个新的 List,并将其赋值给SpringApplication 的 nitializers 成员变量 。 由于是创建了新的 List,并且直接赋值 , 因此该方法一-旦被调用 ,便会导致数据覆盖 , 使用时需注意 。
实例讲解
阅读完源代码 , 我们进行一些拓展 , 来自定义一个 ApplicationContextinitializer 接口的实现 , 并通过配置使其生效 。
这里以实现 ApplicationContextlnitializer 接口 , 并在 initialize 方法中打印容器中初始化了多少个 Bean 对象为例来进行演示 , 代码如下 。
@0rder(123) // @Order 的 vaLue 值越小越早执行
public class LearnApplicationContextInitializer implements ApplicationContextInitializer {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext)//打印容器里面初始化了多少个 BeanSystem. out. println("容器中初始化 Bean 数量:”+ applicationContext . getBeanDefinitionCount());}}上面就完成了一个最基础的 ApplicationContextInitializer 接口的实现类 。
当我们定义好具体的类和功能之后 , 可通过 3 种方法调用该类 。
第 一 种 方 法 就 是 参 考 Spring Boot 源 代 码 中 的 操 作,将 该 实 现 类 配 置 于META-INF/spring.factories 文件中 , 这种方法与上面讲到的源代码配置方法一致 。
第二种方法是通过 application.properties 或 application.yml 文件进行配置 , 格式如下 。
context . initializer . classes=com. secbro2 . learn. initializer. LearnApplicationCont-extInitial1ize这种方法是通过 DelegatingApplicationContextnitializer 类中的 initialize 方法获取到配置文件中对应的 context.initializer.classes 的值 , 并执行对应的 initialize 方法 。
第三种方法是通过 SpringApplication 提供的 addInitializers 方法进行追加配置 , 代码如下 。
public static void main(String[] args) {SpringApplication app = new SpringApplication(SpringLearnApplication. class, Person.class);//添加自定义 ContextInitializer,注意会覆盖掉默认配置的app. addInitializers(new LearnApplicationContextInitializer());app . run(args);}无论通过以上 3 种方法的哪一种 , 配置完成后 , 执行启动程序都可以看到控制台打印容器中Bean 数量的日志 。
本文给大家讲解的内容是Web应用类型推断ApplicationContextlnitializer加载

  1. 下篇文章给大家讲解的是ApplicationListener加载和入口类推断、SpringApplication 的定制化配置;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!