1.简单的示例:
@Configuration
2 @EnableConfigurationProperties({DemoProperties.class})
3 public class DemoConfiguration {
4
5 @Bean
6 public Book getBook(){
7 return new Book();
8 }
9 }
Configuration
@Autowired Book book;
2
3 @Test
4 public void testBook(){
5 System.out.println(book.toString());
6 }
单元测试
结果打印出book对象,证明Book已经被注入到Spring 容器中了。
2.@Configuration配置的bean是如何注入到Spring容器中的呢?
首先先来简单介绍下通过BeanDefinitionRegistry注入bean
@Autowired
2 public void registBeanDefinition(BeanFactory factory){
3 if(factory instanceof BeanDefinitionRegistry) {
4 BeanDefinitionRegistry registry = (BeanDefinitionRegistry)factory;
5 BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Book.class).getBeanDefinition();
6 registry.registerBeanDefinition("mybook", beanDefinition);
7 }
8 }
View Code
@Autowired @Qualifier("mybook") Book book2;
2 @Test
3 public void testBook2(){
4 System.out.println(book2);
5 }
单元测试
结果同样打印出book对象,这里,笔者将beanFactory强转为BenDefinitionRegistry,因为笔者的Demo中使用的是默认BeanFactory,----DefaultListableBeanFactory,他实现了BeanDefinitionRegistry接口。
3.入口,下图为ApplicaitonContext refresh方法的简化,只保留了BeandefinitionRegistry注册bean部分功能。
然,似乎并没什么用?此处会调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法。要解决的一个问题是,BeanDefinitionRegistryPostProcessor类型的bean是如何注入的。以SpringBoot初始化为例。
注意到,ApplicationContext的构造方法:
public AnnotationConfigEmbeddedWebApplicationContext() {
2 this.reader = new AnnotatedBeanDefinitionReader(this);
3 this.scanner = new ClassPathBeanDefinitionScanner(this);
4 }
ApplicationContext构造
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
2 this(registry, getOrCreateEnvironment(registry));
3 }
View Code
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
2 Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
3 Assert.notNull(environment, "Environment must not be null");
4 this.registry = registry;
5 this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
6 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
7 }
View Code
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
2 BeanDefinitionRegistry registry, Object source) {
3
4 DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
5 if (beanFactory != null) {
6 if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
7 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
8 }
9 if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
10 beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
11 }
12 }
13
14 Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
15 //注解@Configuration处理
16 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
17 RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
18 def.setSource(source);
19 beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
20 }
21
22 .......//省略部分代码
23
24 return beanDefs;
25 }
View Code
注意到对@Configuration的处理为ConfigurationClassPostProcessor。
注意到ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,显然关键方法为postProcessBeanDefinitionRegistry。ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry会调用ConfirgurationClassParser的parse方法。会依次解析注解,我们一步一步查看对各个注解的解析。
(1)@PropertySources和@PropertySource
@Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 public @interface PropertySources {
5
6 PropertySource[] value();
7
8 }
PropertySources定义
最终都是处理@PropertySource,@PropertySources仅仅只是包含多个@PropertySource,@PropertySource注解的主要功能是引入配置文件,将配置的属性键值对与环境变量中的配置合并。其中最关键的类为MutablePropertySources
public class MutablePropertySources implements PropertySources {
2
3 private final Log logger;
4
5 private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
6 ......
7 }
View Code
显然MutablePropertySources中包含有一个PropertySource列表。MutablePropertySources仅仅是封装了迭代器功能。可以理解成PropertySources是PropertySource的集合,增加了常用的集合操作。
(2)@ComponentScan
定义自动扫描的包。简化的序列图如下:
其最关键的方法为doScan方法,会注册BeanDefinition到容器中。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
2 Assert.notEmpty(basePackages, "At least one base package must be specified");
3 Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
4 for (String basePackage : basePackages) {
5 Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
6 for (BeanDefinition candidate : candidates) {
7 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
8 candidate.setScope(scopeMetadata.getScopeName());
9 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
10 if (candidate instanceof AbstractBeanDefinition) {
11 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
12 }
13 if (candidate instanceof AnnotatedBeanDefinition) {
14 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
15 }
16 if (checkCandidate(beanName, candidate)) {
17 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
18 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
19 beanDefinitions.add(definitionHolder);
20 registerBeanDefinition(definitionHolder, this.registry);
21 }
22 }
23 }
24 return beanDefinitions;
25 }
doScan方法
registerBeanDefinition(definitionHolder, this.registry);能说明一切。
(3)@Import
@Import注解可以配置需要引入的class(假设配置为A,可以是数组),有三种方式。其流程图如下:
如果A为ImportSelector的子类,调用selectImports()方法,返回class类名数组,循环解析每一个import的类,如果A为BeanDefinitionRegistrar则直接调用registerBeanDefinition直接注入bean到容器中。如果A为普通的类(非前面提到的两种类型),则将A当做@Configuration配置的类,重新解析Configuration.
(4)@ImportSource
主要功能为引入资源文件。
(5)@Bean,比较简单,童FactoryMethod一样
// Process individual @Bean methods
2 Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
3 for (MethodMetadata methodMetadata : beanMethods) {
4 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
5 }
6
7 // Process default methods on interfaces
8 for (SourceClass ifc : sourceClass.getInterfaces()) {
9 beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
10 for (MethodMetadata methodMetadata : beanMethods) {
11 if (!methodMetadata.isAbstract()) {
12 // A default method or other concrete method on a Java 8+ interface...
13 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
14 }
15 }
16 }
@Bean解析
最后真实加载beanDefinition是loadBeanDefinitionsForConfigurationClass方法:
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
2 TrackedConditionEvaluator trackedConditionEvaluator) {
3
4 if (trackedConditionEvaluator.shouldSkip(configClass)) {
5 String beanName = configClass.getBeanName();
6 if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
7 this.registry.removeBeanDefinition(beanName);
8 }
9 this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());
10 return;
11 }
12
13 if (configClass.isImported()) {
14 registerBeanDefinitionForImportedConfigurationClass(configClass);
15 }
16 for (BeanMethod beanMethod : configClass.getBeanMethods()) {
17 loadBeanDefinitionsForBeanMethod(beanMethod);
18 }
19 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
20 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
21 }