回顾一下:
Spring 的四种4种类型的AOP支持:
* 1.基于代理的经典SpringAOP
* 2.纯POJO切面
* 3.@AspectJ注解驱动的切面
* 4.注入式AspectJ切面
前三种都是Spring AOP实现的变体,Spring AOP构建在动态代理之上,因此Spring 对AOP 的支持局限于方法拦截器,Spring 的AOP 无法把通知应用于对象的创建过程(构造方法)。
第四种类型能够将值注入到AspectJ 驱动的切面中。
前面的例子中我们常用@Aspect 来注解一个类,这些切面可能依赖于Spring容器 创建的bean 来完成它们的工作。我们可以借助Spring 的注入依赖把bean 装配到AspectJ 切面中,AspectJ 切面并不依赖于Spring 来创建切面。
场景:评论员对表演员在表演进场时鼓掌表欢迎,在表演员表演后作出评论。
1.表演接口
public interface Performance {
public void perform();
}
2.表演实现类
public class PerformanceImpl implements Performance {
//构造方法
public PerformanceImpl() {
System.out.println("演员进场...");
}
@Override
public void perform() {
System.out.println("表演过程中...");
}
}
3.评论员接口
public interface CriticismEngine {
public String getCriticism();
}
4.实现评论员接口
public class CriticismEngineImpl implements CriticismEngine {
private String[] criticismPool;//评论池,即评论员的评论集合
public CriticismEngineImpl(){}
public void setCriticismPool(String[] criticismPool){
this.criticismPool = criticismPool;
}
/**
* 随机从评论池中选取一条评论
*/
@Override
public String getCriticism() {
int i = (int) (Math.random() * criticismPool.length);
return criticismPool[i];
}
}
5.AspectJ 切面,注意时aspect 类型来声明AspectJ 切面,不是class
public aspect CriticAspect {
private CriticismEngine criticismEngine;//使用Spring 的依赖注入bean
public CriticAspect() {}
pointcut applause(): execution(com.qhf.aop.example08.PerformanceImpl.new());
after(): applause() {
System.out.println("评论员鼓掌...");
}
pointcut performance(): execution(* com.qhf.aop.example08.Performance.perform(..));
after(): performance() {
System.out.println("评论员:" + criticismEngine.getCriticism());
}
public void setCriticismEngine(CriticismEngine criticismEngine) {
this.criticismEngine = criticismEngine;
}
}
6.配置类
@Configuration//作为配置文件之一
@ImportResource("classpath:aop/example08/aop.xml")
public class AOPConfig {
}
7.xml 配置
通常情况下,Spring bean 由Spring 容器初始化的,但是AspectJ 切面是由AspectJ 在运行期创建的。
bean 的 factory-method 属性,值为 "aspectOf" :所有的AspectJ 切面都提供了一个静态的aspectOf() 方法,该方法返回切面的一个单例。这里有个问题:去除了这个属性,依然能运行“评论员鼓掌...”,但是却不能运行这个切面里的引用对象的方法,说明去除这个属性,Spring 创建的bean 不会装配到AspectJ 切面中,切面却是成功创建。这个问题待研究。。。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 启动AspectJ 自动代理 -->
<aop:aspectj-autoproxy/>
<!-- bean,注入到aspect 切面中 -->
<bean id="criticismEngine" class="com.qhf.aop.example08.CriticismEngineImpl">
<property name="criticismPool">
<list>
<value>good</value>
<value>better</value>
<value>bad</value>
<value>worst</value>
</list>
</property>
</bean>
<!-- factory-method="aspectOf":
并不是由Spring 创建的bean,而是由AspectJ 在运行期创建的;
所有的AspectJ 切面都提供了一个静态的aspectOf() 方法,该方法返回切面的一个单例 -->
<bean class="com.qhf.aop.example08.CriticAspect" factory-method="aspectOf">
<property name="criticismEngine" ref="criticismEngine"/>
</bean>
<!-- 自动注入的bean -->
<bean id="performanceImp" class="com.qhf.aop.example08.PerformanceImpl" />
</beans>
8.测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= AOPConfig.class)
public class Test {
@Autowired
private Performance performance;//即便这里名字是performance,符合这个接口的实现类是PerformanceImpl,所以bean的id是performanceImpl
@org.junit.Test
public void test(){
performance.perform();
}
}
9.结果:
演员进场...
评论员鼓掌...
表演过程中...
评论员:good