常用的 SpringApplication.run(Class, Args)
启动Spring应用, 创建或者更新 ApplicationContext
使用source类实例化一个 SpringApplication
实例, 并调用实例方法 run
.
public static ConfigurableApplicationContext run(Object[] sources, String[] args){ return new SpringApplication(sources).run(args); }
实例化的时候首先通过尝试加载 javax.servlet.Servlet
和 org.springframework.web.context.ConfigurableWebApplicationContext
推断当前是否是 web
环境.
然后从 spring.factories
获取 ApplicationContextInitializer
的实现类.
spring.factories
获取 ApplicationListener
的实现类 main
private Class<?> deduceMainApplicationClass() { try { //获取线程栈数据 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
到此实例化就完成了.
public ConfigurableApplicationContext run(String... args){ StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; //默认设置java.awt.headless为true configureHeadlessProperty(); //从spring.factories中获取org.springframework.boot.SpringApplicationRunListener的实现类 SpringApplicationRunListeners listeners = getRunListeners(args); //通过EventPublishingRunListener发布started事件 listeners.started(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); //重点: 创建更新上下文对象 context = createAndRefreshContext(listeners, applicationArguments); //上下文对象更新完调用 afterRefresh(context, applicationArguments); //通过EventPublishingRunListener发布finished事件 listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, ex); throw new IllegalStateException(ex); } }
监听 SpringApplication
的 run
方法. 通过 SpringFactoriesLoader
加载, 实现时需要提供public的构造方法接受 SpringApplication
和 String[]
为参数.
事件的发生顺序为 started -> environmentPrepared -> contextPrepared -> contextLoaded -> finished
.
SpringBoot默认使用 EventPublishingRunListener
这个实现类, 将各个事件封装并发布出去, 最终被 ApplicationListener
捕获.
public interface SpringApplicationRunListener{ void started(); void environmentPrepared(ConfigurableEnvironment environment); void contextPrepared(ConfigurableApplicationContext context); void contextLoaded(ConfigurableApplicationContext context); void finished(ConfigurableApplicationContext context, Throwable exception); }
private ConfigurableApplicationContext createAndRefreshContext(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments){ ConfigurableApplicationContext context; // Create and configure the environment //获取或创建环境实例, web环境使用StandardServletEnvironment, 非web环境使用StandardEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); //配置环境数据 //1. **commandLineArgs**属性从启动参数中解析, 格式"--name=value" //2. 配置profiles. 有效的profile(通过**spring.profiles.active**配置) 和 通过SpringApplication.profiles()指定的额外profile configureEnvironment(environment, applicationArguments.getSourceArgs()); //通过EventPublishingRunListener发布environmentPrepared事件 listeners.environmentPrepared(environment); //如果是web环境, 将非web环境实例转换成web环境实例: //使用有效的profile配置和jndiProperties, servletConfigInitParams, servletContextInitParams的配置. if (isWebEnvironment(environment) && !this.webEnvironment) { environment = convertToStandardEnvironment(environment); } //输出banner if (this.bannerMode != Banner.Mode.OFF) { printBanner(environment); } //创建上下文对象, 没有指定实现类的话(使用SpringApplicationBuilder.contextClass), 使用默认context类. 然后通过反射实例化上下文对象. //1. web环境使用org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext //2. org.springframework.context.annotation.AnnotationConfigApplicationContext //初始化实例的时候会做很多事, //1. 创建AnnotatedBeanDefinitionReader. 注册相关的Annotation Post Processor, 包括: ConfigurationClassPostProcessor(处理@Configuration标注的类), AutowiredAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, EventListenerMethodProcessor, DefaultEventListenerFactory //2. 创建ClassPathBeanDefinitionScanner. 扫描器, 扫描默认的过滤器@Service, @Component, @Registry, @Controller. 同时支持J2EE6的@ManagedBean和@Named // Create, load, refresh and run the ApplicationContext context = createApplicationContext(); //设置环境 context.setEnvironment(environment); //后续的处理 postProcessApplicationContext(context); //应用初始化器(ApplicationContextInitializer的实现类), 对上下文对象做更多初始化的操作, 比如: //1. 添加BeanFactoryPostProcessor //2 .设置上下文对象id //3 .代理配置中context.initializer.classes指定的初始化类 //4. 添加listener, 在web容器启动后更新环境变量中的端口号(server.ports中的local.server.port) applyInitializers(context); //通过EventPublishingRunListener发布contextPrepared事件 listeners.contextPrepared(context); //打印启动信息和有效的profile信息 if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } //将ApplicationArguments实例注册到BeanFactory中, 名字为springApplicationArguments // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); //从source(可以是Resource, Package, CharSequence或者Class. 从run方法进来的为Class)类加载Bean到上下文对象中 // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[sources.size()])); //通过EventPublishingRunListener发布contextLoaded事件 listeners.contextLoaded(context); //更新上下文对象, 调用ApplicationContext.refresh()方法 // Refresh the context refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } return context; }
BeanFactoryPostProcessor
, 基于精确的顺序如果指定了顺序的话. @Configuration
标注的类bean包含其他的bean定义), 会在常规的 BeanFactoryPostProcessor
的检查发生之前. @Configuration
标注的类中的bean定义会在此时假如到注册器中
. BeanPostProcessor
, 如果有顺序的话, 按照顺序来调用. MessageSource
实例. ApplicationEventMulticaster
实例, 应用可以用来注册应用事件的监听. ApplicationListener
实现类的监听器. LoadTimeWeaverAware
的bean, 冻结配置禁止修改bean定义, 实例化non-lazy-init的bean. LifecycleProcessor.onRefresh()
, 发布 ContextRefreshedEvent
事件, 将上下文实例暴露在MBean中.
BeanFactoryPostProcessor
的实现类, 用于引导 @Configuration
类.
默认情况下通过使用 <context:annotation-config/>
或者 <context:component-scan/>
注册.
集合了 @Configuration
, @EnableAutoConfiguration
和 @ComponentScan
属性: exclude
, excludeName
, scanBasePackage
, scanBasePackageClass
类似旧版配置中的xml配置文件, 提供Bean的定义和引入其他xml配置. 分别通过 @Bean
和 @Import
实现.
在ApplicationContext.refresh()时是用 ConfigurationClassPostProcessor
进行bean的实例化.
可以与 @PropertySource
, @Autowired
, @Value
, @Profile
搭配使用.
@Configuration @PropertySource("classpath:/com/acme/app.properties") public class AppConfig{ @Value("${bean.name}") String beanName; @Autowired DataSource dataSource; @Bean public MyBean myBean(){ return new MyBean(beanName); } @Configuration @Profile("test") static class DatabaseConfigTest{ @Bean DataSourcedataSource(){ return new EmbeddedDatabaseBuilder().build(); } } @Configuration @Profile("production") static class DatabaseConfigProduction{ @Bean DataSourcedataSource(){ return new EmbeddedDatabaseBuilder().build(); } } }
开启Spring上下文对象的自动配置功能, 尝试去猜测和实例化你 可能需要的 bean.
这个功能是基于classPath来完成的. 比如: 项目中引用了 tomcat-embedded.jar
, 你可能需要一个 TomcatEmbeddedServletContainerFactory
实例, 除非定义了自己的 EmbeddedServletContainerFactory
实例.
扫描使用 @Configuration
标注的类, 类似于Spring XML的 <context:component-scan>
元素.
使用 basePackages
和 basePackageClasses
属性来指定要扫描的包, 如果没有指定, 则默认从使用了该注解的类的包开始扫描.
提示 @Configuration
有更多的类需要引入, 类似xml中的 <import>
标签.
可以引入 @Configuration
类, ImportSelector
的实现类和 ImportBeanDefinitionRegistrar
的实现类, 还有常规的 Component
类.
三者的处理方式不一样:
@Configuration
常规方式 ImportSelector
会根据泛型类型从 spring.factories
找到对应的配置类. ImportBeanDefinitionRegistrar
可以实现在bean definition级别的处理 ( @Bean
实例级别)
在 引入
@Configuration
类中使用 @Bean
标注的实例, 可以通过 @Autowired
注入. Bean和声明Bean的Configuration类本身都可以通过 @Autowired
注入.
引入XML或者非Configuration, 使用 @ImportResource
.