关于@Configurable
的用法,Spring文档有详细的描述,不过因为看得比较粗略,后面实际使用的时候踩了很多坑。这个注解有如下几个用途:html
非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
能够看到,咱们本身建立的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-instrument
jar包的路径debug
若是用的maven管理依赖,而且IDE为Intellij IDEA,能够打开Project Structure的Libraries选项查看jar包的路径,而后在run/debug里面配置jvm参数。
首先,若是仅仅有@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
是不起任何做用的,所以对单元测试不会产生影响