Spring @Configuration 注解介绍

提前说明: 下文是我根据官方文档进行自己的描述和扩展, 写下来了我觉得比较值得关注的地方, 并附带了自己的介绍, 并不是原封不动的拿过来了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的。

附上文档地址, 点击进入

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容