Spring注解源码解析:@Component
流程
@Controller、@Service、@Repository的本质是@Component
注解
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(“XX.xx.xx”);
context.getBean();
1.AnnotationConfigApplicationContext
沿着AnnotationConfigApplicationContext的构造方法,看下Spring在源码层面又是如何处理标注了注解@Component的类:
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
方法this()中,初始化了两个成员变量this.reader和this.scanner,既然在构造方法中这么刻意的初始化它们,很有可能这两个成员变量的初始化逻辑中
可以看到首先会初始化BeanDefinitionRegistry类型的成员变量registr
beanDefinitionRegistry接口是Spring容器底层实现的一个接口,封装了注册BeanDefinition以及其他关于BeanDefinition相关的操作。
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
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;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
AnnotationConfigUtils类中的方法registerAnnotationConfigProcessors
主要是注册一些类的BeanDefinition到Spring容器中 包括:
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
"org.springframework.context.annotation.internalCommonAnnotationProcessor";
"org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
"org.springframework.context.event.internalEventListenerProcessor";
"org.springframework.context.event.internalEventListenerFactory";
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
另外一个成员变量也就是this.scanner对应的ClassPathBeanDefinitionScanner的初始化:
设置环境变量组件environment及相应的资源加载器resourceLoader,最终我们还是看到了一些重要的逻辑,如方法registerDefaultFilters
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
? registerDefaultFilters();
在方法registerDefaultFilters中,我们发现主要就是往集合includeFilters中注册一些AnnotationTypeFilter,而通过AnnotationTypeFilter的名称,我们大概可以知道这是一个注解过滤器,是用来过滤指定类型的注解的。
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
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) {
}
try {
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) {
}
}
2.Scan();
Spring接下来会把扫描的任务委托给成员变量this.scanner处理,而this.scanner刚刚我们也看到了它的初始化,实际类型为ClassPathBeanDefinitionScanner。
@Override
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
首先通过成员变量this.registry的方法getBeanDefinitionCount,获取Spring容器当前已经注册BeanDefinition的个数。
然后在方法最后,用当前Spring容器中BeanDefinition的数量,减去初始Spring容器中BeanDefinition数量,得到本次方法执行时一共注册了多少个BeanDefinition。
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
doScan(basePackages);
方法doScan会遍历所有包路径,依次到这些包路径下扫描并加载BeanDefinition,
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) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
findCandidateComponents()
方法scanCandidateComponents果然开始扫描指定路径下的类了,首先会对我们传进去的包路径basePackage进行一些拼接处理,其中,ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX的值为“classpath*”,this.resourcePattern默认值为“**/*.class”。
再加上我们设置的basePackage值为“com.x x x.container.annotation.component”,所以,我们可以很容易的得到packageSearchPath的值为:classpath*:com.xxx.container.annotation.component/**/*.class,也就是扫描该路径下的所有类,每个类我们都可以得到相应的资源Resource。
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
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 (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
}
return candidates;
}
isCandidateComponent()
Spring是通过注解过滤器来过滤资源的,可以看到方法中会通过封装了注解过滤器的集合this.includeFilters,来过滤封装了Resource的MetadataReader。
因为this.includeFilter中添加了注解@Component的过滤器,所以,这里只会将标注了@Component注解的类给留下来,而成员变量this.excludeFilters很明显也是用来存放注解的过滤器,只不过它存放的注解过滤器,是用来剔除掉指定类型的注解过滤器的。
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
|