Spring @Configurable基本用法

关于@Configurable的用法,Spring文档有详细的描述,不过因为看得比较粗略,后面实际使用的时候踩了很多坑。这个注解有如下几个用途:html

为非Spring管理的对象注入Spring Bean

非Spring管理的对象,这里指的是咱们本身new的对象,好比Dog dog = new Dog(),这个dog对象的生命周期不是由Spring管理的,而是咱们本身建立的对象,根据文档的说法,咱们只要在类上面加上@Configurable注解,就可让Spring来配置这些非Spring管理的对象了,即为它们注入须要的依赖(实际上还有不少额外的工做要作)。下面有个例子java

// Account类,使用new操做符号手动建立,不交由Spring Container管理
@Configurable(autowire = Autowire.BY_TYPE)
public class Account {

    @Autowired
    Dog dog;

    public void output(){
        System.out.println(dog);
    }

}

上面的Account类使用的是@Configurable,而不是@Configuration@Configuration相似于XML配置里面的<beans></beans>,咱们能够在<beans></beans>里面声明要交由Spring Cotainer建立和管理的Bean,所以咱们能够在@Configuration注解的类里面使用@Bean注解达到一样的效果,注意被@Configuration标注的类也会被Spring Container建立和管理,所以它也是一个Bean。spring

@Configuration标注的类,可以被Spring配置,而后当咱们手动建立Account对象的时候(Account acc = new Account()),Spring将会用建立一个Account的Bean,而后这个Bean能被Spring正常地注入须要的属性,接着Spring使用这个Bean来设置咱们刚刚建立的
Account对象(acc)的属性,最后返回的对象的属性就和Bean的同样了。编程

// 配置类,使用注解的方式建立Bean
@Configuration
@EnableLoadTimeWeaving
@EnableSpringConfigured
public class Config {

    // 这个Bean将会被注入到Account的属性中
    @Bean
    Dog dog(){
        Dog d = new Dog();
        d.setId(1);
        d.setName("dog");
        return d;
    }
}
public class Dog {
    private int id;
    private String name;
    // set,get和toString方法就不贴了
}
// 启动类
@ComponentScan
public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(App.class);
        Account account = new Account();
        account.output();
    }
}

程序输入结果以下:jvm

Imgur

能够看到,咱们本身建立的Account对象,输出了Dog对象,而不是null。由于Spring使用AspectJ的LTW(LoadTimeWeaving)技术为咱们本身建立的Account对象注入了Dog对象。maven

要使上面的例子正常运行,须要知足几个要求:单元测试

  • spring-core, spring-beans, spring-context, spring-instrument, spring-aspects, aspectjweaver, spring-tx等几个依赖要有,其中spring-tx是可选的,没有的话会输出一些警告信息。测试

  • @EnableLoadTimeWeaving@EnableSpringConfigured两个注解必须有,能够注解在任意被@Configuration注解的类上面spa

  • 运行前加上-javaagent:/path/to/spring-instrument.jar这个jvm参数,/path/to/spring-instrument.jar为你的spring-instrumentjar包的路径debug

若是用的maven管理依赖,而且IDE为Intellij IDEA,能够打开Project Structure的Libraries选项查看jar包的路径,而后在run/debug里面配置jvm参数。
Imgur
Imgur

How it works?

首先,若是仅仅有@Configuration注解,是不起任何做用的,所以咱们这时候手动建立Account对象的话,将会输出null。由于起到关键做用的时候AnnotationBeanConfigurerAspect这个类(它是使用aspect定义的,而不是class,由于我还没用过aspectj编程,因此还不太了解),而这个类的实例在添加@EnableSpringConfigured注解后将会被Spring建立,而后Spring将会结合LWT技术调用这个对象里面的方法对咱们手动建立的Account对象的属性进行处理。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(SpringConfiguredConfiguration.class) //而后咱们去看看SpringConfiguredConfiguration干了什么
public @interface EnableSpringConfigured {

}
@Configuration
public class SpringConfiguredConfiguration {

	/**
	 * The bean name used for the configurer aspect.
	 */
	public static final String BEAN_CONFIGURER_ASPECT_BEAN_NAME =
			"org.springframework.context.config.internalBeanConfigurerAspect";

	@Bean(name = BEAN_CONFIGURER_ASPECT_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public AnnotationBeanConfigurerAspect beanConfigurerAspect() {
		return AnnotationBeanConfigurerAspect.aspectOf();
	}

}

从上能够看到,一个AnnotationBeanConfigurerAspect类型的Bean将会被Spring Container建立和管理,所以它就是让@Configurable注解起做用的核心。

public aspect AnnotationBeanConfigurerAspect extends AbstractInterfaceDrivenDependencyInjectionAspect
		implements BeanFactoryAware, InitializingBean, DisposableBean{
      //类的实现就不贴了,从它实现的接口也能够猜到一些东西
    }

文档上面还提到,不单单是使用new建立的时候,在反序列化的时候,被@Configurable注解的类和使用new建立的时候同样,会被拦截而后注入属性

方便单元测试

当类没有被AspectJ动态织入(LoadTimeWeaving)的时候,@Configuration是不起任何做用的,所以对单元测试不会产生影响

相关文章
相关标签/搜索