主启动类
文章目录
- 主启动类
- @SpringBootApplication
- 作用
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @AutoConfigurationPackage
- @Import
-
- @ComponentScan
- run()
- ApplicationContext
- 启动后执行
- @PostConstruct
- 两个接口
- ApplicationListener
@SpringBootApplication
作用
package li_maven;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
@SpringBootConfiguration
- 包含
@Configuration
注解
- 可以作为配置类、配置文件使用
- 可使用
@Bean
声明对象注入到容器 - 包含
@Component
注解
@EnableAutoConfiguration
@AutoConfigurationPackage
@Import
@Import({AutoConfigurationImportSelector.class})
- 开启自动配置类的导包的选择器
- 即:带入哪些类,有选择性的导入
@Import
支持导入的三种方式
- 带有
@Configuration
注解的配置类 ImportSelector
的实现ImportBeanDefinitionRegistrar
的实现
自动装配流程
自动装配在 AutoConfigurationImportSelector
类中进行以下流程
-
selectImports(AnnotationMetadata annotationMetadata)
:选择需要导入的组件
- 调用
getAutoConfigurationEntry()
方法
-
getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)
- 根据导入的配置类的
AnnotationMetadata
返回 AutoConfigurationImportSelector.AutoConfigurationEntry
- 调用
getCandidateConfigurations()
方法找到所有候选的配置类
-
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)
-
loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)
-
传入参数:this.getSpringFactoriesLoaderFactoryClass()
-
String factoryTypeName = factoryType.getName();
factoryType
是 EnableAutoConfiguration.class
-
ClassLoader classLoaderToUse = classLoader
- 当传入类加载器为空时:
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader()
-
返回值:调用 loadSpringFactories()
转为 List 集合返回
- 方法返回值 Map 集合
- 调用
getOrDefault(factoryTypeName, Collections.emptyList())
factoryTypeName
值是 EnableAutoConfiguration
- 获取对应的 value
META-INF/spring.factories
文件下key
为 org.....EnableAutoConfiguration
得值对应的 value
- value 不存在时返回默认值空数组
-
loadSpringFactories(ClassLoader classLoader)
:返回 Map 集合
- 先从缓存中根据传进来的类加载器加载组件得到 Map result
- result 不为 null 时直接返回
- 为 null 时创建新的 HashMap result
Enumeration urls = classLoader.getResources("META-INF/spring.factories")
- 固定资源路径:
META-INF/spring.factories
- 加载引入 jar 包当前类路径下的
META-INF/spring.factories
文件 - 将所有资源加载到 Propeties 配置文件中
- 获取到组件后放入 result 集合中(此时强转为 List)
- key:文件中定义的一些标识工厂类
- value:能自动配置的一些工厂实现的类
- 将 classLoader 作为 key,result 作为 value 放入缓存
- 返回 result
- 方法作用
- 加载所有依赖的路径
META-INF/spring.factories
文件 - 通过 map 结构保存
- key:文件中定义的一些标识工厂类
- value:能自动配置的一些工厂实现的类
SpringFactoriesLoader
工厂加载机制
- Spring内部提供的一个约定俗成的加载方式
- 只需要在模块的
META-INF/spring.factories
文件
- Properties 格式的文件中
- key:接口、注解、或抽象类的全名
- value:以
,
分隔的实现类
- 使用
SpringFactoriesLoader
实现相应的实现类注入 Spirng 容器
- 加载所有 jar 包下的
classpath
路径下的 META-INF/spring.factories
文件
自动配置原理
-
SpringBoot 启动的时候加载主配置类
@EnableAutoConfiguration
注解开启自动配置功能
-
@EnableAutoConfiguration
作用
- 利用
EnableAutoConfigurationImportSelector
给容器中导入一些组件 - 查看
selectImports()
方法的内容
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
SpringFactoriesLoader.loadFactoryNames()
- 扫描所有jar包类路径下
META-INF/spring.factories
- 把扫描到的文件的内容包装成
properties
对象 - 从
properties
中获取 EnableAutoConfiguration.class
类(类名)对应的值 - 然后把他们添加在容器中
- 将类路径
META-INF/spring.factories
里面配置的所有 EnableAutoConfiguration
的值加入到了容器 - 这样的
xxxAutoConfiguration
类都是容器中的一个组件,都加入到容器中,用他们来做自动配置
-
对每一个自动配置类进行自动配置功能
- 以
HttpEncodingAutoConfiguration
为例解释自动配置原理
- 所有配置文件中能配置的属性都是在
xxxxProperties
类中封装
- 在配置文件中设置属性之后会自动装配到配置类中
@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final HttpEncodingProperties properties;
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean(CharacterEncodingFilter.class)
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
}
- 当需要其他的配置时
- 如监听相关配置:listenter
- 传入不同的参数,获取相关的 listenter 配置
- 只有自动配置类进入到容器中以后,这个自动配置类才开始进行启动
- 通过
@Conditional
等注解的判断进行动态加载
- 加载自动配置类的时候,并非将 spring.factories 的配置全部加载进来
@ComponentScan
- 组件扫描器,配置用于 Configuration 类的组件扫描指令
- 类似
<context:component-scan>
basePackageClasses
或basePackages
来定义要扫描的特定包
- 默认扫描 @ComponentScan 所在类的同级包和子包
run()
- SpringApplication.run() 方法启动流程
- 作用
- 判断应用类型:普通项目 或 Web 项目
- 查找并加载所有可用初始化器,设置到
initializers
属性 - 加载所有监听器程序,设置到
listeners
属性 - 判断并设置 main() 方法定义类,找到运行主类
ApplicationContext
@Repository
class Demo{
}
@SpringBootApplication
public class DemoApplication{
public static void main(String[] args){
ApplicationContext context = SpringApplication.run( DemoApplication.class, args);
Demo demo = (Demo)context.getBean("demo");
System.out.println(demo);
}
}
启动后执行
- 开发中可能需要在容器启动后执行一些内容
- 四种实现方式
- 注解:
@PostConstruct
- 实现
CommandLineRunner
接口 - 实现
ApplicationRunner
接口 - 实现
ApplicationListener
接口
- 执行顺序
- 注解
@PostConstruct
始终最先执行 - 监听
ApplicationStartedEvent
事件 ApplicationRuner
默认优先执行CommandLineRunner
默认后执行
- 若两个接口都指定了
@Order
则按数字大小执行 - 数字越小优先级越高
- 监听
ApplicationReadyEvent
事件
@PostConstruct
- Java 自带注解,注解在方法上会在项目启动时执行该方法
- 执行顺序
- 构造函数
@Autowired
@PostConstruct
- 注意事项
- 方法不能有参数
- 方法返回值为 void
- 方法不能抛出已检查异常
- 方法是非静态方法
- 方法只会被执行一次
- 耗时长的逻辑应放到独立线程,减少容器初始化时间
- 容器加载过程
- SpringBoot 将标记 Bean 的相关注解的类或接口自动初始化全局单一实例
- 当未标记初始化顺序时按照默认顺序进行初始化
- 初始化过程中执行一个 Bean 的构造方法后会执行该类存在的
@PostConstruce
方法,之后再初始化下一个 Bean
- 则
@PostConstruct
方法中逻辑处理时间过长时会增加 SpringBoot 初始化 Bean 时间,增加应用启动时间
- 只有 Bean 初始化完成后才会打开端口服务,所以初始化完成前应用不可访问
两个接口
ApplicationListener
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)