Spring context:component-scan与context:annotation-config的区别

1. 区别概述

1.1. <context:annotation-config/>的作用

<context:annotation-config/>用来注册几个常用的BeanPostProcessor,包括

  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor
  • PersistenceAnnotationBeanPostProcessor
  • RequiredAnnotationBeanPostProcessor

这四个Processor,注册这4个BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。BeanPostProcessor就是处理注解的处理器。

比如我们要使用@Autowired注解,那么就必须事先在 Spring 容器中声明AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下

1
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

如果想使用@Resource、@PostConstruct、@PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor。传统声明方式如下

1
<bean class="org.springframework.beans.factory.annotation.CommonAnnotationBeanPostProcessor"/>

如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor的Bean

1
<bean class="org.springframework.beans.factory.annotation.PersistenceAnnotationBeanPostProcessor"/>

如果想使用 @Required的注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean

1
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>

一般来说,像@Resource、@PostConstruct、@Antowired这些注解在自动注入还是比较常用,所以如果总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config/>的简化配置方式,自动帮你完成声明

但是<context:annotation-config/>存在一定的局限性,它不能激活@Component、@Controller、@Service等常用注解

1.2. <context:component-scan>的作用

包含了<context:annotation-config/>的功能,同时还注册base-package下的注解类,即可以识别@Component、@Controller、@Service等注解。
如果理解了上述所说,那么也就懂得,no bean named springsessionrepositoryfilter is defined,就是因为没配置此两项之一

1.3. 二者的总结

<context:component-scan>包含了<context:annotation-config/>的功能,所以实际开发中,只要配置<context:component-scan>就可以了

如果同时使用这两个配置会不会出现重复注入的情况呢?答案是不会的。如果都配置了,<context:annotation-config/>会被忽略,相当于只配置了<context:component-scan>,所以@Autowire,@esource等注入注解只会被注入一次

2. 源码分析

2.1. <context:annotation-config/>源码

首先找到ContextNamespaceHandler,它的作用是解析context命名空间下的元素,看一下继承层次图

1
2
3
4
5
6
7
8
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// 只保留重要的两句
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
}
}

annotation-config对应AnnotationConfigBeanDefinitionParser,主要看parse方法,

1
2
3
4
5
6
7
8
9
10
11
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// 获取所有与BeanPostProcessors有关的bean定义.
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
return null;
}
}

AnnotationConfigUtils.registerAnnotationConfigProcessors中获取所有BeanPostProcessor的bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public abstract class AnnotationConfigUtils {
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
"org.springframework.context.annotation.internalConfigurationBeanNameGenerator";

public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";

public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalCommonAnnotationProcessor";

public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalPersistenceAnnotationProcessor";

private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
"org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";

public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
"org.springframework.context.event.internalEventListenerProcessor";

public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
"org.springframework.context.event.internalEventListenerFactory";

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {

DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}

Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}

// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}

// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}

if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}

if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}

return beanDefs;
}
}

这里用到了CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAMEAUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME等几个常量,在此列了一个表

常量 对应的BeanPostProcessor 对应的注解
CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME ConfigurationClassPostProcessor @Configuration
AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME AutowiredAnnotationBeanPostProcessor @AutoWired
REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME RequiredAnnotationBeanPostProcessor @Required
COMMON_ANNOTATION_PROCESSOR_BEAN_NAME CommonAnnotationBeanPostProcessor @javax.annotation.PostConstruct、@javax.annotation.PreDestroy

2.2. <context:component-scan/>源码

类似的,我们看ComponentScanBeanDefinitionParser的parse方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
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);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
// 重点
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

return null;
}
}

简单来说,就是扫描属性base-package指定包下的类,然后注册,那重点就在registerComponents方法了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
protected void registerComponents(
XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

Object source = readerContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
}

// Register annotation config processors, if necessary.
boolean annotationConfig = true;
if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
}
if (annotationConfig) {
// 跟<context:annotation-config/>一样,也调用了AnnotationConfigUtils.registerAnnotationConfigProcessors
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
}
}

readerContext.fireComponentRegistered(compositeDef);
}
}

可以看出此方法就做了两件事,一是注册base-package下的类,二是调用AnnotationConfigUtils.registerAnnotationConfigProcessors 注册BeanPostProcessor,跟<context:annotation-config/>一模一样。到此就真相大白了

panchaoxin wechat
关注我的公众号
支持一下