文章目录
spring对象生命周期提供的扩展点:
1、BeanFactoryPostProcessor:实例化对象之前
2、BeanNameAware:设置容器中bean的名称
3、BeanFactoryAware:返回对象实例的beanFactory
4、BeanPostProcessor
5、InitializingBean
6、ApplicationContextAware
......
factoryBean 和 beanFactory
相同点:都是用来创建对象的
不同:
factoryBean 更像是一种标准的生产线,需要经过完整的步骤和过程才能生成具体的对象
beanFactory:更像是用户自定义,根据用户需求创建出具体对象
对象注入容器@Import:
可以导入添加了@Configuration的类
也可以直接导入类
导入实现了importSelector接口的类
导入实现ImportBeanDefinitionRegistrar接口
有条件的注入:Conditional注解
@ConditionalOnBean、@ConditionalOnClass、@ConditionalOnMissingBean......
提高对象注入效率:@indxed
编译时将所有需要注入的对象写道一个文件中,在注入时就不需要做包的扫描,直接读取这个文件就行了
springboot自动装配
@SpringBootApplication注解
其实是一个复合注解
run方法和SpringBootApplication注解怎么联系起来的
包含confuguration注解,主类本身会作为配置类扫描到创建对象放入容器中,在spring对象的生命周期中有configuration注解
对应的beanFactoryPostProceessor扩展类:configurationClassPostProcessor
在创建beanDefinition后会执行postProcessBeanFactory()会处理类上的其他注解,进而会处理到import注解
这里又会调用自身的processConfigurationBeanDefinition(),这个方法中会使用ConfigurationClassParser来解析配置类
(因为加了configuration注解)
parse方法解析配置类
调用重载的parse方法
都会调用自身的processConfigurationClass方法
真正的业务方法:doProcessConfigurationClass()
真正解析import注解
AutoConfigurationImportSelector就实现了DeferredImportSelector接口
所以在解析import注解时发现导入的类实现了DeferredImportSelector,不会去掉selectImports()方法,而是调用handle
最终会调用
这里就会调用DeferredImportSelector接口的类部类group的process()方法
AutoConfigurationImportSelector实现的process方法,从spring.factory文件读取自动装配类
这样就和AutoConfigurationImportSelector联系起来了,自动装配的流程就更完善了
SpringBootConfiguration
就是一个configuration注解
ComponentScan
扫描要把对象注入容器的包(类上有@configuration、@component、@service…就会被放入ioc容器中管理)
EnableAutoConfiguration
又是一个复合注解
重点看这个:@Import(AutoConfigurationImportSelector.class)
,
AutoConfigurationImportSelector的作用:
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取资源文件下:MEAT-INF下的spring.factory文件中的全路径类名
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//去重
configurations = removeDuplicates(configurations);
//去掉排除在外的(@SpringBootApplication中的exclude
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
//去掉排除在外的(@SpringBootApplication中的exclude
configurations.removeAll(exclusions);
//根据过滤器过滤掉部分
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
getCandidateConfigurations(annotationMetadata, attributes);
从spring.factory文件中获取key为EnableAutoConfiguration的所有类
getSpringFactoriesLoaderFactoryClass()
就是EnableAutoConfiguration的全路径类名
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader())
loadSpringFactories
FACTORIES_RESOURCE_LOCATION
就是META-INF/spring.factories
这样就把所有srping.factory文件中以org.springframework.boot.autoconfigure.EnableAutoConfiguration为key的所有值全部拿到
过滤部分自动装配类:这是除了使用OnConditional注解的另一中有条件的注入,根据META-INF/spring-autoconfigure-metadata.properties
文件中的配置过滤
至此已经了解到SpringBootConfiguration注解的作用,那么注解是在什么时候起作用的?
SpringApplication.run方法
点进去可以发现分为两部分:1、创建SpringApplication类,2、然后调用其run方法
创建SpringApplication类
调用构造方法创建SpringApplication类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//推断程序是否是web应用(如果是:是servlet还是reactive类型)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从系统资源文件spring.factory下找到以BootstrapRegistryInitializer为Key的所有类,添加进集合
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
//从系统资源文件spring.factory下找到以ApplicationContextInitializer为Key的所有类,添加进集合
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从系统资源文件spring.factory下找到以ApplicationListener为Key的所有类,添加进集合
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//找到main方法所在类
this.mainApplicationClass = deduceMainApplicationClass();
}
run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
//计时开始
stopWatch.start();
//根据创建SpringApplication类时添加的bootstrapRegistryInitializers集合创建bootstrapContext
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
//找到系统资源文件下spring.factory中以SpringApplicationRunListener为key的所有类
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//重点,刷新容器
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
refreshContext(context)
:最终会调用AbstractApplicationContext下的refresh方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//实例化对象并调用BeanFactoryPostProcessors后置增强器
//从spring.facotry文件中读取的以EnableAutoConfiguration为Key的所有自动装配类在这里面完成对象实例化
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
contextRefresh.end();
}
}
}
总结自动装配原理:
0、包含confuguration注解,主类本身也会被扫描创建对象放入容器中,
在spring对象的生命周期中有configuration注解对应的beanFactoryPostProceessor(configurationClassPostProcessor)包含confuguration注解,
主类本身也会被扫描创建对象放入容器中,在spring对象的生命周期中有configuration注解对应的
beanFactoryPostProceessor,在创建beanDefinitionhou会处理类上的其他注解,
进而会处理到import注解,在创建beanDefinitionhou会处理类上的其他注解,进而会处理到import注解
1、SpringBootApplication注解中的EnableAutoConfiguration注解导入了AutoConfigurationImportSelector类,这个类的作用
就是把spring.factory文件中以EnableAutoCinfiguration为key的所有自动装配类名:getAutoConfigurationEntry方法,通过
conditional注解和META-INF/spring-autoconfigure-metadata.properties中的配置进行过滤得到最终要加载进内存
2、springApplication的run方法最终会通过refreshContext()->refresh()->invokeBeanFactoryPostProcessors(beanFactory)->.....
最终调用到AutoConfigurationImportSelector中的getAutoConfigurationEntry(),拿到所有自动装配的类名后,通过反射创建对
象(@configuration、@bean、@component等注解)
自定义starter
明白了springboot自动装配原理,那么自定义starter就很简单
1、创建一个starter项目,定义一个自动装配类使用@configuration和@bean或者是@componentScan搭配使用,使用
conditional注解或者在资源文件下创建META-INF/spring-autoconfigure-metadata.properties设置自动装配的条件
2、在资源文件下创建META-INF/spring.factory文件:内容为k=v形式,key就是org.springframework.boot.autoconfigure,
value是自定义的自动装配类群全路径类名
如果想要实现别的项目引入starter之后编写application配置文件有自动提示的效果:在MEAT-INF下创建additional-spring-configuration-metadata.json文件
,并填写响应的文件
3、打包项目,在其他springboot项目中引入即可