基于Annotation的IOC初始化
Annotation的前世今生
Spring2.0后,Spring也引入了基于注解(Annotation)方式的配置,注解(Annotation)是JDK1.5之后的新特性,用于简化Bean配置,可以去到XML配置文件。个人认为注解可以简化配置,提高开发速度,但是也会给后期维护增加难度。目前还是XML方式发展相对成熟,方便统一管理。随着SpringBoot的兴起,基于注解的开发甚至实现了零配置。个人习惯还是倾向于 xml和注解相互使用。SpringIOC容器对于类级别的主机和类内部的注解分为以下两种处理策略:
1.类级别:@Component、@Repository、@Controller、@Service以及JavaEE6的@ManagedBean和@Named注解。都是添加在类上面的类级别注解,Spring容器根据注解的过滤规则扫描读取注解Bean定义类,并将其注册到SpringIOC容器中。
2.类内部:@Autowire、@Value、@Resource以及EJB和WebService相关的注解等,都是添加在类内部的字段上内部注解,SpringIOC容器通过Bean后置注解处理器解析Bean内部的注解。下面根据两种处理策略,分别分析Spring处理的方式。
1.定位Bean扫描路径
Spring中管理注解Bean定义的容器有两个:** 、AnnotationConfigWebApplicationContext。
这两个类是专门处理Spring注解方式配置的容器,直接依赖于注解作为容器配置信息来源的IOC容器。AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext**的Web版本,两者的用法以及应对注解的处理方式几乎没有区别。
下面来看看AnnotationConfigWebApplicationContext的源码:
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
//保存一个读取注解的Bean定义读取器,并将其设置到容器中
private final AnnotatedBeanDefinitionReader reader;
//保存一个扫描指定类路径中注解Bean定义的扫描器,并将其设置到容器中
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
//默认构造函数,初始化一个空容器,容器不包含任何 Bean 信息,需要在稍后通过调用其register()
//方法注册配置类,并调用refresh()方法刷新容器,触发容器对注解Bean的载入、解析和注册过程
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
/**
* Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory.
* @param beanFactory the DefaultListableBeanFactory instance to use for this context
*/
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given annotated classes and automatically refreshing the context.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
//最常用的构造函数,通过将涉及到的配置类传递给该构造函数,以实现将相应配置类中的Bean自动注册到容器中
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
/**
* Create a new AnnotationConfigApplicationContext, scanning for bean definitions
* in the given packages and automatically refreshing the context.
* @param basePackages the packages to check for annotated classes
*/
//该构造函数会自动扫描以给定的包及其子包下的所有类,并自动识别所有的Spring Bean,将其注册到容器中
public AnnotationConfigApplicationContext(String... basePackages) {
this();
//我们自己模拟写过
scan(basePackages);
refresh();
}
/**
* {@inheritDoc}
* <p>Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader}
* and {@link ClassPathBeanDefinitionScanner} members.
*/
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
/**
* Provide a custom {@link BeanNameGenerator} for use with {@link AnnotatedBeanDefinitionReader}
* and/or {@link ClassPathBeanDefinitionScanner}, if any.
* <p>Default is {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
* @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
* @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
*/
//为容器的注解Bean读取器和注解Bean扫描器设置Bean名称产生器
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
/**
* Set the {@link ScopeMetadataResolver} to use for detected bean classes.
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
* <p>Any call to this method must occur prior to calls to {@link #register(Class...)}
* and/or {@link #scan(String...)}.
*/
//为容器的注解Bean读取器和注解Bean扫描器设置作用范围元信息解析器
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
//---------------------------------------------------------------------
// Implementation of AnnotationConfigRegistry
//---------------------------------------------------------------------
/**
* Register one or more annotated classes to be processed.
* <p>Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
* @see #scan(String...)
* @see #refresh()
*/
//为容器注册一个要被处理的注解Bean,新注册的Bean,必须手动调用容器的
//refresh()方法刷新容器,触发容器对新注册的Bean的处理
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
/**
* Perform a scan within the specified base packages.
* <p>Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param basePackages the packages to check for annotated classes
* @see #register(Class...)
* @see #refresh()
*/
//扫描指定包路径及其子包下的注解类,为了使新添加的类被处理,必须手动调用
//refresh()方法刷新容器
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
.....
}
通过上面的源码分析,我们可以看到Spring对注解的处理方式分为两种:
1.直接将注解Bean注册到容器中。
可以在初始化容器时候注册,也可以在容器创建之后手动调用注册方法想容器注册,然后通过手动刷新容器,使得容器对注册的bean进行处理。
2.通过扫描指定的包及其子包下的所有类。
在初始化注解容器时候指定要扫描的路径,如果容器创建以后给定路径动态添加了注解Bean,则需要手动调用容器扫描方法,然后手动刷新容器,使得容器对所注册的Bean进行处理。接下来看看是怎么处理的。
2.读取Annotation元数据
当创建注解处理器时,如果传入的初始参数是具体的注册Bean定义类时,注解容器读取并注册。
1.AnnotationConfigApplicationContext通过调用注解Bean定义读取器
AnnotatedBeanDefinitionReader的register()方法向容器注册指定的注解Bean,注解Bean定义读取器向容器注册Bean的源码如下:
//注册多个注解Bean定义类
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param annotatedClass the class of the bean
*/
//注册一个注解Bean定义类
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, using the given supplier for obtaining a new
* instance (possibly declared as a lambda expression or method reference).
* @param annotatedClass the class of the bean
* @param instanceSupplier a callback for creating an instance of the bean
* (may be {@code null})
* @since 5.0
*/
public <T> void registerBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier) {
doRegisterBean(annotatedClass, instanceSupplier, null, null);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations, using the given supplier for obtaining a new
* instance (possibly declared as a lambda expression or method reference).
* @param annotatedClass the class of the bean
* @param name an explicit name for the bean
* @param instanceSupplier a callback for creating an instance of the bean
* (may be {@code null})
* @since 5.0
*/
public <T> void registerBean(Class<T> annotatedClass, String name, @Nullable Supplier<T> instanceSupplier) {
doRegisterBean(annotatedClass, instanceSupplier, name, null);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param annotatedClass the class of the bean
* @param qualifiers specific qualifier annotations to consider,
* in addition to qualifiers at the bean class level
*/
//Bean定义读取器注册注解Bean定义的入口方法
@SuppressWarnings("unchecked")
public void registerBean(Class<?> annotatedClass, Class<? extends Annotation>... qualifiers) {
doRegisterBean(annotatedClass, null, null, qualifiers);
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param annotatedClass the class of the bean
* @param name an explicit name for the bean
* @param qualifiers specific qualifier annotations to consider,
* in addition to qualifiers at the bean class level
*/
//Bean定义读取器向容器注册注解Bean定义类
@SuppressWarnings("unchecked")
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
doRegisterBean(annotatedClass, null, name, qualifiers);
}
//Bean定义读取器向容器注册注解Bean定义类
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
//根据指定的注解Bean定义类,创建Spring容器中对注解Bean的封装的数据结构
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(instanceSupplier);
//========第一步===========================
//解析注解Bean定义的作用域,若@Scope("prototype"),则Bean为原型类型;
//若@Scope("singleton"),则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);
}
//如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一
//个autowiring自动依赖注入装配限定符,该Bean在进autowiring
//自动依赖注入装配时,根据名称装配限定符指定的Bean
else {
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);
}
从上面的源码我们可以看出,注册注解Bean定义类的基本步骤:
1.需要使用注解元数据解析器解析注解Bean中关于作用域的配置。
2.使用AnnotationConfigUtils的processCommonDefinitionAnnotations()
方法处理注解Bean定义类中通用的注解。
3.使用AnnotationConfigUilts的applyScopedProxyMode()
方法创建对于作用域的代理对象。
4.通过BeanDefinitionReaderUtils向容器注册Bean。
下面详细分析这四步
1.AnnotationScopeMetadatResolver解析作用域元数据。
AnnotationScopeMetadatResolver通过resolveScopeMetadata(BeanDefinition definition);
方法解析注解Bean定义的作用域元数据,即判断注册的Bean是原型(prototype)还是单例(singleton)类型,其源码如下:
//解析注解Bean定义类中的作用域元信息
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
//从注解Bean定义类的属性中查找属性为”Scope”的值,即@Scope注解的值
//AnnotationConfigUtils.attributesFor()方法将Bean
//中所有的注解和注解的值存放在一个map集合中
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
//将获取到的@Scope注解的值设置到要返回的对象中
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
//获取@Scope注解中的proxyMode属性值,在创建代理对象时会用到
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
//如果@Scope的proxyMode属性为DEFAULT或者NO
if (proxyMode == ScopedProxyMode.DEFAULT) {
//设置proxyMode为NO
proxyMode = this.defaultProxyMode;
}
//为返回的元数据设置proxyMode
metadata.setScopedProxyMode(proxyMode);
}
}
//返回解析的作用域元信息对象
return metadata;
}
2.AnnotationConfigUtils处理注解Bean定义类中的通用注解
AnnotatiionConfigUtils类中的processCommonDefinitionAnnotations()
方法在向容器注册Bean之前,首先对注解Bean定义类中的通用Spring注解进行处理,源码如下:
//处理Bean定义中通用注解
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
//如果Bean定义中有@Lazy注解,则将该Bean预实例化属性设置为@lazy注解的值
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
//如果Bean定义中有@Primary注解,则为该Bean设置为autowiring自动依赖注入装配的首选对象
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
//如果Bean定义中有@ DependsOn注解,则为该Bean设置所依赖的Bean名称,
//容器将确保在实例化该Bean之前首先实例化所依赖的Bean
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
if (abd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
absBd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
absBd.setDescription(description.getString("value"));
}
}
}
3.AnnotationConfigUtils根据注解Bean定义类中配置的作用域为其应用相应的代理策略。
AnnotationConfigUtils类的applyScopedProxyMode()方法根据注解Bean定义类中配置的作用域@Scope注解的值,为Bean定义应用相应的代理模式,主要是在Spring面向切面变成AOP中使用
//根据作用域为Bean应用引用的代码模式
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
//获取注解Bean定义类中@Scope注解的proxyMode属性值
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
//如果配置的@Scope注解的proxyMode属性值为NO,则不应用代理模式
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
//获取配置的@Scope注解的proxyMode属性值,如果为TARGET_CLASS
//则返回true,如果为INTERFACES,则返回false
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
//为注册的Bean创建相应模式的代理对象
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
4.BeanDefinitionReaderUtils向容器注册Bean。
BeanDefinitionReaderUtils主要是校验BeanDefinition信息,然后将Bean添加到容器中一个管理BeanDefinition的HashMap中。
3.扫描指定包并解析为BeanDefinition
当创建注解处理器时候,如果传入的初始参数是注解Bean定义类所在的包时,注解容器讲扫描给定的包及其子包,将扫描的注解Bean定义载入并注册。
1.ClassPathBeanDefinitionScanner扫描给定的包及其子。AnnotationConfigApplicationContext通过调用类路径Bean定义扫描器ClassPathBeanDefinitionScanner扫描给定包及其子包下的所有类,源码如下:
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
private final BeanDefinitionRegistry registry;
private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
@Nullable
private String[] autowireCandidatePatterns;
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private boolean includeAnnotationConfig = true;
/**
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory.
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry}
*/
//创建一个类路径Bean定义扫描器
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
/**
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory.
* <p>If the passed-in bean factory does not only implement the
* {@code BeanDefinitionRegistry} interface but also the {@code ResourceLoader}
* interface, it will be used as default {@code ResourceLoader} as well. This will
* usually be the case for {@link org.springframework.context.ApplicationContext}
* implementations.
* <p>If given a plain {@code BeanDefinitionRegistry}, the default {@code ResourceLoader}
* will be a {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
* <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its
* environment will be used by this reader. Otherwise, the reader will initialize and
* use a {@link org.springframework.core.env.StandardEnvironment}. All
* {@code ApplicationContext} implementations are {@code EnvironmentCapable}, while
* normal {@code BeanFactory} implementations are not.
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry}
* @param useDefaultFilters whether to include the default filters for the
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* @see #setResourceLoader
* @see #setEnvironment
*/
//为容器创建一个类路径Bean定义扫描器,并指定是否使用默认的扫描过滤规则。
//即Spring默认扫描配置:@Component、@Repository、@Service、@Controller
//注解的Bean,同时也支持JavaEE6的@ManagedBean和JSR-330的@Named注解
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
/**
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
* using the given {@link Environment} when evaluating bean definition profile metadata.
* <p>If the passed-in bean factory does not only implement the {@code
* BeanDefinitionRegistry} interface but also the {@link ResourceLoader} interface, it
* will be used as default {@code ResourceLoader} as well. This will usually be the
* case for {@link org.springframework.context.ApplicationContext} implementations.
* <p>If given a plain {@code BeanDefinitionRegistry}, the default {@code ResourceLoader}
* will be a {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry}
* @param useDefaultFilters whether to include the default filters for the
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* @param environment the Spring {@link Environment} to use when evaluating bean
* definition profile metadata
* @since 3.1
* @see #setResourceLoader
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
/**
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
* using the given {@link Environment} when evaluating bean definition profile metadata.
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry}
* @param useDefaultFilters whether to include the default filters for the
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* @param environment the Spring {@link Environment} to use when evaluating bean
* definition profile metadata
* @param resourceLoader the {@link ResourceLoader} to use
* @since 4.3.6
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//为容器设置加载Bean定义的注册器
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
//为容器设置资源加载器
setResourceLoader(resourceLoader);
}
/**
* Return the BeanDefinitionRegistry that this scanner operates on.
*/
@Override
public final BeanDefinitionRegistry getRegistry() {
return this.registry;
}
/**
* Set the defaults to use for detected beans.
* @see BeanDefinitionDefaults
*/
public void setBeanDefinitionDefaults(@Nullable BeanDefinitionDefaults beanDefinitionDefaults) {
this.beanDefinitionDefaults =
(beanDefinitionDefaults != null ? beanDefinitionDefaults : new BeanDefinitionDefaults());
}
/**
* Return the defaults to use for detected beans (never {@code null}).
* @since 4.1
*/
public BeanDefinitionDefaults getBeanDefinitionDefaults() {
return this.beanDefinitionDefaults;
}
/**
* Set the name-matching patterns for determining autowire candidates.
* @param autowireCandidatePatterns the patterns to match against
*/
public void setAutowireCandidatePatterns(@Nullable String... autowireCandidatePatterns) {
this.autowireCandidatePatterns = autowireCandidatePatterns;
}
/**
* Set the BeanNameGenerator to use for detected bean classes.
* <p>Default is a {@link AnnotationBeanNameGenerator}.
*/
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator());
}
/**
* Set the ScopeMetadataResolver to use for detected bean classes.
* Note that this will override any custom "scopedProxyMode" setting.
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
* @see #setScopedProxyMode
*/
public void setScopeMetadataResolver(@Nullable ScopeMetadataResolver scopeMetadataResolver) {
this.scopeMetadataResolver =
(scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
}
/**
* Specify the proxy behavior for non-singleton scoped beans.
* Note that this will override any custom "scopeMetadataResolver" setting.
* <p>The default is {@link ScopedProxyMode#NO}.
* @see #setScopeMetadataResolver
*/
public void setScopedProxyMode(ScopedProxyMode scopedProxyMode) {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(scopedProxyMode);
}
/**
* Specify whether to register annotation config post-processors.
* <p>The default is to register the post-processors. Turn this off
* to be able to ignore the annotations or to process them differently.
*/
public void setIncludeAnnotationConfig(boolean includeAnnotationConfig) {
this.includeAnnotationConfig = includeAnnotationConfig;
}
/**
* Perform a scan within the specified base packages.
* @param basePackages the packages to check for annotated classes
* @return number of beans registered
*/
//调用类路径Bean定义扫描器入口方法
public int scan(String... basePackages) {
//获取容器中已经注册的Bean个数
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//启动扫描器扫描给定包
doScan(basePackages);
// Register annotation config processors, if necessary.
//注册注解配置(Annotation config)处理器
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//返回注册的Bean个数
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
/**
* Perform a scan within the specified base packages,
* returning the registered bean definitions.
* <p>This method does <i>not</i> register an annotation config processor
* but rather leaves this up to the caller.
* @param basePackages the packages to check for annotated classes
* @return set of beans registered if any for tooling registration purposes (never {@code null})
*/
//类路径Bean定义扫描器扫描给定包及其子包
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
//创建一个集合,存放扫描到Bean定义的封装类
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
//遍历扫描所有给定的包
for (String basePackage : basePackages) {
//调用父类ClassPathScanningCandidateComponentProvider的方法
//扫描给定类路径,获取符合条件的Bean定义
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//遍历扫描到的Bean
for (BeanDefinition candidate : candidates) {
//获取Bean定义类中@Scope注解的值,即获取Bean的作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//为Bean设置注解配置的作用域
candidate.setScope(scopeMetadata.getScopeName());
//为Bean生成名称
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中通用的注解,在分析注解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);
//向容器注册扫描到的Bean
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
.....
}
2.ClassPathScanningCandidateComponentProvider扫描给定包及其子包的类:
ClassPathScanningCandidateComponentProvider类的findCandidateComponents()方法具体实现扫描给定类路径包的功能,源码如下:
public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
protected final Log logger = LogFactory.getLog(getClass());
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
//保存过滤规则要包含的注解,即Spring默认的@Component、@Repository、@Service、
//@Controller注解的Bean,以及JavaEE6的@ManagedBean和JSR-330的@Named注解
private final List<TypeFilter> includeFilters = new LinkedList<>();
//保存过滤规则要排除的注解
private final List<TypeFilter> excludeFilters = new LinkedList<>();
@Nullable
private Environment environment;
@Nullable
private ConditionEvaluator conditionEvaluator;
@Nullable
private ResourcePatternResolver resourcePatternResolver;
@Nullable
private MetadataReaderFactory metadataReaderFactory;
@Nullable
private CandidateComponentsIndex componentsIndex;
/**
* Protected constructor for flexible subclass initialization.
* @since 4.3.6
*/
protected ClassPathScanningCandidateComponentProvider() {
}
/**
* Create a ClassPathScanningCandidateComponentProvider with a {@link StandardEnvironment}.
* @param useDefaultFilters whether to register the default filters for the
* {@link Component @Component}, {@link Repository @Repository},
* {@link Service @Service}, and {@link Controller @Controller}
* stereotype annotations
* @see #registerDefaultFilters()
*/
//构造方法,该方法在子类ClassPathBeanDefinitionScanner的构造方法中被调用
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) {
this(useDefaultFilters, new StandardEnvironment());
}
/**
* Create a ClassPathScanningCandidateComponentProvider with the given {@link Environment}.
* @param useDefaultFilters whether to register the default filters for the
* {@link Component @Component}, {@link Repository @Repository},
* {@link Service @Service}, and {@link Controller @Controller}
* stereotype annotations
* @param environment the Environment to use
* @see #registerDefaultFilters()
*/
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
//如果使用Spring默认的过滤规则,则向容器注册过滤规则
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(null);
}
/**
* Set the resource pattern to use when scanning the classpath.
* This value will be appended to each base package name.
* @see #findCandidateComponents(String)
* @see #DEFAULT_RESOURCE_PATTERN
*/
public void setResourcePattern(String resourcePattern) {
Assert.notNull(resourcePattern, "'resourcePattern' must not be null");
this.resourcePattern = resourcePattern;
}
/**
* Add an include type filter to the <i>end</i> of the inclusion list.
*/
public void addIncludeFilter(TypeFilter includeFilter) {
this.includeFilters.add(includeFilter);
}
/**
* Add an exclude type filter to the <i>front</i> of the exclusion list.
*/
public void addExcludeFilter(TypeFilter excludeFilter) {
this.excludeFilters.add(0, excludeFilter);
}
/**
* Reset the configured type filters.
* @param useDefaultFilters whether to re-register the default filters for
* the {@link Component @Component}, {@link Repository @Repository},
* {@link Service @Service}, and {@link Controller @Controller}
* stereotype annotations
* @see #registerDefaultFilters()
*/
public void resetFilters(boolean useDefaultFilters) {
this.includeFilters.clear();
this.excludeFilters.clear();
if (useDefaultFilters) {
registerDefaultFilters();
}
}
/**
* Register the default filter for {@link Component @Component}.
* <p>This will implicitly register all annotations that have the
* {@link Component @Component} meta-annotation including the
* {@link Repository @Repository}, {@link Service @Service}, and
* {@link Controller @Controller} stereotype annotations.
* <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
* JSR-330's {@link javax.inject.Named} annotations, if available.
*
*/
//向容器注册过滤规则
@SuppressWarnings("unchecked")
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.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 {
//向要包含的过滤规则添加@Named注解
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.
}
}
/**
* Set the Environment to use when resolving placeholders and evaluating
* {@link Conditional @Conditional}-annotated component classes.
* <p>The default is a {@link StandardEnvironment}.
* @param environment the Environment to use
*/
public void setEnvironment(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
this.environment = environment;
this.conditionEvaluator = null;
}
@Override
public final Environment getEnvironment() {
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
return this.environment;
}
/**
* Return the {@link BeanDefinitionRegistry} used by this scanner, if any.
*/
@Nullable
protected BeanDefinitionRegistry getRegistry() {
return null;
}
/**
* Set the {@link ResourceLoader} to use for resource locations.
* This will typically be a {@link ResourcePatternResolver} implementation.
* <p>Default is a {@code PathMatchingResourcePatternResolver}, also capable of
* resource pattern resolving through the {@code ResourcePatternResolver} interface.
* @see org.springframework.core.io.support.ResourcePatternResolver
* @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
*/
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}
/**
* Return the ResourceLoader that this component provider uses.
*/
public final ResourceLoader getResourceLoader() {
return getResourcePatternResolver();
}
private ResourcePatternResolver getResourcePatternResolver() {
if (this.resourcePatternResolver == null) {
this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
}
return this.resourcePatternResolver;
}
/**
* Set the {@link MetadataReaderFactory} to use.
* <p>Default is a {@link CachingMetadataReaderFactory} for the specified
* {@linkplain #setResourceLoader resource loader}.
* <p>Call this setter method <i>after</i> {@link #setResourceLoader} in order
* for the given MetadataReaderFactory to override the default factory.
*/
public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
this.metadataReaderFactory = metadataReaderFactory;
}
/**
* Return the MetadataReaderFactory used by this component provider.
*/
public final MetadataReaderFactory getMetadataReaderFactory() {
if (this.metadataReaderFactory == null) {
this.metadataReaderFactory = new CachingMetadataReaderFactory();
}
return this.metadataReaderFactory;
}
/**
* Scan the class path for candidate components.
* @param basePackage the package to check for annotated classes
* @return a corresponding Set of autodetected bean definitions
*/
//扫描给定类路径的包
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
/**
* Determine if the index can be used by this instance.
* @return {@code true} if the index is available and the configuration of this
* instance is supported by it, {@code false} otherwise
* @since 5.0
*/
private boolean indexSupportsIncludeFilters() {
for (TypeFilter includeFilter : this.includeFilters) {
if (!indexSupportsIncludeFilter(includeFilter)) {
return false;
}
}
return true;
}
/**
* Determine if the specified include {@link TypeFilter} is supported by the index.
* @param filter the filter to check
* @return whether the index supports this include filter
* @since 5.0
* @see #extractStereotype(TypeFilter)
*/
private boolean indexSupportsIncludeFilter(TypeFilter filter) {
if (filter instanceof AnnotationTypeFilter) {
Class<? extends Annotation> annotation = ((AnnotationTypeFilter) filter).getAnnotationType();
return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) ||
annotation.getName().startsWith("javax."));
}
if (filter instanceof AssignableTypeFilter) {
Class<?> target = ((AssignableTypeFilter) filter).getTargetType();
return AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, target);
}
return false;
}
/**
* Extract the stereotype to use for the specified compatible filter.
* @param filter the filter to handle
* @return the stereotype in the index matching this filter
* @since 5.0
* @see #indexSupportsIncludeFilter(TypeFilter)
*/
@Nullable
private String extractStereotype(TypeFilter filter) {
if (filter instanceof AnnotationTypeFilter) {
return ((AnnotationTypeFilter) filter).getAnnotationType().getName();
}
if (filter instanceof AssignableTypeFilter) {
return ((AssignableTypeFilter) filter).getTargetType().getName();
}
return null;
}
private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
//创建存储扫描到的类的集合
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
Set<String> types = new HashSet<>();
for (TypeFilter filter : this.includeFilters) {
String stereotype = extractStereotype(filter);
if (stereotype == null) {
throw new IllegalArgumentException("Failed to extract stereotype from "+ filter);
}
types.addAll(index.getCandidateTypes(basePackage, stereotype));
}
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (String type : types) {
//为指定资源获取元数据读取器,元信息读取器通过汇编(ASM)读//取资源元信息
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
//如果扫描到的类符合容器配置的过滤规则
if (isCandidateComponent(metadataReader)) {
//通过汇编(ASM)读取资源字节码中的Bean定义元信息
AnnotatedGenericBeanDefinition sbd = new AnnotatedGenericBeanDefinition(
metadataReader.getAnnotationMetadata());
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Using candidate component class from index: " + type);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + type);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because matching an exclude filter: " + type);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
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 {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
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;
}
/**
* Resolve the specified base package into a pattern specification for
* the package search path.
* <p>The default implementation resolves placeholders against system properties,
* and converts a "."-based package path to a "/"-based resource path.
* @param basePackage the base package as specified by the user
* @return the pattern specification to be used for package searching
*/
protected String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));
}
/**
* Determine whether the given class does not match any exclude filter
* and does match at least one include filter.
* @param metadataReader the ASM ClassReader for the class
* @return whether the class qualifies as a candidate component
*/
//判断元信息读取器读取的类是否符合容器定义的注解过滤规则
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//如果读取的类的注解在排除注解过滤规则中,返回false
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
//如果读取的类的注解在包含的注解的过滤规则中,则返回ture
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
//如果读取的类的注解既不在排除规则,也不在包含规则中,则返回false
return false;
}
/**
* Determine whether the given class is a candidate component based on any
* {@code @Conditional} annotations.
* @param metadataReader the ASM ClassReader for the class
* @return whether the class qualifies as a candidate component
*/
private boolean isConditionMatch(MetadataReader metadataReader) {
if (this.conditionEvaluator == null) {
this.conditionEvaluator =
new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
}
return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}
/**
* Determine whether the given bean definition qualifies as candidate.
* <p>The default implementation checks whether the class is not an interface
* and not dependent on an enclosing class.
* <p>Can be overridden in subclasses.
* @param beanDefinition the bean definition to check
* @return whether the bean definition qualifies as a candidate component
*/
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
/**
* Clear the local metadata cache, if any, removing all cached class metadata.
*/
public void clearCache() {
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
}
4.注册注解BeanDefinition
AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的Web版本,他们对于注解Bean的注册和扫描是基本相同的,但是AnnotationConfigApplicationContext对注解Bean的定义的载入稍有不同,AnnotationConfigApplicationContext注入注解Bean的定义如下:
//载入注解Bean定义资源
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
//为容器设置注解Bean定义读取器
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
//为容器设置类路径Bean定义扫描器
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
//获取容器的Bean名称生成器
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
//为注解Bean定义读取器和类路径扫描器设置Bean名称生成器
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
//获取容器的作用域元信息解析器
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
//为注解Bean定义读取器和类路径扫描器设置作用域元信息解析器
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.annotatedClasses.isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info("Registering annotated classes: [" +
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
}
reader.register(this.annotatedClasses.toArray(new Class<?>[this.annotatedClasses.size()]));
}
if (!this.basePackages.isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
scanner.scan(this.basePackages.toArray(new String[this.basePackages.size()]));
}
//获取容器定义的Bean定义资源路径
String[] configLocations = getConfigLocations();
//如果定位的Bean定义资源路径不为空
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
//使用当前容器的类加载器加载定位路径的字节码类文件
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
if (logger.isInfoEnabled()) {
logger.info("Successfully resolved class for [" + configLocation + "]");
}
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not load class for config location [" + configLocation +
"] - trying package scan. " + ex);
}
//如果容器类加载器加载定义路径的Bean定义资源失败
//则启用容器类路径扫描器扫描给定路径包及其子包中的类
int count = scanner.scan(configLocation);
if (logger.isInfoEnabled()) {
if (count == 0) {
logger.info("No annotated classes found for specified class/package [" + configLocation + "]");
}
else {
logger.info("Found " + count + " annotated classes in package [" + configLocation + "]");
}
}
}
}
}
}
IOC容器初始化小结
1.初始化的入口在容器中的refresh()
方法调用来完成。
2.对Bean定义载入IOC容器的方法是loadBeanDefinition(),大致流程就是:通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoade的实现,可以从类路径,文件系统,URL等方式来定资源位置。如果是XmlBeanFactory作为IOC容器,那么需要为他指定Bean定义的资源,也就是说Bean定义文件时通过抽象成Resource来被IOC容器处理的,容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是XmlBeanDefinition来解析Bean的XML文件-实际的处理过程是委托给BeanDefinitionParserDelegate来完成,从而得到bean的定义信息。这些信息在Spring中使用BeanDefinition对象的来表示-这个名字可以让我们想到loadBeanDefinition(),registerBeanDefinition() 这些相关的方法。他们都是为了处理BeanDefinition服务的。容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这些由IOC实现BeanDefinitionRegister接口来实现。注册过程就是在IOC容器内部维护一个HashMap来保存得到BeanDefinition的过程。以后d对Bean围绕这个HashMap来实现。
以下是容器初始化全过程的时序图:
一步一步手绘Spring IoC运行时序图.jpg
网友评论