在分析Spring IOC容器启动流程的时候,在加载Bean定义信息BeanDefinition的时候,用到了两个非常关键的类:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。它俩完成对Bean信息的加载。
因此为了更加顺畅的去理解Bean的加载的一个过程,本文主要介绍Spring的这两员大将的一个初始化过程,以及它俩扮演的重要角色。
IOC容器加载Bean定义信息分析
AnnotationConfigApplicationContext(spring-context包下)的继承图谱如下:
需要注意的是,我们在Tomcat等web环境下的容器类为:AnnotationConfigWebApplicationContext,它在spring-web包下
Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息。
而BeanDefinitionRegistry接口提供了向容器注册,删除,获取BeanDefinition对象的方法。
简单来说,BeanDefinitionRegistry可以用来管理BeanDefinition,所以理解AnnotationConfigApplicationContext很关键,它是spring加载bean,管理bean的最重要的类。
源码跟踪:
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
// 把该配置类(们)注册进来
register(annotatedClasses);
// 容器启动核心方法
refresh();
}
this()如下:
//AnnotatedBeanDefinitionReader是一个读取注解的Bean读取器,这里将this传了进去。
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
//从上面这个构造函数可以顺便提一句:如果你仅仅是这样ApplicationContext applicationContext = new AnnotationConfigApplicationContext()
// 容器是不会启动的(也就是不会执行refresh()的),这时候需要自己之后再手动启动容器
进而再看看register()方法:
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
实际逻辑在doRegisterBean()此方法上:
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 先把此实体类型转换为一个BeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//abd.getMetadata() 元数据包括注解信息、是否内部类、类Class基本信息等等
// 此处由conditionEvaluator#shouldSkip去过滤,此Class是否是配置类。
// 大体逻辑为:必须有@Configuration修饰。然后解析一些Condition注解,看是否排除~
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
// 解析Scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 得到Bean的名称 一般为首字母小写(此处为AnnotationBeanNameGenerator)
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 设定一些注解默认值,如lazy、Primary等等
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 解析qualifiers,若有此注解 则primary都成为true了
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 自定义定制信息(一般都不需要)
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 下面位解析Scope是否需要代理,最后把这个Bean注册进去
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
AnnotatedBeanDefinitionReader初始化,构造器如下:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
//ConditionEvaluator完成条件注解的判断,在后面的Spring Boot中有大量的应用
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//这句会把一些自动注解处理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中 具体见下面
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
这里将AnnotationConfigApplicationContext注册为管理BeanDefinition的BeanDefinitionRegistry,也就是说,spring中bean的管理完全交给了AnnotationConfigApplicationContext。
AnnotationConfigUtils#registerAnnotationConfigProcessors()
我们要用一些注解比如:@Autowired/@Required/@Resource都依赖于各种各样的BeanPostProcessor来解析(AutowiredAnnotation、RequiredAnnotation、CommonAnnotationBeanPostProcessor等等)。
但是像这种非常常用的,让调用者自己去申明,显然使用起来就过重了。所以Spring为我们提供了一种极为方便注册这些BeanPostProcessor的方式(若是xml方式,配置<context:annotation-config/>,若是全注解驱动的ApplicationContext,就默认会执行)
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 把我们的beanFactory从registry里解析出来
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
// 相当于如果没有这个AutowireCandidateResolver,就给设置一份ContextAnnotationAutowireCandidateResolver
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
//这里初始长度放4 是因为大多数情况下,我们只会注册4个BeanPostProcessor 如下(不多说了)
// BeanDefinitionHolder解释:持有name和aliases,为注册做准备
// Spring 4.2之后这个改成6我觉得更准确点
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);
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));
}
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));
}
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
// 支持JSR-250的一些注解:@Resource、@PostConstruct、@PreDestroy等
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.
// 若导入了对JPA的支持,那就注册JPA相关注解的处理器
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));
}
// 下面两个类,是Spring4.2之后加入进来的,为了更好的使用Spring的事件而提供支持
// 支持了@EventListener注解,我们可以通过此注解更方便的监听事件了(Spring4.2之后)
// 具体这个Processor和ListenerFactory怎么起作用的,且听事件专题分解
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;
}
我们发现:内部定义的class都是带internal的
(1) ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor处理器,BeanDefinitionRegistryPostProcessor的处理方法能处理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法内部处理@Configuration,@Import,@ImportResource和类内部的@Bean。
ConfigurationClassPostProcessor类继承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor类继承了BeanFactoryPostProcessor。
通过BeanDefinitionRegistryPostProcessor可以创建一个特别后置处理器来将BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。在Mybatis与Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor来对Mapper的BeanDefinition进行了后置的自定义处理。
(2) AutowiredAnnotationBeanPostProcessor是用来处理@Autowired注解和@Value注解的
(3) RequiredAnnotationBeanPostProcessor这是用来处理@Required注解
(4) CommonAnnotationBeanPostProcessor提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。
(5) EventListenerMethodProcessor提供@PersistenceContext的支持。
(6) EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener实在spring4.2之后出现的,可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener。
到此AnnotatedBeanDefinitionReader初始化完毕。
总结一下,AnnotatedBeanDefinitionReader读取器用来加载class类型的配置,在它初始化的时候,会预先注册一些BeanPostProcessor和BeanFactoryPostProcessor,这些处理器会在接下来的spring初始化流程中被调用。
ClassPathBeanDefinitionScanner的初始化:
跟踪构造函数的重载,最终都到这里:
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
//useDefaultFilters为true,所以此处一般都会执行
// 当然我们也可以设置为false,比如@ComponentScan里就可以设置为false,只扫描指定的注解/类等等
if (useDefaultFilters) {
registerDefaultFilters();
}
// 设置环境
setEnvironment(environment);
// 详情如下: 这里resourceLoader传值,还是我们的工厂。否则为null
setResourceLoader(resourceLoader);
}
registerDefaultFilters()
protected void registerDefaultFilters() {
// 这里需要注意,默认情况下都是添加了@Component这个注解的
//(相当于@Service @Controller @Respository等都会扫描,因为这些注解都属于@Component) 另外@Configuration也属于哦
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
//下面两个 是兼容JSR-250的@ManagedBean和330的@Named注解
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("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 {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
} catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
// 所以,如果你想Spring连你自定义的注解都扫描,自己实现一个AnnotationTypeFilter就可以啦
}
ClassPathBeanDefinitionScanner继承于ClassPathScanningCandidateComponentProvider,它内部维护有两个final类型的List:这两个对象在执行本类的scanCandidateComponents()方法时就会起作用。
//includeFilters中的就是满足过滤规则的
private final List<TypeFilter> includeFilters = new LinkedList<>();
//excludeFilters则是不满足过滤规则的
private final List<TypeFilter> excludeFilters = new LinkedList<>();
ClassPathScanningCandidateComponentProvider#setResourceLoader
为ResourcePatternResolver,MetadataReaderFactory和CandidateComponentsIndex设定初始值。
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
// Spring5以后才有这句,优化了bean扫描
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}