背景:
Performance代表任何类型的现场表演,如舞台剧、电影或音乐会。
Audience有四个方法,定义了一个观众在观看演出时可能会做的事情。在演出之前,观众要就坐takeSeats()并将手机调至静音状态silenceCellPhones()。如果演出很精彩的话,观众应该会鼓掌喝彩applause()。不过,如果演出没有达到观众预期的话,观众会要求退款demandRefund()。
加入Encoreable接口,代表此表演有返场演出performEncore()方法。此演出并不是常规的Performance中存在的,属于新的方法。如何在执行perform()之后执行新的方法?
Java并不是动态语言。一旦类编译完成了,我们就很难再为该类添加新的功能了。如果切面不仅仅实现了所包装bean相同的接口,而且还实现了新的接口,那么切面所通知的bean看起来似乎也像是实现了新的接口。其实底层实现类并没有真的实现新的接口,当新的接口的方法被调用时,代理会把此调用委托给实现了新接口的某个实现对象,实际上,一个bean的实现被拆分到了多个类中。
需要引入依赖
<!--spring aop依赖AspectJ-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
Performance接口与实现类PerformanceImpl
public interface Performance {
void perform();
}
@Component("performance")
public class PerformanceImpl implements Performance {
@Override
public void perform() {
System.out.println("perform...");
}
}
常规的切面类:Audience类
@Component
@Aspect
public class Audience {
@Pointcut("execution(* chapter04.performance.Performance.perform(..))")
public void performance(){}
@Around("performance()")
public void watchPerformance(ProceedingJoinPoint jp){
try {
System.out.println("Silencing cell phones");
System.out.println("Taking seats");
jp.proceed();
System.out.println("CLAP CLAP CLAP");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("Demanding a refund");
}
}
}
引入新的接口:Encoreable接口与实现类DefaultEncoreable
public interface Encoreable {
void performEncore();
}
public class DefaultEncoreable implements Encoreable {
@Override
public void performEncore() {
System.out.println("perform encore...");
}
}
新引入接口需要的切面类EncoreableIntroducer
/**
* 通过@DeclareParents注解,将Encoreable接口引入到Performance bean中
* Created by Administrator on 2017/12/1.
*/
@Component
@Aspect
public class EncoreableIntroducer {
/**
* value属性指定了哪种类型的bean要引入该接口,在本例中,也就是所有实现Performance的类型。
* defaultImpl属性指定了为引入功能提供实现的类
* @DeclareParents 注解所标注的静态属性指明了要引入了接口。在这里,我们所引入的是Encoreable接口。
*/
@DeclareParents(value="chapter04.performance.Performance+",defaultImpl = DefaultEncoreable.class)
public static Encoreable encoreable;
}
applicationContext.xml配置
<context:component-scan base-package="aop_test,chapter04"/>
<!-- 开启aop注解 -->
<aop:aspectj-autoproxy/>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class testPerformance {
@Autowired
Performance performance;
@Test
public void test(){
performance.perform();
Encoreable encoreable = (Encoreable) performance;
encoreable.performEncore();
}
}
测试结果
Silencing cell phones
Taking seats
perform...
CLAP CLAP CLAP
perform encore...