Spring|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中: 对应了Java中@Bean
  2. xml中: 对应了Java中@ComponentScan
@Configuration @ComponentScan(...) public class AppConfig { // various @Bean definitions ... }

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

这里这个说明一下, 它的作用是启用一些其他的后处理器(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() { ... } } }

【Spring|Spring @Configuration 注解介绍】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的。
附上文档地址, 点击进入

    推荐阅读