ClassPathBeanDefinitionScanner继承自ClassPathScanningCandidateComponentProvider,构造时要求指定一个BeanDefinitionRegistry对象,其扩展了一个scan方法,可以同时指定多个要扫描的包。底层在扫描bean定义时还是使用的父类的findCandidateComponents方法,但是扫描后会自动利用持有的BeanDefinitionRegistry自动对bean定义进行注册。注册bean定义的bean名称会使用持有的BeanNameGenerator生成,默认是AnnotationBeanNameGenerator;如果对应的bean定义是AnnotatedBeanDefinition类型的,还会处理对应的一些注解定义。而使用ClassPathScanningCandidateComponentProvider时我们只能获取到对应的bean定义,另外的bean注册等还需要我们来做。
ClassPathBeanDefinitionScanner的核心代码如下:
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);
}
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
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;
}
假设现有HelloOne和HelloTwo两个类,分别位于包com.elim.learn.spring.bean.registry.one和com.elim.learn.spring.bean.registry.two下,它们类上都标注了HelloAnnotation注解,如果现在需要只扫描包com.elim.learn.spring.bean.registry.one和com.elim.learn.spring.bean.registry.two下类上拥有HelloAnnotation注解的类作为bean,则可以定义如下BeanDefinitionRegistryPostProcessor进行bean扫描。
public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
TypeFilter includeFilter = new AnnotationTypeFilter(HelloAnnotation.class);
scanner.addIncludeFilter(includeFilter);
String[] basePackages = {"com.elim.learn.spring.bean.registry.one", "com.elim.learn.spring.bean.registry.two"};
scanner.scan(basePackages);
}
}
测试代码如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={CustomBeanDefinitionRegistry.class})
public class CustomBeanDefinitionRegistryTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void assertBean() {
Assert.assertNotNull(this.applicationContext.getBean(HelloOne.class));
Assert.assertNotNull(this.applicationContext.getBean(HelloTwo.class));
}
}
关于ClassPathBeanDefinitionScanner的更多信息请参考相应的API文档或源码。
(本文由Elim写于2017年9月29日)
相关推荐
SpringCloud——分布式配置中心(Spring Cloud Config)之高可用的分布式配置中心
SpringCloud——消息总线(Bus)之Spring Cloud Bus将分布式系统的节点与轻量级消息代理链接。
SpringCloud——断路器(Hystrix)之Ribbon使用断路器和Feign使用断路器
SpringCloud——分布式跟踪(Sleuth)之Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案。
Spring boot——@DeclareParents例子...
SpringCloud——服务注册(consul)之Consul通过HTTP API和DNS提供服务发现服务。
Spring系列——MVC框架整合.md
SpringCloud——路由器和过滤器(Zuul)之微服务网关的实现
关于Spring方面的常见面试题
MyBatis与Spring整合——通过官方文档进行最简单的整合
Spring总结——田超凡【原创田超凡,已申请版权,禁止随意转发,侵权仿冒必究】
所有Spring——jar详细介绍 所有Spring——jar详细介绍 所有Spring——jar详细介绍
Zookeeper作为注册中心搭建SpringCloud实现服务注册及发现
我们从一个简单的容器开始,一步步的重构,最后实现一个基本的Spring框架的雏形,为了帮助我们更加深入的理解Spring的IoC...【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)
NULL 博文链接:https://ylxy3058.iteye.com/blog/2225314
SpringCloud-Eureka实现服务的注册与发现,创建服务注册中心(eureka-server)和服务提供者 (eureka-client)
SpringCloud —— Eureka 集群 SpringCloud —— 服务注册进 Eureka 集群 SpringCloud —— Eureka 自我保护 SpringCloud —— SpringCloud Consul 实现服务注册中心 SpringCloud —— 三个注册中心的异同点 ...
刘冬编写Spring.NET学习笔记25——整合Quartz.NET例子。 原文: http://www.cnblogs.com/GoodHelper/archive/2009/11/20/SpringNet_QuartzNet.html
NULL 博文链接:https://snowolf.iteye.com/blog/236264