注解自动扫描原理分析
在spring的配置文件中加入如下代码,spring便开启了自动扫描,那么它的底层到底是如何实现的呢?
<context:component-scan base-package="com.wisely.highlight_spring4.ch1"/>
-
首先找到解析这个标签的地方,spring 中解析具体的标签都有相应的解析器,且都继承了NamespaceHandlerSupport
-
查看
ComponentScanBeanDefinitionParser
的parse
方法
-
真正的逻辑其实是在
ClassPathBeanDefinitionScanner
的doScan
方法中
-
测试一下扫描过程
package com.wisely.highlight_spring4.ch1.di;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
public class BeanFactoryTest
{
public static void main(String[] args) throws IOException, ClassNotFoundException {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
//这里特别注意一下类路径必须这样写
//获取指定包下的所有类
Resource[] resources = resourcePatternResolver.getResources("classpath*:com\\wisely\\highlight_spring4\\ch1\\di\\*");
MetadataReaderFactory metadata=new SimpleMetadataReaderFactory();
for(Resource resource:resources) {
System.out.println(resource);
MetadataReader metadataReader=metadata.getMetadataReader(resource);
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
candidates.add(sbd);
}
for(BeanDefinition beanDefinition : candidates) {
String classname=beanDefinition.getBeanClassName();
//扫描controller注解
Controller c=Class.forName(classname).getAnnotation(Controller.class);
//扫描Service注解
Service s=Class.forName(classname).getAnnotation(Service.class);
//扫描Component注解
Component component=Class.forName(classname).getAnnotation(Component.class);
if(c!=null ||s!=null ||component!=null){
System.out.println(classname);
}
}
}
}
-
我的项目包结构
-
控制台输出结果