以配置文件方式(语法取决于你使用什么样的配置文件properties or xml or yml or yaml or 配置中心)
context.initializer.classes = 实现类A, 实现类B
在ConfigurationClassPostProcessor和Spring Boot之间创建共享的CachingMetadataReaderFactory, 干啥的我也不知道,后续debug在研究。
ContextIdApplicationContextInitializer用于设置SpringApplication.getId()的值,如果配置文件中指定了spring.application.name,则本类不起作用,反之。
ConfigurationWarningsApplicationContextInitializer添加BeanFactoryPostProcessor:ConfigurationWarningsPostProcessor用于打印配置错误的日志
ServerPortInfoApplicationContextInitializer用于设置server.ports属性的值,它是Web服务器实际监听的应用程序端口。同时实现了ApplicationListener接口用于监听WebServerInitializedEvent事件,WebServer初始化完毕之后设置端口。
// ServerPortInfoApplicationContextInitializer.java // ① public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.addApplicationListener(this); } // ② public void onApplicationEvent(WebServerInitializedEvent event) { String propertyName = "local." + getName(event.getApplicationContext()) + ".port"; setPortProperty(event.getApplicationContext(), propertyName, event.getWebServer().getPort()); } // ③ private String getName(WebServerApplicationContext context) { String name = context.getServerNamespace(); return StringUtils.hasText(name) ? name : "server"; } // ④ private void setPortProperty(ApplicationContext context, String propertyName, int port) { if (context instanceof ConfigurableApplicationContext) { setPortProperty(((ConfigurableApplicationContext) context).getEnvironment(), propertyName, port); } if (context.getParent() != null) { setPortProperty(context.getParent(), propertyName, port); } } @SuppressWarnings("unchecked") private void setPortProperty(ConfigurableEnvironment environment, String propertyName, int port) { MutablePropertySources sources = environment.getPropertySources(); PropertySource<?> source = sources.get("server.ports"); if (source == null) { source = new MapPropertySource("server.ports", new HashMap<>()); sources.addFirst(source); } ((Map<String, Object>) source.getSource()).put(propertyName, port); }① - 向上下文监听器列表中添加当前类(作为监听器加入)
② - 在监听事件中设置端口,默认属性为local.server.port
③ - 若设置了服务器Namespace,则属性值为local.Namespace的值.port
④ - 将监听端口信息填入server.ports属性下
用于设置ConditionEvaluationReportListener监听器,此监听器监听ContextRefreshedEvent和ApplicationFailedEvent,分别打印出上下文容器成功刷新和失败的日志报告
在这一章节中,可以看到ApplicationContextInitializer扩展接口的实际应用。通过Spring框架内置的一些initializer可以实现框架功能,同理我们也可以利用这一特性在上下文容器还未刷新之前做一些扩展功能。
发布ApplicationContextInitializedEvent事件由SpringApplicationRunListeners.contextPrepared(ConfigurableApplicationContext context)方法触发。
当上下文容器加载完毕所有的ApplicationContextInitializer之后,触发该事件,通知那些关注了此事件的监听器进行下一步操作。每次发布事件的时候可能已经有新的监听器被加进来,在上一章节中我们就看到会在ApplicationContextInitializer里面添加监听器
但我们只需要关注那些监听了当前事件的监听器即可。这里仅仅作为一个提示,监听器可能在任何地方被加进来。这里并未发现有监听器监听此事件。
日志打印的:The following profiles are active: dev,test 这一句就来自于此。代码比较简单一看便知。
if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } protected void logStartupProfileInfo(ConfigurableApplicationContext context) { Log log = getApplicationLog(); if (log.isInfoEnabled()) { String[] activeProfiles = context.getEnvironment().getActiveProfiles(); if (ObjectUtils.isEmpty(activeProfiles)) { String[] defaultProfiles = context.getEnvironment().getDefaultProfiles(); log.info("No active profile set, falling back to default profiles: " + StringUtils.arrayToCommaDelimitedString(defaultProfiles)); } else { log.info("The following profiles are active: "+ StringUtils.arrayToCommaDelimitedString(activeProfiles)); } } } 注册启动SpringApplication时的参数