前言
spring解析Bean通常通过 读取xml文件 和 扫码注解 两种方式进行。在 Spring源码解读(二)Bean创建过程之解析——BeanDefinition 中分析了通过读取xml文件解析得到BeanDefinnition,这篇博文再来分析扫描指定包路径下的注解解析Bean.
类的继承关系
扫描指定包下的注解标注的bean是由ClassPathBeanDefinitionScanner实现的。
程序入口
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.lsz.demo");
Object bean = ctx.getBean("");
使用AnnotationConfigApplicationContext,通过它的边长参数的构造方法, 传入要扫描的报名构建上下文对象。
默认情况下会为该上下文对象指定ClassPathBeanDefinitionScanner扫描器。
public AnnotationConfigApplicationContext(String... basePackages) {
/**
* 先调用无参构造方法
* this.reader = new AnnotatedBeanDefinitionReader(this);
* this.scanner = new ClassPathBeanDefinitionScanner(this);
* 无参构造方法内就是bean的读取器和扫描器
*/
this();
// 调用自己的scan方法,扫码所需的bean
scan(basePackages);
// 这里父类org.springframework.context.support.AbstractApplicationContext的方法
// 用于刷新整个spring上下文信息,是spring的核心内容
refresh();
}
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
创建ClassPathBeanDefinitionScanner
最终执行的构造方法:
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
// 注册默认的过滤器,调用父类ClasspathScanningCandidateComponentProvider的方法
registerDefaultFilters();
}
// 环境参数
setEnvironment(environment);
// 系统资源
setResourceLoader(resourceLoader);
}
由上面的继承关系可以得知ClassPathBeanDefinitionScanner间接实现了 EnvironmentCapable 和 ResourceLoaderAware ,从而能到拿到环境参数和系统资源加载器,很好理解,这里分析下父类的 registerDefaultFilters方法,主要主要就是添加需要扫描的过滤去,如我们这里加入的我们常见的@Component注解和javax.annotation.ManagedBean、javax.inject.Named,后面两个时非必须的。
/**
* 需要扫描的过滤器
*/
private final List<TypeFilter> includeFilters = new ArrayList<>();
/**
* 排除掉的过滤器
*/
private final List<TypeFilter> excludeFilters = new ArrayList<>();
protected void registerDefaultFilters() {
// 添加需要扫描的注解 @Component
// 因为 @Controller、@Service、@Repository 都被 @Component 注解标注,所以隐私的包含了这三个注解
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
// 添加需要扫描的注解 @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和注册注解配置Bean的处理器。
public int scan(String... basePackages) {
// 这就是bean注册表的大小,也就是BeanFactory中map的大小
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
// 执行扫描
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
// 注册注解配置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
不知大家有没有发现一个规律,spring源码中的执行其真是含义的代码都是以“do”开头的,比如getBean()方法中会调用doGetBean(),createBean方法中会调用doCreateBean,这里也是一样scan方法中调用doScan方法。有了这个规律,读剩下的源码的时候能更快的定位到核心位置。
执行扫描指定的包并注册
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
// 遍历变长参数,处理多个包下bean
for (String basePackage : basePackages) {
// 查找包路径下的bean,将其转换为BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 解析bean的scope属性
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
// 如果是AbstractBeanDefinition,给这个装饰类赋默认值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 如果是AnnotatedBeanDefinition(有注解的类)
// 把注解设置到装饰类中
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查beanName是否重复有冲突
if (checkCandidate(beanName, candidate)) {
// 构建BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 应用作用域代理模式
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册Bean
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
查找到包路径下的bean,并转换为BeanDifinition
这个方法内分为普通处理和对@Indexed的处理。对@Indexed的处理是spring5的新特性,目的是为了提升spring启动的性能。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
// 对 @Indexed 注册处理
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
// 普通逻辑处理
return scanCandidateComponents(basePackage);
}
}
普通处理 scanCandidateComponents
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 包搜索路径 classpath*:xxx.**.*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 将class文件转换为resource对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
// 遍历resource,将resource转换为ScannedGenericBeanDefinition
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
try {
// 读取resource的元数据,也就是class的信息
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 根据excludeFilters和includeFilters判断是否符合处理条件
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
// 判断是否可以被实例化, 确定给定的 bean 定义是否有资格作为候选。 排除接口类等等
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
// 添加到候选bean集合中
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 (FileNotFoundException ex) {
if (traceEnabled) {
logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
对@Indexed的处理 addCandidateComponentsFromIndex
关于对@Indexed的实现细节上,涉及到很多其他的东西,这里暂时不展开。
private Set<BeanDefinition> addCandidateComponentsFromIndex(CandidateComponentsIndex index, String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
Set<String> types = new HashSet<>();
// 遍历过滤器,找出满足条件的的bean
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) {
// 读取resource的元数据,也就是class的信息
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(type);
// 根据excludeFilters和includeFilters判断是否符合处理条件
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(metadataReader.getResource());
// 判断是否可以被实例化, 确定给定的 bean 定义是否有资格作为候选。 排除接口类等等
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Using candidate component class from index: " + type);
}
// 添加到候选bean集合中
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;
}
对AbstractBeanDefinition处理
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
// 填充默认值
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
if (this.autowireCandidatePatterns != null) {
// 如果设置了autowireCandidatePatterns自动装配候选模式,则按照其跪着设置bean的AutowireCandidate
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
对AnnotatedBeanDefinition处理
对通用的注解解析,然后填充到装饰类BeanDefinition中。
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
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"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
检查BeanName
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
// 注册表中不包含这个beanName 直接返回ture
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
// 当前这个beanName已经存在了,判断给定的新 BeanDefinition 是否与给定的现有BeanDefinition兼容。
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
对BeanDefinition代理模式处理
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
// 获取代理模式
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
/**
* ScopedProxyMode 存在四个类型
* DEFAULT、NO :不要创建范围代理
* INTERFACES:JDK动态代理
* TARGET_CLASS:CGLIB代理
*/
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
// 代理默认如果为NO, 不需要代理直接返回
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 为提供的目标 bean 生成一个作用域代理,使用内部名称注册目标 bean 并在作用域代理上设置“targetBeanName”。
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
将BeanDefinition注册到BeanFactroy的注册表
BeanDefinitionReaderUtils#registerBeanDefinition这个方法在 Spring源码解读(三)Bean创建过程之注册——DefaultListableBeanFactory 中已经分析过了。
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}