【源码窥探】Spring5注解配置类Configuration(版本5.2.X)

版权声明:如有转载-请加微信457556886告知下就可以 知识都是分享的 https://blog.csdn.net/wolf_love666/article/details/90767391

友好提示:

路径:org.springframework.context.annotation.Configuration
版本:5.2.0.BUILD

官方说明解释:

1、@Configuration类可以声明1个或者多个bean方法,也可以通过spring容器生成bean定义和运行时候要求的那些请求的服务。举例如下:

@Configuration
 public class AppConfig {

    @Bean
     public MyBean myBean() {
         //实例化,配置和返回对应bean
    }
 }

2、
@Configuration类是可以被引导的,使用AnnotationConfigApplicationContext类,或者web功能的变形AnnotationConfigWebApplicationContext类。比如下面的这个例子:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
 ctx.register(AppConfig.class);
 ctx.refresh();
 MyBean myBean = ctx.getBean(MyBean.class);
//use myBean ...处理业务逻辑

策略提醒:
应用上下文中使用AnnotationConfigApplicationContext
servlet容器web配置环境中使用AnnotationConfigWebApplicationContext

3、通过Spring beans的XML文件使用
作为直接注册@Configuration类的替换AnnotationConfigApplicationContext和@Configuration的组合方案也可以是直接通过spring的xml文件定义的方式。

<beans>
 <context:annotation-config/>
 <bean class="com.acme.AppConfig"/>
 </beans>
 在上述的例子中,
<context:annotation-config/>
是为了来开启ConfigurationClassPostProcessor
和其他注解相关操作来方便操作@Configuration类

4、通过组件扫描

@Configuration使用spring组件@Component进行元注解,
这样spring开启{ <context: Component -scan/>}扫描注解的时候,凡是应用注解@Configuration的类,
都可以被相当于正常的bean实例,通过@Autowired 或者@Inject注入。
如果只有一个构造函数,那么默认自动注入该构造函数,比如如下例子:默认SomeBean就自动注入了bean实例。因为只有这一个构造函数。
@Configuration
public class AppConfig {

private final SomeBean someBean;

public AppConfig(SomeBean someBean) {
  this.someBean = someBean;
}

// @Bean definition using "SomeBean"
 
}

@Configuration类可以不只是通过组件扫描引导使用,也可以通过配置组件注解扫描引导使用@ComponentScan

@Configuration
@ComponentScan("com.xiaochengxinyizhan.services")
public class AppConfig {
    // 其他的 @Bean definitions ...
 }
备注:com.xiaochengxinyizhan.services是AppConfig的包目路径目录

5、处理外部参数,使用Environment的API支持。
spring的核心包org.springframework.core.env.Environment类可以通过@Autowired注入到@Configuration类。比如如下例子:

@Configuration
public class AppConfig {

@Autowired 
Environment env;

@Bean
public MyBean myBean() {
 MyBean myBean = new MyBean();
   myBean.setName(env.getProperty("bean.name"));
   return myBean;
    }
 }

通过{ Environment}解析的属性会被放在一个或多个“property source”对象中,{@Configuration}类中可以通过使用{@PropertySource} 注解将属性源赋值存放给 {Environment}对象
举例如下:

@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {

@Inject 
Environment env;

@Bean
public MyBean myBean() {
return new MyBean(env.getProperty("bean.name"));
   }
 }

6、使用@Value注解
外部参数在@Configuration类中也可以通过使用@Value注解注入。

@Configuration
@PropertySource("classpath:/com/acme/app.properties")
 public class AppConfig {
 
 @Value("${bean.name}") 
   String beanName;

  @Bean
   public MyBean myBean() {
     return new MyBean(beanName);
  }
 }

这个方法经常与spring的PropertySourcesPlaceholderConfigurer类一起使用,PropertySourcesPlaceholderConfigurer可以自动从XML配置文件通过

<context:property-placeholder/>

获取或者在@Configuration类中的通过static 修饰的@bean方法获取,具体用法可以参考BeanFactoryPostProcessor 返回 @Bean的方法。
当然如果没有指定的话,则spring会指定个默认的,以及如果你不想用它可以自己的定制,那么还得看下PropertySourcesPlaceholderConfigurer官网的用法。

7、用@Import注解类完善@Configuration类
比如如下例子:

@Configuration
public class DatabaseConfig {

   @Bean
     public DataSource dataSource() {
       //实例化,配置和返回DataSource;
 }
 }

@Configuration
@Import(DatabaseConfig.class)
public class AppConfig {

 private final DatabaseConfig dataConfig;

 public AppConfig(DatabaseConfig dataConfig) {
    this.dataConfig = dataConfig;
  }

@Bean
   public MyBean myBean() {
      // 引用 dataSource() bean 方法
     return new MyBean(dataConfig.dataSource());
   }
 }

现在可以引导{AppConfig}和导入的{DatabaseConfig}
只在Spring上下文中注册{AppConfig}

new AnnotationConfigApplicationContext(AppConfig.class);

8、使用@Profile注解
由于@Configuration类会被Spring容器当成组件使用,那么我们可以使用@Profile注解来区分该配置类在哪种环境下适用,比如如下示例:

