美文网首页Java技术区SpringSpring-clound
Spring @Configuration 注解介绍

Spring @Configuration 注解介绍

作者: 听歌闭麦开始自闭 | 来源:发表于2019-02-05 01:14 被阅读0次

    提前说明: 下文是我根据官方文档进行自己的描述和扩展, 写下来了我觉得比较值得关注的地方, 并附带了自己的介绍, 并不是原封不动的拿过来了api翻译了下,越往后越精彩

    指示一个类声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求
    使用方式如下:

    @Configuration
    public class AppConfig {
    
        @Bean
        public MyBean myBean() {
            // instantiate, configure and return bean ...
        }
    }
    

    简单看一下@Configuration的内部实现

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Configuration { ... }
    

    可以看到这个 @Component 注解, 意味也将会注册为bean, 其内部也可以依赖注入。 (换个方式说,一般Bean能用的东西,它也能用) 例如: @Autowired、@Inject、@Scope等

    @Configuration类 通常 使用AnnotationConfigApplicationContext或 其支持Web的变体AnnotationConfigWebApplicationContext进行引导。
    前者的一个简单示例如下:

    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.register(AppConfig.class);
    ctx.refresh();
    MyBean myBean = ctx.getBean(MyBean.class);
    // use myBean ...
    

    如果你看过ClassXmlPathApplicationContext的 工作过程, 你应该就能明白。
    @Configuration 注释的类 类似于于一个 xml 配置文件的存在(针对于 ClassXmlPathApplicationContext 来说)。
    不过它是由AnnotationConfigApplicationContext类进行解析并注册到Bean的注册表中。
    关于AnnotationConfigApplicationContext的工作过程就不说明了。 和ClassXmlPathApplicationContext差不多,换汤不换药。 真有兴趣自己调试。

    这里提一下, 上面说我们可以将其理解为一个Xml内容的Java版本, 那么,一些Xml中使用的其他写法在其中能用吗? 答案是能。 我也没试过其余用法,写出来自己知道的几个。
    如下:

    1. xml中: <bean/> 对应了Java中@Bean
    2. xml中: <context:component-scan/> 对应了Java中@ComponentScan
     @Configuration
     @ComponentScan(...)
     public class AppConfig {
         // various @Bean definitions ...
     }
    
    1. xml中: <import/> 对应了Java中@Import

    Via Spring <beans> XML

    除了上面写的引导方式外, 也可以使用将该类作为一个 bean 写到 xml 中, 交由ClassXmlPathApplicationContext或其他类 进行解析, 如下:

     <beans>
        <context:annotation-config/>
        <bean class="com.acme.AppConfig"/>
     </beans>
    

    这里这个<context:annotation-config/>说明一下, 它的作用是启用一些其他的后处理器(Post Processor), 例如: ConfigurationClassPostProcessor类
    下面会对ConfigurationClassPostProcessor进行稍微的提及


    With the @Import annotation

    使用@Import注解

    我的一篇描述@Import的文章, 点击进入


    With the @Profile annotation

    使用@Profile注释

    这个地方也挺简单的, 我的另一文章简单说了下@Profile注解,点击查看

    关于原文档关于``@Configuration和@Profile的联合使用, 自己去看一下描述就好了, 一共2个代码例子, 3行话..


    With Spring XML using the @ImportResource annotation

    使用@ImportResource注解

    这个地方只是拿过来翻译了一下, 因为我觉得有必要写在这提醒一下可以这么用。挺简单的
    @ImportResource

    可以使用@ImportResource注释将Spring XML配置文件导入@Configuration类。 可以注入从 XML导入的Bean定义
    例如,使用@Inject:

     @Configuration
     @ImportResource("classpath:/com/acme/database-config.xml")
     public class AppConfig {
    
         @Inject DataSource dataSource; // from XML
    
         @Bean
         public MyBean myBean() {
             // inject the XML-defined dataSource bean
             return new MyBean(this.dataSource);
         }
     }
    

    With nested @Configuration classes

    使用嵌套的@Configuration类

    这里不写示例了, 可以看下面 Constraints when authoring @Configuration classes
    里面的第4个约束的代码示例.. 因为这个帖子我是看着原文从下往上写的.
    

    这里还是要说一下几个点(结合下面的代码示例看)
    1.在引导这样的安排时, 只需要针对应用程序上下文注册AppConfig。
    (注册AppConfig就自动注册了它的嵌套配置了, 你可以看看关于@Configuration相关的PostProcessor是如何处理的, 最下面有提到关于如何使用PostProcessor实现cglib代理的)
    2.由于是一个嵌套的@Configuration类, 其子类也是@Configuration的加载模式。
    但是AppConfigAux类生成的bean的id是 (AppConfig文件的路径).AppConfig$AppConfigAux。

    当然你也可以使用上面说到的@Import去搞, 这随你意。

    另请注意,嵌套的@Configuration类可以通过@Profile注释使用, 以便为封闭的@Configuration类提供相同bean的两个选项。


    Configuring lazy initialization

    配置延迟初始化

    如果在@Configuring注解旁边也是用@Lazy, 如下所示:

    @Configuration
    @Lazy
    public class AppConfig { ... }
    

    其内部的所有bean都将会使用该属性, 默认情况下bean是non-lazy的。


    Enabling built-in Spring features using @Enable annotations

    使用@EnableXX注释启用内置Spring功能

    可以使用各自的@EnableXXX注释从@Configuration类启用和配置Spring等功能。
    例如:
    1.异步方法执行 @EnableAsync
    2.计划任务执行 @EnableScheduling
    3.注释驱动事务管理 @EnableTransactionManagement@EnableAspectJAutoProxy
    4.Spring WebMVC @EnableWebMvc

    稍微提一下 Spring Boot 的启动类注解@SpringBootApplication也有元注解@Configuration。 你在用 Sprng Cloud 的时候会写很多@EnableXXX到你用的时候可以注意一下


    Constraints when authoring @Configuration classes

    创建@Configuration类时的约束

    1.必须以类的形式提供配置类, 允许通过生成的子类进行运行时增强(Cglib动态代理)。

    这里的后半句将在下面说明...有点长,为了不影响格式
    

    2.配置类必须是non-final的。

    可以使用第4个约束的代码对 AppConfigAux 进行修改并测试, 编译器(IDEA)会直接指出这种写法是错误的
    

    3.配置类必须是non-local的(即不能在方法中声明)。

    non-local是不是翻译成非局部的比较好
    可以使用第4个约束的代码对 AppConfigAux 的访问级别修改成private试一试,会报错的, 这一步的测试体现该类不能是private级别。
    
    不能在方法中声明 表示的是不能是局部内部类
    
    

    4.必须将任何嵌套配置类声明为static。

    @Configuration
    public class AppConfig {
    
        @Bean
        public Chinese getChinese() { ... }
    
        @Configuration
        public static class AppConfigAux {
            @Bean
            public English getEnglish() { ... }
        }
    }
    
    

    5.@Bean方法可能不会反过来创建进一步的配置类(任何此类实例都将被视为常规bean,其配置注释仍未被检测到)。

    @Configuration
    public class AppConfig {
        // 这个也将被视为一个bean, 并不会有什么特殊处理
        @Bean
        public AppConfig getAppConfig() {
            return new AppConfig();
        }
    }
    

    对约束1后半句的说明
    不知道你们还记得ConfigurationClassPostProcessor这个类不. 上面有提到过。
    这个类是用来处理带有@Configuration注解的类的, 看一下它的源码:

    public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
            PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { ... }
    
    
    // 这里再跟进去看看BeanDefinitionRegistryPostProcessor的源码, 如下
    
    public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { ... }
    

    重点是它是BeanFactoryPostProcessor接口的实现 这个现象
    这里开始往下,如果你有关于IOC的源码只是的话,就很简单了。如果没有,跟着调试。

    然后我们就可以跟到org.springframework.context.support.AbstractApplicationContext#refresh()方法中, 可以看到invokeBeanFactoryPostProcessors()

    到这, 我们知道ConfigurationClassPostProcessor工作在BeanDefinitions加载之后, bean实例化之前的结论。
    BeanDefinitions加载是在try外面那2步中(invokeBeanFactoryPostProcessors()的上面)
    实例化是在finishBeanFactoryInitialization(beanFactory)方法中

    到这一步就不跟下去了, 最终这一步会调用ConfigurationClassPostProcessor.class中的postProcessBeanFactory(...)方法。
    重点是其中调用的enhanceConfigurationClasses(ConfigurableListableBeanFactory)
    这个方法中你会看到对@Configuration注解的类的增强操作。 在细节就不讲了, 可以自己跟一下看看如何加载其中@Bean的。

    附上文档地址, 点击进入

    相关文章

      网友评论

        本文标题:Spring @Configuration 注解介绍

        本文链接:https://www.haomeiwen.com/subject/pgvmsqtx.html