Thread和Topic在①处,都标注了@Configurable注解。仅仅标注了注解并没有任何用途,我们需要利用AspectJ LTW在加载这些领域对象类时为标注@Configurable注解的类织入切面。
首先,我们得将匹配@Configurable注解类的切面类AnnotationBeanConfigurerAspect所在的spring-aspects.jar类包添加到类路径上。spring-aspects.jar类包本身拥有一个aop.xml配置文件,其内容如下所示:
该配置文件会将AnnotationBeanConfigurerAspect和AnnotationTransactionAspect切面类应用到所有类中。AnnotationTransactionAspect用于处理@Transaction注解,这里我们没有用到。由于,我们希望限制进行AspectJ切面织入目标类的范围,所以我们需要再定义一个aop.xml文件:<aspectj>
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
</aspects>
</aspectj>
通过<weaver>的options属性的设置,指定在日志中显示织入操作的信息,通过<include>元素指定需要进行AspectJ织入的目标类。可以简单地将这个配置文件放到src/META-INF/目录下。<?xml version="1.0"?>
<aspectj>
<weaver options="-showWeaveInfo
-XmessageHandlerClass:org.springframework.aop.aspectj.AspectJWeaverMessageHandler"><include within="com.baobaotao.configure..*" /> ① 使AspectJ织入器仅对该包下类进行操作
</weaver>
</aspectj>
前面,我们提到过切面类AnnotationBeanConfigurerAspect实现了BeanFactoryAware接口,所以需要在Spring配置文件中配置它,以便其可以感知Spring IoC容器,此外我们还需要配置Thread和Topic领域对象Bean,为标注了@Configurable的领域对象提供依赖注入的功能:
在①处我们声明了一个AnnotationBeanConfigurerAspect Bean,并且定义了factory-method="aspectOf"属性,确保Spring从AspectJ获取切面实例,而不是尝试自己去创建该实例。<bean class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"
factory-method="aspectOf"/>①
<bean class="com.baobaotao.configure.Topic" scope="prototype"> ② 配置领域对象
<property name="title" value="测试帖子"/>
<property name="content" value="测试内容"/>
</bean>
<bean class="com.baobaotao.configure.Thread" scope="prototype"> ③ 配置领域对象
<property name="title" value="测试的主题"/>
<property name="topic" ref="com.baobaotao.configure.Topic"/>
</bean>
Spring在aop命名空间中为配置AntationBeanConfigurerAspect提供了专门的配置元素:<aop:spring-configured/>,可以用这种简洁的配置替代①处的配置。在②和③处,我们在Spring IoC中配置了领域对象Bean。
至此,一切已经就绪,我们可以编写一个测试类测试Spring管理容器外对象的功能:
在①处使用传统创建领域对象的方式构造一个Thread领域对象,在②处打印出该领域对象的信息。为ConfigureAnnoAspectTest类设置好JVM的javaagent参数,启用AspectJ LTW织入器,设置完成后,运行该测试类,控制台将输出以下的信息:package com.baobaotao.configure;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ConfigureAnnoAspectTest ...{
public static void main(String[] args) ...{
String configPath = "com/baobaotao/configure/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Thread thread = new Thread(); ① 象传统一样通过new构造领域对象
System.out.println(thread.toString()); ② 查看领域对象的信息
}
}
…
① 以下两行表示织入器注册切面类
②以下几行表示织入器对匹配目标类进行织入操作INFO [main] (AspectJWeaverMessageHandler.java:55) - [AspectJ] register
aspect org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspectINFO [main] (AspectJWeaverMessageHandler.java:55) - [AspectJ] register
aspect org.springframework.transaction.aspectj.AnnotationTransactionAspect…
INFO [main] (AspectJWeaverMessageHandler.java:55) - [AspectJ] weaving
'com/baobaotao/configure/Topic'INFO [main] (AspectJWeaverMessageHandler.java:55) - [AspectJ]
Join point 'initialization(void com.baobaotao.configure.Topic.<init>())' in
Type 'com.baobaotao.configure.Topic' (Topic.java:8) advised by afterReturning advice
from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect'
(AbstractBeanConfigurerAspect.aj:43)INFO [main] (AspectJWeaverMessageHandler.java:55) - [AspectJ] weaving
'com/baobaotao/configure/Thread'INFO [main] (AspectJWeaverMessageHandler.java:55) - [AspectJ] Join point
'initialization(void com.baobaotao.configure.Thread.<init>())' in Type
'com.baobaotao.configure.Thread' (Thread.java:7) advised by afterReturning
advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect'
(AbstractBeanConfigurerAspect.aj:43)'
