今天我们学习一个比较少用到,但是也是比较强大的功能@Configurable。
大家都知道,在Spring容器里的对象可以通过@Autowired来注入,但是如果这个对象是你自己new出来的,恐怕很难通过@Autowired来获得对象了。
@Configurable这个注解就是为了给非Spring容器管理的对象提供注入Spring容器内对象的一个注解。
我们先看一下我们的一个普通对象,这个对象里我们注入一个Spring的ApplicationContext。然后标记为@Configurable。
@Configurable
public class User {
@Autowired
ApplicationContext applicationContext;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString(){
return Arrays.asList(applicationContext.getBeanDefinitionNames()).toString();
}
}
这里我们重写toString()方法打印为显示容器里的bean名称。
然后我们修改启动类
@SpringBootApplication
@EnableSpringConfigured
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
此时我们需要的东西基本准备完成了,然后我们需要在pom文件添加
<!-- aspects 编译需要的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- aspects 编译需要的依赖 end-->
和
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<outxml>true</outxml>
<verbose>true</verbose>
<showWeaveInfo>true</showWeaveInfo>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
我们写测试类来看看结果,
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
@Test
public void contextLoads() {
User user=new User();
System.out.println(user.toString());
}
}
注意,这里我们的User对象是new出来的。我们看到运行后并没有报空指针异常,而是打印出了Spring容器对象名称。
[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, org.springframework.boot.test.mock.mockito.MockitoPostProcessor$SpyPostProcessor, org.springframework.boot.test.mock.mockito.MockitoPostProcessor, application, org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory, org.springframework.context.annotation.aspectj.SpringConfiguredConfiguration, org.springframework.context.config.internalBeanConfigurerAspect, org.springframework.boot.autoconfigure.AutoConfigurationPackages, org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration, org.springframework.boot.autoconfigure.condition.BeanTypeRegistry, propertySourcesPlaceholderConfigurer, org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$CglibAutoProxyConfiguration, org.springframework.aop.config.internalAutoProxyCreator, org.springframework.boot.autoconfigure.aop.AopAutoConfiguration, org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration, org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration, org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor, org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata, org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration, persistenceExceptionTranslationPostProcessor, org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration, spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties, org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration, taskExecutorBuilder, applicationTaskExecutor, spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties, org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration, taskSchedulerBuilder, spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, platformTransactionManagerCustomizers, spring.transaction-org.springframework.boot.autoconfigure.transaction.TransactionProperties]
我们去target里面反编译class文件看看结果
@Configurable
public class User implements ConfigurableObject {
@Autowired
ApplicationContext applicationContext;
private String name;
private int age;
public User() {
JoinPoint var2 = Factory.makeJP(ajc$tjp_1, this, this);
JoinPoint var1 = Factory.makeJP(ajc$tjp_0, this, this);
if (this != null && this.getClass().isAnnotationPresent(Configurable.class) && AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class))) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$before$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$1$e854fa65(this);
}
if (this != null && this.getClass().isAnnotationPresent(Configurable.class) && (this == null || !this.getClass().isAnnotationPresent(Configurable.class) || !AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class))) && AbstractDependencyInjectionAspect.ajc$if$6f1(var1)) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(this);
}
if (!AnnotationBeanConfigurerAspect.ajc$if$bb0((Configurable)this.getClass().getAnnotation(Configurable.class)) && AbstractDependencyInjectionAspect.ajc$if$6f1(var2)) {
AnnotationBeanConfigurerAspect.aspectOf().ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(this);
}
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return Arrays.asList(this.applicationContext.getBeanDefinitionNames()).toString();
}
static {
ajc$preClinit();
}
}
可以看到,Spring为我们添加了很多方法,这也就解释了为啥能注入spring bean的原因了。
源码链接https://link.zhihu.com/?target=https%3A//github.com/yuebo/wechat-blog/tree/master/spring