配置以及代碼如下
配置
<!-- 配置自動(dòng)掃描的包 -->
<context:component-scan base-package="com.test.controller">
</context:component-scan>
代碼
package com.test.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}
當(dāng)我們?cè)谂渲梦募信渲昧?lt;context:component-scan>,那么spring將自動(dòng)幫我們掃描指定包下的類(lèi)是否標(biāo)注了@Component,@Repository,@Service,@Controller這幾個(gè)注解,如果標(biāo)注了那么spring將自動(dòng)幫我們實(shí)例化。那么spring是如何做到的呢?下面來(lái)看源碼分析。
源碼分析
(1)前面講過(guò)[<context:annotation-config/>自動(dòng)掃描標(biāo)簽詳解],當(dāng)解析自定義的標(biāo)簽時(shí),就由BeanDefinitionParser接口的子類(lèi)來(lái)完成的。而NamespaceHandler <context:component-scan>的同樣是ContextNamespaceHandler 類(lèi)
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());
}
}
最終由ComponentScanBeanDefinitionParser來(lái)解析<context:component-scan>標(biāo)簽。
(2)看下ComponentScanBeanDefinitionParse的解析方法parse()
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//獲取要掃描的包名,也就是base-package元素對(duì)應(yīng)的值,我這里配置的是com.test.controller
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//這里進(jìn)行掃描
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
//注冊(cè)其他的BeanPostProcessor,這個(gè)放在最后講
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
從上面的代碼可以看出,先是獲取到<context:component-scan>標(biāo)簽中配置的base-package元素,通過(guò)這個(gè)元素的值知道要掃描那些類(lèi),然后執(zhí)行掃描,獲取標(biāo)注了@Component,@Repository,@Service,@Controller這幾個(gè)注解的類(lèi),并注冊(cè)到beanDefinitionMap中,在容器觸發(fā)getBean()方法,將對(duì)這些類(lèi)進(jìn)行實(shí)例化,并保存在spring的注冊(cè)表(當(dāng)然這是在Singleton情況下)
(3)下面來(lái)看具體的掃描過(guò)程
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
進(jìn)入doScan方法中
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) {
//這里是重點(diǎn),這里將對(duì)指定的包下的類(lèi)進(jìn)行掃描,拿到候選的掃描類(lèi)
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);
//這里注冊(cè)到beanDefinitionMap中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
重點(diǎn)是繼承自父類(lèi)ClassPathScanningCandidateComponentProvider 的findCandidateComponents方法,這里將進(jìn)行掃描
來(lái)看下這個(gè)findCandidateComponents方法
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + "/" + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.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 = this.metadataReaderFactory.getMetadataReader(resource);
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;
}
未待完續(xù)。。。
[朝陽(yáng)區(qū)尼克楊]
轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝啦!