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() { ... }
    }
}

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 注解介绍)