文章目录
1.美图
2.概述
梳理Spring 容器启动时,注解bean 加载的主流程和相关核心逻辑。
3.案例
3.1 案例1
bean
package com.spring.boot.annotation;
import lombok.Data;
@Data
public class TestBean {
private String name;
}
初始化string bean
package com.spring.boot.annotation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
class NameConfig {
@Bean
String name() { return "foo"; }
}
配置
package com.spring.boot.annotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(NameConfig.class)
//@Import(AspectJAutoProxyRegistrar.class)
//@ImportResource("org/springframework/aop/aspectj/AfterAdviceBindingTests.xml")
class AutowiredConfig {
@Autowired
private String name;
@Bean
TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(name);
return testBean;
}
}
测试类
package com.spring.boot.annotation;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import static org.junit.Assert.*;
import static org.springframework.util.StringUtils.uncapitalize;
public class NameConfigTest {
@Test
public void scanAndRefresh() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.springframework.context.annotation6");
context.refresh();
// context.getBean(uncapitalize(ConfigForScanning.class.getSimpleName()));
// context.getBean("testBean"); // contributed by ConfigForScanning
// context.getBean(uncapitalize(ComponentForScanning.class.getSimpleName()));
// context.getBean(uncapitalize(Jsr330NamedForScanning.class.getSimpleName()));
Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
assertEquals(1, beans.size());
}
@Test
public void registerAndRefresh() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AutowiredConfig.class);
//context.register(Config.class, NameConfig.class);
context.refresh();
context.getBean("testBean");
context.getBean("name");
Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
assertEquals(2, beans.size());
}
}
4.容器初始化
先说明几个在Spring 初始化容器中非常重要的对象
- BeanDefinition 对象:容器中的每一个 bean 都会有一个对应的 BeanDefinition 实例。该实例负责保存 bean 对象的所有必要信息,包括 bean 对象的 class 类型、是否是抽象类、构造方法和参数、其他属性等等。
- BeanDefinitionRegistry 对象: 抽象出 bean 的注册逻辑。registerBeanDefinition、removeBeanDefinition、getBeanDefinition 等注册管理 BeanDefinition 的方法。
- BeanFactory 对象: 则抽象出了 bean 的管理逻辑。主要包含 getBean、containBean、getType、getAliases 等管理 bean 的方法。
- DefaultListableBeanFactory 对象: 作为一个比较通用的 BeanFactory 实现,它同时也实现了 BeanDefinitionRegistry 接口,因此它就承担了 bean 的注册管理工作,这是常用的注册管理bean 的beanFactory。
5.AnnotationConfigApplicationContext
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
//直接将注解bean注册到容器,通过将涉及到的配置类传递给该构造函数,以实现将相应配置类中的Bean自动注册到容器中
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
}
从源码中可以看出,空参的构造方法会先初始化sacner和reader,为进行bean的解析注册做准备,而容器里不包含任何Bean信息,从注释
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
可以看出,如果调用空参构造,需要手动调用其register()方法注册配置类,并调用refresh()方法刷新容器,触发容器对注解Bean的载入、解析和注册过程。
而BeanFactory是在哪里初始化的呢?
从AnnotationConfigApplicationContext
父类中,可以找到beanFactory
的初始化。
GenericApplicationContext#new
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
在new DefaultListableBeanFactory()
过程中会初始化所有父类的属性以及加载各种配置,如beanClassLoader,InstantiationStrategy
等。
然后在初始化AnnotatedBeanDefinitionReader
过程中,会初始化spring inner-post-processor
,包括BeanPostProcessor
和BeanFactoryPostProcessor
(比如
ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor)。
AnnotatedBeanDefinitionReader#new
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
AnnotationConfigUtils#registerAnnotationConfigProcessors
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);
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));
}
...
return beanDefs;
}
而在初始化ClassPathBeanDefinitionScanner
时,会注册过滤器,也就是需要扫描什么注解,比如@Component
。
protected void registerDefaultFilters() {
//向要包含的过滤规则中添加@Component注解类,注意Spring中@Repository
//@Service和@Controller都是Component,因为这些注解都添加了@Component注解
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
//获取当前类的类加载器
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
//向要包含的过滤规则添加JavaEE6的@ManagedBean注解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
//向要包含的过滤规则添加@Named注解
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
此时容器的初始化完成。开始注册bean Definition
5.1 registerBean
Spring 提供两种bean的注册方式,一种时通过扫描路径来加载,另一种则是通过class文件来注册。先来看下class文件注册。
5.1.1 class文件注册
@Test
public void registerAndRefresh() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AutowiredConfig.class);
context.refresh();
context.getBean("testBean");
context.getBean("name");
Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
assertEquals(2, beans.size());
}
主要看context.register(AutowiredConfig.class)
方法,主要流程如下:
5.1.2 AnnotationBeanDefinitionReader#doRegisterBean
<T> void doRegisterBean(Class<T> beanClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
//根据指定的注解Bean定义类,创建Spring容器中对注解Bean的封装的数据结构
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
//用来解析注释了@condition注解的类,不满足条件跳过
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//设置创建bean实例的回调
abd.setInstanceSupplier(instanceSupplier);
//解析注解Bean定义的作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
//为注解Bean定义设置作用域
abd.setScope(scopeMetadata.getScopeName());
//为注解Bean生成Bean名称
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//处理注解Bean定义中的通用注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
//如果在向容器注册注解Bean定义时,使用了额外的限定符注解,则解析限定符注解。
//主要是配置的关于autowiring自动依赖注入装配的限定条件,即@Qualifier注解,Spring自动依赖注入装配默认是按类型装配,
// 如果使用@Qualifier则按名称
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
//如果配置了@Primary注解,设置该Bean为autowiring自动依赖注入装配时的首选
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
//如果配置了@Lazy注解,则设置该Bean为非延迟初始化,如果没有配置,则该Bean为预实例化
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
//如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一
//个autowiring自动依赖注入装配限定符,该Bean在进autowiring
//自动依赖注入装配时,根据名称装配限定符指定的Bean
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
//创建一个指定Bean名称的Bean定义对象,封装注解Bean定义类数据
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//根据注解Bean定义类中配置的作用域,创建相应的代理对象
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//向IoC容器注册注解Bean类定义对象
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
可以看出,就是将annotatedClass解析成BeanDefinition,并将bean的属性例如@Lazy等封装进去,接着调用beanFactory的注册:
DefaultListableBeanFactory#registerBeanDefinition
/**
* 向IOC容器注册解析的BeanDefiniton
* @param beanName the name of the bean instance to register
* @param beanDefinition definition of the bean instance to register
* @throws BeanDefinitionStoreException
*/
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
//校验解析的BeanDefiniton,如果beanDefinition是AbstractBeanDefinition实例,则验证
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
//验证不能将静态工厂方法与方法重写相结合(静态工厂方法必须创建实例) 此处的检验是针对AbstractBeanDefinition的属性methodOverrides的检验
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 2、优先尝试从缓存中加载BeanDefinition
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// beanName已经存在且不允许被覆盖,抛出异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
// 使用新的BeanDefinition覆盖已经加载的BeanDefinition,if else中只有日志打印,无实质代码,删除为了阅读方便
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
//覆盖 beanDefinition 与 被覆盖的 beanDefinition 不相同,打印 debug 日志
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//其他的,都打印debug日志
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//允许覆盖,直接覆盖原有的 BeanDefinition 到 beanDefinitionMap 中。
this.beanDefinitionMap.put(beanName, beanDefinition);
}
// 3、缓存中无对应的BeanDefinition,则直接注册
else {
// 如果beanDefinition已经被标记为创建(为了解决单例bean的循环依赖问题)
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
//注册的过程中需要线程同步,以保证数据的一致性
synchronized (this.beanDefinitionMap) {
// 将beanDefinition保存到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
// 创建List<String>并将缓存的beanDefinitionNames和新解析的beanName加入集合,对beanDefinitionNames进行重新的扩容操作
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
//添加扩容之前的
updatedDefinitions.addAll(this.beanDefinitionNames);
//添加beanName到updatedDefinitions中
updatedDefinitions.add(beanName);
// 将updatedDefinitions赋值给beanDefinitionNames
this.beanDefinitionNames = updatedDefinitions;
// 如果manualSingletonNames中包含新注册的beanName
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
// 将beanDefinition信息维护至缓存
// beanDefinitionMap-->(key->beanName,value->beanDefinition)
this.beanDefinitionMap.put(beanName, beanDefinition);
// beanDefinitionNames-->维护了beanName集合
this.beanDefinitionNames.add(beanName);
// manualSingletonNames缓存了手动注册的单例bean,所以需要调用一下remove方法,防止beanName重复
// 例如:xmlBeanFactory.registerSingleton("myDog", new Dog());
// 就可以向manualSingletonNames中注册单例bean
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
//检查是否有同名的BeanDefinition已经在IOC容器中注册
// 4、重置BeanDefinition,
// 当前注册的bean的定义已经在beanDefinitionMap缓存中存在,
// 或者其实例已经存在于单例bean的缓存中
if (existingDefinition != null || containsSingleton(beanName)) {
//重置所有已经注册过的BeanDefinition的缓存
resetBeanDefinition(beanName);
}
}
BeanDefinition的注册分为步:
- 从缓存中取出当前bean的BeanDefinition
- 如果存在,则用当前BeanDefinition覆盖原有的
- 如果不存在,判断当前bean是否以及开始创建
- 如果没有开始创建,则将当前BeanDefinition,以及beanName放入缓存
- 如果已经开始创建,将当前BeanDefinition和beanName放入缓存后,如果当前bean是manual singleton bean,则将当前beanName从manual singleton Bean Name中移出,也就是变成了普通的bean,这里的manual singleton Bean指的是以下几种bean:
5.2 scanBean方式
新建类
package com.spring.boot.annotation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConfigForScanning {
@Bean
public TestBean testBean() {
return new TestBean();
}
}
package com.spring.boot.annotation;
import org.springframework.stereotype.Component;
@Component
public class ComponentForScanning {
}
package com.spring.boot.annotation;
import javax.inject.Named;
@Named
public class Jsr330NamedForScanning {
}
测试类
@Test
public void scanAndRefresh() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("com.spring.boot.annotation");
context.refresh();
context.getBean(uncapitalize(ConfigForScanning.class.getSimpleName()));
context.getBean("testBean"); // contributed by ConfigForScanning
context.getBean(uncapitalize(ComponentForScanning.class.getSimpleName()));
context.getBean(uncapitalize(Jsr330NamedForScanning.class.getSimpleName()));
Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
assertEquals(1, beans.size());
}
还是先看context.scan()
方法。主要流程如下:
5.2.1 ClassPathBeanDefinitionScanner#doScan
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//扫描给定类路径,获取符合条件的Bean定义
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//获取Bean定义类中@Scope注解的值,即获取Bean的作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//生成bean name
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//如果扫描到的Bean不是Spring的注解Bean,则为Bean设置默认值,
//设置Bean的自动依赖注入装配属性等
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
//如果扫描到的Bean是Spring的注解Bean,则处理其通用的Spring注解
if (candidate instanceof AnnotatedBeanDefinition) {
//处理注解Bean中通用的注解
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//根据Bean名称检查指定的Bean是否需要在容器中注册,或者在容器中冲突
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//根据注解中配置的作用域,为Bean应用相应的代理模式
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
这个其实和registerBean差不多,只是多了一步从扫描路径里获取符合的bean并封装到beanDefinition中,然后就是registerBean的流程
ClassPathScanningCandidateComponentProvider#scanCandidateComponents
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
//解析给定的包路径,this.resourcePattern=” **/*.class”,
//ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX=“classpath:”
//resolveBasePackage方法将包名中的”.”转换为文件系统的”/”
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//将给定的包路径解析为Spring资源对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
//为指定资源获取元数据读取器,元信息读取器通过汇编(ASM)读取资源元信息
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//如果扫描到的类符合容器配置的过滤规则
if (isCandidateComponent(metadataReader)) {
//通过汇编(ASM)读取资源字节码中的Bean定义元信息
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
//设置Bean定义来源于resource
sbd.setResource(resource);
//为元数据元素设置配置资源对象
sbd.setSource(resource);
//检查Bean是否是一个可实例化的对象
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}