前面在写业务框架后,由于项目依赖的Spring IOC,单将该项目install后,在其它项目引入时,会找不到所依赖的Bean。所以利用Springboot的自动转配,在项目启动时加载Bean,并注册到IOC容器中。
Springboot自动装配可以说是SpringBoot自己定义的SPI机制,SPI 的全名为 Service Provider Interface ,SPI 思想 也可以叫做 SPI机制 ,它就是为某个接口寻找服务实现的机制。
项目启动时,会传入启动类的Class对象,在创建完容器后,会将该传入的启动类注册包装成BeanDeifinition后注册到BeanFactory中。
public static void main(String[] args) {
//这里传入启动类对象
SpringApplication.run(BtestApplication.class, args);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//这里存放启动类传入的Class对象
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
BtestApplication.class 这个对象最终会被存入到primarySources属性集合中。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
//注册ConfigurationClassPostProcessor 工厂后置处理器
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//注册AutowiredAnnotationBeanPostProcessor 工厂后置处理器,用于处理器@Autowire等
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//注册AutowiredAnnotationBeanPostProcessor 工厂后置处理器,用于处理器@Resoruce注解等
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
在创建ConfigurableApplicationContext上下文对象时,会往容器中注册Spring内部处理器类,包括后面需要用到的BeanFactoryPostProcessor,跟自动装配相关的是ConfigurationClassPostProcessor后置处理器。
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置系统环境参数
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//获取Bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// Load the sources
//获取存放启动类Class对象的集合
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//将其注册到Bean工厂中
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
if (!CollectionUtils.isEmpty(this.primarySources)) {
allSources.addAll(this.primarySources);
}
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
return Collections.unmodifiableSet(allSources);
}
在前面Spring将系统启动所传入的Class对象存入到了primarySources集合中,现将该集合中的对象获取出来并注册到BeanFactory工厂中,后续需要扫描该类的注解。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 容器刷新前准备工作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//创建Bean工厂,解析配置
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// bean工厂准备工作
prepareBeanFactory(beanFactory);
try {
//拓展接口,留给子类进行实现拓展
postProcessBeanFactory(beanFactory);
// 注册执行,BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 注册创建BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 这个方法主要作用就是使用国际化,定制不同的消息文本,比如定义了一个Person的Bean,它有name属性,我们需要在不同的国家展示对应国家所在语言名称,这时候就可以使用国际化了。
initMessageSource();
// Initialize event multicaster for this context.
//初始化应用事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//拓展接口,留给子类进行实现拓展,springboot就对该方法进行了处理
onRefresh();
// Check for listener beans and register them.
//将内部的、以及我们自定义的监听器添加到缓存中,为后续逻辑处理做准备。还有添加事件源到缓存中。
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//实例化剩下非懒加载的Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//使用应用事件广播器推送上下文刷新完毕事件(ContextRefreshedEvent )到相应的监听器。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
//执行相关销毁方法
destroyBeans();
// Reset 'active' flag.
//重置上下文刷新状态
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
前面步骤都是基本准备工作,创建完上下文对象之后,调用Spring IOC的核心流程,完成Bean的扫描注册、实例化、初始化工作。笔者前面写了16篇Spring IOC的流程文章,有兴趣可以看一下。
在步骤1中,已经往BeanFactory工厂中注册了一个ConfigurationClassPostProcessor后置处理器
该后置处理器实现了BeanDefinitionRegistryPostProcessor接口,所以最终会调用其postProcessBeanDefinitionRegistry方法。
该方法主要作用:
1、获取所有的BeanDefinition,挨个循环判断
2、对@Componet、@PropertySources、@ComponentScans、@Import、@ImportResource进行解析处理
我们启动类配置了@SpringBootApplication注解,@SpringBootApplication注解信息如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@EnableAutoConfiguration:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
由于启动类配置了@Import注解,所以会动@Import进行解析操作
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
//如果Import选择器 实现了DeferredImportSelector接口,则添加到容器里面。后续会调用其getAutoConfigurationEntry方法
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//调用Import选择器的selectImports方法,返回需要注册的BeanName
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
由于启动类配置的Import是AutoConfigurationImportSelector类,而该类实现了DeferredImportSelector接口,所以不会直接调用其selectImports方法,网上有很多文章说是掉这个方法进来的,其实并不是。如果实现了DeferredImportSelector接口,会将该Selector实现类加入到集合中,在后续调用其getAutoConfigurationEntry()方法;
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取META/INF/spring.factories
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
getCandidateConfigurations(annotationMetadata, attributes),见方法1详解
该方法会加载META-INF/spring.factories目录下的文件,并获取文件KEY为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有配置类。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()),见方法2详解
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
//factoryTypeName=org.springframework.boot.autoconfigure.EnableAutoConfiguration
String factoryTypeName = factoryType.getName();
//加载获有的配置类放到缓存中,并从中获取KEY为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置类
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
//FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
//加载配置文件中的所有KEY-VELUE配置类,并将其放入缓存中
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
只要我们在META-INF/目录下的spring.factories文件中配置key为org.springframework.boot.autoconfigure.EnableAutoConfiguration,值为我们需要注入的自动装配类,Springboot会将该类包装成BeanDefinition并注入到IOC容器中;
使用Spring开发时,由于项目中某些类需要提前注入到IOC容器中时,我们可以利用Springboot的自动装配,遵守其约定,将自动装配类配置到META-INF/目录下的spring.factories文件中,并指定key为org.springframework.boot.autoconfigure.EnableAutoConfiguration。这样Springboot就可以将该类注入到IOC容器中。
如果一个ImportSelector实现类,实现了DeferredImportSelector接口,那么该ImportSelector并不会调用selectImports()方法,而是直接调用getAutoConfigurationEntry()方法,网上有很多文章直接说入口是selectImports(),所以学会看源码,才能看清本质。