发布时间:2023-10-15 12:30
@Controller、@Service、@Repository的本质是@Component
注解
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(“XX.xx.xx”);
context.getBean();
沿着AnnotationConfigApplicationContext的构造方法,看下Spring在源码层面又是如何处理标注了注解@Component的类:
public AnnotationConfigApplicationContext(String... basePackages) {
this();
//扫描指定的bean
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);
}
//看看AnnotatedBeanDefinitionReader 主要做什么的
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\");
//初始化registry
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//注册一些和注解相关的后置处理器BeanDefinition
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() {
//注册Component类型的注解过滤器
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
//注册javax.annotation.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 {
//注册avax.inject.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.
}
}
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);
// Register annotation config processors, if necessary.
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) {
//在包路径下,加载符合条件的beanDefinitions
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//获取beanDefinitions的 注解@Scope的元数据信息
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//设置beanDefinitions的作用域为单例
candidate.setScope(scopeMetadata.getScopeName());
//生成bean的名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//为beanDefinitions注册一些默认的属性值
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//为其他各种注解上的信息,设置在beanDefinitions
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//判断当前的candiate,和容器中已经注册的beanDefinitions是否兼容
if (checkCandidate(beanName, candidate)) {
//将beanDefinitions和beanName封装到BeanDefinitionHolder
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//注册BeanDefinitionHolder在spring容器中
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 {
//将resource封装到MetadataReader中,MetadataReader为资源Resource访问组件
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//判断当前的Resouce是否符合条件
if (isCandidateComponent(metadataReader)) {
//metadataReader封装到ScannedGenericBeanDefinition 类型的BeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
//判断ScannedGenericBeanDefinition当前的属否符合条件
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;
}