@Profile("development")
@Configuration
 public class EmbeddedDatabaseConfig {

@Bean
    public DataSource dataSource() {
        // instantiate, configure and return embedded DataSource
    }
 }

@Profile("production")
@Configuration
 public class ProductionDatabaseConfig {

@Bean
   public DataSource dataSource() {
       // instantiate, configure and return production DataSource
    }
 }

既然可以声明配置类,那么我们也可以声明配置@Bean方法级别(想要了解更多的可以看官方的@Profile和org.springframework.core.env.Environment)

 @Configuration
public class ProfileDatabaseConfig {

@Bean("dataSource")
@Profile("development")
public DataSource embeddedDatabase() { ... }

@Bean("dataSource")
@Profile("production")
  public DataSource productionDatabase() { ... }
 }

9、使用@ImportResource注解导入SpringXML的文件
正如上面所提到的,@Configuration类可能被声明为正规的SpringXML文件中的bean定义。那么也是可以通过@ImportResource注解导入@Configuration配置类中。Bean定义在XML文件的同样可以依赖注入。比如如下的例子:

@Configuration
 @ImportResource("classpath:/com/acme/database-config.xml")
public class AppConfig {

 @Inject DataSource dataSource; // 在XML中定义的

@Bean
    public MyBean myBean() {
       // 注入xml中定义的bean
       return new MyBean(this.dataSource);
   }
 }

10、@Configuration配置类可以嵌套(带来好处是如果显性已知的情况那么可以直接减少不必要的注解和环境说明)
比如如下这个例子:

 @Configuration
 public class AppConfig {
 
@Inject DataSource dataSource;

@Bean
 public MyBean myBean() {
   return new MyBean(dataSource);
   }

@Configuration
static class DatabaseConfig {
       @Bean
       DataSource dataSource() {
           return new EmbeddedDatabaseBuilder().build();
        }
     }
 }

11、配置懒初始化
默认情况下,@Bean方法在容器引导时候初始化,为了避免这种情况发生,@Configuration注解可以和@Lazy注解一起声明使用是其懒加载初始化。当然@Lazy也可以只用在独立的@Bean方法上

12、@Configuration类测试支持
在spring-test模块中spring容器的测试上下文框架提供了@ContextConfiguration注解可以接受@Configuration配置类和Class类对象

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppConfig.class, DatabaseConfig.class})
public class MyTests {

@Autowired 
MyBean myBean;

@Autowired 
DataSource dataSource;

@Test
     public void test() {
        // assertions against myBean ...
     }
}

13、在@Configuration配置类上,使用@Enable注解开启构建Spring特性
spring特性例如异步方法执行,定时任务执行,注解事务驱动,甚至Spring MVC可以被启动和配置。

org.springframework.scheduling.annotation.EnableAsync @EnableAsync
org.springframework.scheduling.annotation.EnableScheduling @EnableScheduling
org.springframework.transaction.annotation.EnableTransactionManagement @EnableTransactionManagement
org.springframework.context.annotation.EnableAspectJAutoProxy @EnableAspectJAutoProxy
org.springframework.web.servlet.config.annotation.EnableWebMvc @EnableWebMvc

14、@Configuration配置类的规定

  • 配置类必须是作为类被提供的(并不是工厂方法返回的实例),允许通过生成的子类进行运行时增强。
  • 配置类必须是非final修饰的,允许运行的时候使用子类,除非是proxyBeanMethods()设置为false,不允许子类的生成。
  • 配置类必须是非本地的(不能通过方法声明)
  • 如果他们的配置注解检查不到@Bean方法可能创建不了配置类,任何实例将被作为正常的Bean对待。

源码如下:

@Target(ElementType.TYPE)
//元素类型
@Retention(RetentionPolicy.RUNTIME)
//运行期间使用
@Documented
//文档化生成
@Component
//作为spring容器的组件可以被注入
public @interface Configuration {

	//如果不指定名字,则自动生成默认的配置类文件名称,要求是与@Configuration配套使用
	@AliasFor(annotation = Component.class)
	String value() default "";

	//从5.2开始,指定是否方法应该被大力为了强制bean生命周期行为例如有时候返回共享的单例bean实例再使用@Bean方法调用的时候,
	这个特性需要方法拦截,通过运行时生成的CGLIB 子类实现,该类带有一些限制,
	比如配置类及其方法不允许声明{final}。
	 默认值是{true},允许在配置类内的“bean间引用”,以及对该配置的 {@Bean}方法的外部调用,例如来自
	 另一个配置类。如果不需要,因为这个特定配置的每个{@Bean}方法都是自包含的,
	 并且被设计为容器使用的普通工厂方法,将这个标志切换到{false},以避免CGLIB子类处理。
	 关闭bean方法拦截有效地单独处理{ @Bean}方法,
	 就像在非{@Configuration}类上声明时一样,“@Bean Lite模式”(参考{@Bean的javadoc})。
	 因此,它在行为上等同于删除{@Configuration}原型。
	boolean proxyBeanMethods() default true;

}

猜你喜欢

转载自blog.csdn.net/wolf_love666/article/details/90767391