博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring之@Configuration配置解析
阅读量:4677 次
发布时间:2019-06-09

本文共 8888 字,大约阅读时间需要 29 分钟。

1.简单的示例:

1 @Configuration2 @EnableConfigurationProperties({DemoProperties.class})3 public class DemoConfiguration {4 5     @Bean6     public Book getBook(){7        return new Book();8     }9 }
Configuration
1     @Autowired Book book;2 3     @Test4     public void testBook(){5         System.out.println(book.toString());6     }
单元测试

结果打印出book对象,证明Book已经被注入到Spring 容器中了。

2.@Configuration配置的bean是如何注入到Spring容器中的呢?

首先先来简单介绍下通过BeanDefinitionRegistry注入bean

1     @Autowired2     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
1     @Autowired @Qualifier("mybook") Book book2;2     @Test3     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的构造方法:

1 public AnnotationConfigEmbeddedWebApplicationContext() {2         this.reader = new AnnotatedBeanDefinitionReader(this);3         this.scanner = new ClassPathBeanDefinitionScanner(this);4     }
ApplicationContext构造
1 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {2         this(registry, getOrCreateEnvironment(registry));3     }
View Code
1     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
1     public static Set
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
beanDefs = new LinkedHashSet
(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  

1 @Target(ElementType.TYPE)2 @Retention(RetentionPolicy.RUNTIME)3 @Documented4 public @interface PropertySources {5 6     PropertySource[] value();7 8 }
PropertySources定义

最终都是处理@PropertySource,@PropertySources仅仅只是包含多个@PropertySource,@PropertySource注解的主要功能是引入配置文件,将配置的属性键值对与环境变量中的配置合并。其中最关键的类为MutablePropertySources

1 public class MutablePropertySources implements PropertySources {2 3     private final Log logger;4 5     private final List
> propertySourceList = new CopyOnWriteArrayList
>();6 ......7 }
View Code

显然MutablePropertySources中包含有一个PropertySource列表。MutablePropertySources仅仅是封装了迭代器功能。可以理解成PropertySources是PropertySource的集合,增加了常用的集合操作。

(2)@ComponentScan

定义自动扫描的包。简化的序列图如下:

 

其最关键的方法为doScan方法,会注册BeanDefinition到容器中。

1     protected Set
doScan(String... basePackages) { 2 Assert.notEmpty(basePackages, "At least one base package must be specified"); 3 Set
beanDefinitions = new LinkedHashSet
(); 4 for (String basePackage : basePackages) { 5 Set
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一样

1         // Process individual @Bean methods 2         Set
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方法:

1     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     }
View Code

 

转载于:https://www.cnblogs.com/dragonfei/p/5925114.html

你可能感兴趣的文章
QQ登录JS SDK教程,调用openapi接口
查看>>
Socket编程
查看>>
为什么需要输入验证码?
查看>>
【spring 4】AOP:动态代理
查看>>
十六进制转化二进制[c]
查看>>
Create Index using NEST .NET
查看>>
异常:This application has no explicit mapping for /error, so you are seeing this as a fallback.
查看>>
垮平台开发平台
查看>>
使用wordpress自带ajax方法
查看>>
IOS中int和NSInteger的区别
查看>>
ios之AFN上传下载详细步骤(2)
查看>>
分解因数
查看>>
数据的存取与清洗
查看>>
设计模式---代理模式
查看>>
耶鲁大学——心理学导论(这就是你的大脑)
查看>>
使用gifplayer操作gif的方法
查看>>
利用SOAtest建立自动化测试验证网站是否成功加载
查看>>
win7 64 搭建 64 位 apache httpd php mysql
查看>>
博客存档TensorFlow入门一 1.4编程练习
查看>>
BZOJ 1047 [HAOI2007]理想的正方形
查看>>