`
IXHONG
  • 浏览: 450053 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring之@Configuration配置解析

阅读更多

 

 1.简单的示例:

技术分享
1 @Configuration
2 @EnableConfigurationProperties({DemoProperties.class})
3 public class DemoConfiguration {
4 
5     @Bean
6     public Book getBook(){
7        return new Book();
8     }
9 }
Configuration
技术分享
1     @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

技术分享
1     @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
技术分享
1     @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的构造方法:

技术分享
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<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  

技术分享
1 @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

技术分享
1 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到容器中。

技术分享
 1     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一样

技术分享
 1         // 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方法:

技术分享
 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     }
0
1
分享到:
评论

相关推荐

    Springboot @Configuration @bean注解作用解析

    Spring Boot 中 @Configuration 和 @Bean 注解的作用解析 在 Spring Boot 框架中,@Configuration 和 @Bean 是两个非常重要的注解,它们分别用于配置 Spring 容器和注册 Bean。 一、@Configuration 注解 @...

    Spring @Bean注解配置及使用方法解析

    Spring @Bean 注解配置及使用方法解析 @Bean 注解是 Spring 框架中用于生成 Bean 实例的注解,主要用在方法上,声明当前方法体中包含了最终产生 Bean 实例的逻辑。该注解可以与 @Component 或 @Configuration 一起...

    (转)Spring中@Autowired注解和@Resource注解的区别

    通过源码分析,我们可以了解到Spring如何解析这些注解并执行依赖注入的过程,这有助于我们更好地理解和利用Spring框架。同时,结合工具如IDEA的代码提示和重构功能,可以更高效地运用这些注解进行开发。

    Spring配置Freemarker视图解析器,配置多个视图解析器

    本篇文章将深入探讨如何在Spring中配置Freemarker视图解析器,以及如何配置多个视图解析器以实现更灵活的应用场景。 首先,让我们了解如何配置单个Freemarker视图解析器。在Spring的配置文件(如`...

    Spring Boot:启动原理解析.docx

    在 Spring Boot 中,@Configuration 注解是启动类的标注之一,它使得启动类本身就是一个 IoC 容器的配置类。 2. @EnableAutoConfiguration 注解 @EnableAutoConfiguration 注解是 Spring Boot 的自动配置机制的...

    spring源码合集spring源码合集

    2. **配置类源码深度解析**:在"11-Spring之配置类源码深度解析-周瑜"中,我们将研究Spring的@Configuration和@Bean注解的工作机制。Spring的配置类提供了一种声明式配置的方式,替代了传统的XML配置。我们将探讨...

    Spring注解@Conditional案例解析

    Spring注解@Conditional案例解析 @Conditional是一个Spring4提供的注解,用于按照一定的条件进行判断,满足条件给容器注册Bean。下面是对@Conditional的详细解析和示例代码。 一、@Conditional介绍 @Conditional...

    Spring 自定义注解的解析

    在Spring框架中,自定义注解的解析是一个强大的特性,允许开发者根据业务需求创建特定的注解,并在Spring容器启动时自动处理这些注解。本文将深入探讨如何在Spring环境中通过`component-scan`配置来处理自定义Java...

    Spring读取配置文件原理(Spring如何依赖注入的)

    Spring框架是Java开发中广泛使用的轻量级框架,它的核心特性之一就是依赖注入(Dependency Injection,简称DI)。本文将深入探讨Spring如何通过读取配置文件实现依赖注入,并讲解相关源码,帮助理解其工作原理。 在...

    spring读取jar中的配置文件

    在Java开发中,Spring框架是应用最广泛的IoC(Inversion of Control)和AOP(Aspect Oriented Programming)容器。...在实际开发中,应根据项目需求选择合适的方式,确保配置文件能被正确地加载和解析。

    Spring@注解.md

    使用`@Configuration`注解的类被视为Spring容器的配置类。 - **@Bean**:可以理解为Spring中的`&lt;bean&gt;`标签,用于定义一个具体的Bean。 结合使用`@Configuration`和`@Bean`可以有效地管理Spring容器中的Bean,例如...

    Spring4 jar包和Spring配置文件

    Spring框架是Java开发中最常用的轻量级框架之一,它的核心在于IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)。在本压缩包中,你将找到Spring4版本的相关jar包,这些是...

    spring mvc 读取配置文件

    这些文件包含了Spring MVC应用的所有组件配置,如控制器(Controller)、视图解析器(View Resolver)、数据访问对象(DAO)等。在Spring 4.0之后,随着Java配置的引入,我们也可以使用@Configuration注解的类来代替...

    Spring-Reference_zh_CN(Spring中文参考手册)

    6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 ...

    SpringMVC基于代码的配置方式(零配置,无web.xml)

    在基于代码的配置中,我们不再需要在web.xml中配置,而是通过Spring的@Configuration和@EnableWebMvc注解来实现。不过,由于Spring Boot的自动配置,通常我们并不需要显式地添加@EnableWebMvc,因为已经默认开启了。...

    spring无web.xml零配置

    然而,随着Spring的发展,特别是Spring 3.0引入的Java配置特性,我们可以通过编写Java类来完成这些配置,使得配置过程更加面向对象化,同时避免了XML解析的繁琐。 Java配置(javaconfig)的核心在于`@Configuration...

    spring + spring mvc + hibernate 之零配置之路源代码

    本文将详细解析"spring + spring mvc + hibernate 之零配置之路"这一主题,并探讨如何通过源代码实现无XML配置的Java应用。 Spring框架是一个全面的后端开发框架,它提供了依赖注入(DI)和面向切面编程(AOP)等...

    springboot原理解析

    - **定义**:`@Configuration` 注解是Spring提供的一种配置方式,用于定义JavaConfig形式的Spring IoC容器的配置类,它可以替代XML配置文件。 - **作用**: - `@Configuration` 相当于 `&lt;beans&gt;` 标签,用来定义一...

    spring3.1相关配置文件

    此外,`@Configuration`注解的引入,允许开发者使用Java配置类替代XML配置,提高了代码的可读性和可维护性。 2. **AOP增强**:Spring 3.1对AOP的支持也有所加强,增加了对代理模式的选择,可以选择JDK动态代理或...

Global site tag (gtag.js) - Google Analytics