# Spring scan
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-Spring](https://github.com/SourceHot/spring-framework-read)
## 解析
- Spring 注解形式使用有下面两种方式
1. 通过`AnnotationConfigApplicationContext`参数:扫描包
2. 通过xml配置`context:component-scan`属性`base-package`
```java
AnnotationConfigApplicationContext aac =
new AnnotationConfigApplicationContext("com.huifer.source.spring.ann");
```
```xml
```
- 目标明确开始找入口方法
- `AnnotationConfigApplicationContext`直接点进去看就找到了
```java
public AnnotationConfigApplicationContext(String... basePackages) {
this();
// 扫描包
scan(basePackages);
refresh();
}
```
- `context:component-scan`寻找方式:冒号`:`钱+NamespaceHandler 或者全文搜索`component-scan`,最终找到`org.springframework.context.config.ContextNamespaceHandler`
```java
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
```
### org.springframework.context.annotation.ComponentScanBeanDefinitionParser
![image-20200115093602651](../../../images/spring/image-20200115093602651.png)
- 实现`BeanDefinitionParser`直接看`parse`方法
```java
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 获取 base-package 属性值
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
// 处理 ${}
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
// 分隔符`,;\t\n`切分
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
// 扫描对象创建
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
// 执行扫描方法
Set beanDefinitions = scanner.doScan(basePackages);
// 注册组件,触发监听
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
```
- 回过头看`AnnotationConfigApplicationContext`
### org.springframework.context.annotation.AnnotationConfigApplicationContext
```java
public AnnotationConfigApplicationContext(String... basePackages) {
this();
// 扫描包
scan(basePackages);
refresh();
}
```
```java
private final ClassPathBeanDefinitionScanner scanner;
@Override
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
```
- `org.springframework.context.annotation.ClassPathBeanDefinitionScanner.scan`
```java
public int scan(String... basePackages) {
// 获取bean数量
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);
}
```
- 这个地方`doScan`似曾相识,他就是`org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse`中的`doScan`,下一步解析doScan
### org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan
```java
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 寻找组件
Set candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// bean 作用域设置
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
// 设置生命周期
candidate.setScope(scopeMetadata.getScopeName());
// 创建beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
// 设置默认属性 具体方法:org.springframework.beans.factory.support.AbstractBeanDefinition.applyDefaults
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 读取Lazy,Primary 等注解
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// bean的重复检查
if (checkCandidate(beanName, candidate)) {
// 创建 BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 代理对象的处理
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 放入list中,最后返回用
beanDefinitions.add(definitionHolder);
// 注册bean
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
```
#### org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents
```java
public Set findCandidateComponents(String basePackage) {
// 扫描
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
```
```java
/**
* 扫描当前包路径下的资源
* @param basePackage
* @return
*/
private Set scanCandidateComponents(String basePackage) {
Set candidates = new LinkedHashSet<>();
try {
// 字符串拼接出一个编译后的路径 classpath://
// 这里替换了通配符
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 metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 判断是否是 Component
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;
}
```
#### org.springframework.context.annotation.ScopeMetadataResolver#resolveScopeMetadata
```java
/**
* 生命周期设置
*
* @param definition the target bean definition
* @return
*/
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
// 判断是否属于 AnnotatedBeanDefinition
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
// 获取 value 属性值并且设置
metadata.setScopeName(attributes.getString("value"));
// 获取 proxyMode 属性值并且设置
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
```
- `org.springframework.context.annotation.AnnotationScopeMetadataResolverTests#resolveScopeMetadataShouldReadScopedProxyModeFromAnnotation`测试用例
```java
@Test
public void resolveScopeMetadataShouldReadScopedProxyModeFromAnnotation() {
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithScopedProxy.class);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals("request", scopeMetadata.getScopeName());
assertEquals(TARGET_CLASS, scopeMetadata.getScopedProxyMode());
}
```
![image-20200115141708702](../../../images/spring/image-20200115141708702.png)
#### org.springframework.beans.factory.support.BeanNameGenerator#generateBeanName
- 创建beanName `org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName`
```java
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
// 如果存在bean(value="") value存在
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
// 创建beanName
return buildDefaultBeanName(definition, registry);
}
```
```java
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
AnnotationMetadata amd = annotatedDef.getMetadata();
Set types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) {
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null && isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
// 获取注解的value 属性值
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
// 判断是否存在值
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
// beanName = value属性值
beanName = strVal;
}
}
}
}
return beanName;
}
```
```java
@Service(value = "dhc")
public class DemoService {
}
```
![image-20200115143315633](../../../images/spring/image-20200115143315633.png)
- `org.springframework.context.annotation.AnnotationBeanNameGenerator#buildDefaultBeanName(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry)`
- `org.springframework.context.annotation.AnnotationBeanNameGenerator#buildDefaultBeanName(org.springframework.beans.factory.config.BeanDefinition)`
```JAVA
protected String buildDefaultBeanName(BeanDefinition definition) {
// 获取bean class name
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
// 获取短类名,
String shortClassName = ClassUtils.getShortName(beanClassName);
// 第一个字母小写
return Introspector.decapitalize(shortClassName);
}
```
```JAVA
@Configuration
public class BeanConfig {
@Scope(value =ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean(value = "hc")
public Ubean f() {
return new Ubean();
}
}
```
![image-20200115143456554](../../../images/spring/image-20200115143456554.png)
#### org.springframework.context.annotation.ClassPathBeanDefinitionScanner#postProcessBeanDefinition
- 这个方法没什么难点,直接是set方法
```java
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
```
```java
public void applyDefaults(BeanDefinitionDefaults defaults) {
setLazyInit(defaults.isLazyInit());
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
```
#### org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(org.springframework.beans.factory.annotation.AnnotatedBeanDefinition)
```java
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
```
```java
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
// 获取 lazy 注解
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"));
}
}
```
- 方法思路:
1. 获取注解的属性值
2. 设置注解属性
#### org.springframework.context.annotation.ClassPathBeanDefinitionScanner#checkCandidate
- 重复检查
```java
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
// 判断当前 beanName 是否在注册表中
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
// 从注册表中获取
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
// 当前的bean
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
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() + "]");
}
```
#### org.springframework.context.annotation.AnnotationConfigUtils#applyScopedProxyMode
```JAVA
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 创建代理对象
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
```