Spring-scan
This commit is contained in:
parent
2f9a3ce125
commit
181c959d49
534
docs/Spring/clazz/Spring-scan.md
Normal file
534
docs/Spring/clazz/Spring-scan.md
Normal file
@ -0,0 +1,534 @@
|
||||
# Spring scan
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [huifer-spring](https://github.com/huifer/spring-framework-read)
|
||||
|
||||
## 解析
|
||||
- Spring 注解形式使用有下面两种方式
|
||||
1. 通过`AnnotationConfigApplicationContext`参数:扫描包
|
||||
2. 通过xml配置`context:component-scan`属性`base-package`
|
||||
```java
|
||||
AnnotationConfigApplicationContext aac =
|
||||
new AnnotationConfigApplicationContext("com.huifer.source.spring.ann");
|
||||
```
|
||||
```xml
|
||||
<context:component-scan base-package="com.huifer.source.spring.ann">
|
||||
</context:component-scan>
|
||||
```
|
||||
|
||||
- 目标明确开始找入口方法
|
||||
- `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
|
||||
|
||||

|
||||
|
||||
- 实现`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<BeanDefinitionHolder> 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<BeanDefinitionHolder> doScan(String... basePackages) {
|
||||
Assert.notEmpty(basePackages, "At least one base package must be specified");
|
||||
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
|
||||
for (String basePackage : basePackages) {
|
||||
// 寻找组件
|
||||
Set<BeanDefinition> 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<BeanDefinition> findCandidateComponents(String basePackage) {
|
||||
// 扫描
|
||||
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
|
||||
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
|
||||
}
|
||||
else {
|
||||
return scanCandidateComponents(basePackage);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```java
|
||||
/**
|
||||
* 扫描当前包路径下的资源
|
||||
* @param basePackage
|
||||
* @return
|
||||
*/
|
||||
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
|
||||
Set<BeanDefinition> 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());
|
||||
}
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 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<String> 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 {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
- `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();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### 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);
|
||||
}
|
||||
|
||||
```
|
||||
|
BIN
images/spring/image-20200115093602651.png
Normal file
BIN
images/spring/image-20200115093602651.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
images/spring/image-20200115141708702.png
Normal file
BIN
images/spring/image-20200115141708702.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
images/spring/image-20200115143315633.png
Normal file
BIN
images/spring/image-20200115143315633.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
BIN
images/spring/image-20200115143456554.png
Normal file
BIN
images/spring/image-20200115143456554.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
Loading…
x
Reference in New Issue
Block a user