在前面的切面学习中,注意到可以在对象.方法运行前后引入切面,执行通知代码,这本来就执行了多个方法,看起来却是像是对象的多个方法。切面只是实现了它们所包装的bean 相同接口的代理,如果除了实现这些接口,代理也能暴露新接口的话,切面所通知的bean看起来像是实现了新的接口,即便底层实现类并没有实现这些接口也无所谓。
当引入接口的方法即通知被调用时,代理会把此调用委托给实现了新接口的某个其他对象。实际上,一个bean的实现被拆分为多个类中。
实例:表演实现类只有play 方法,现需要有重新表演的方法 replay。需要有两个接口,一个父接口和一个子接口。
1.表演接口
package com.qhf.aop.example06;
public interface Performance {
void play();
}
2.表演实现类
import org.springframework.stereotype.Component;
@Component
public class PerformanceImpl implements Performance {
@Override
public void play() {
System.out.println("playing...");
}
}
3.定义一个重新表演接口
public interface Reperformance {
void replay();
}
4.重新表演实现类
public class ReperformanceImpl implements Reperformance {
@Override
public void replay() {
System.out.println("replaying...");
}
}
5.子接口的引入,相当于表演有两个方法,play 和 replay 方法
*@DeclareParents 注解,字面可理解为声明父母,即为value 值的类型的bean 引入该接口。
*value 值指定父接口,+ 号是作为子类型,即所有Performance 子类型
*defaultImpl 指定用哪个bean 作为实现类来引入
*Reperformance reperformance 中声明的bean 自动装配为指定defaultImpl 的类
@Component
@Aspect
public class ReperformanceIntorducer {
@DeclareParents(value = "com.qhf.aop.example06.Performance + ", defaultImpl = ReperformanceImpl.class)
public static Reperformance reperformance;
}
6.配置类
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AopConfig {
}
7.测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AopConfig.class)
public class Test {
@Autowired
private Performance performance;
@org.junit.Test
public void test(){
performance.play();
Reperformance r = (Reperformance) performance;//向下转型为子接口类
r.replay();
}
}
注意在ReperformanceImpl 中没有标注@Component,因为它在切面代理类ReperformanceIntorducer 中通过@DeclareParents 注解,值是.class说明是用字节码文件来装配到 reperformance 引用对象中。
只需通过父接口的实现类引用,向下转型为子接口类,便可以访问父接口引入的新方法。
7.结果
playing...
replaying...
xml配置
1.配置类
@Configuration
@ImportResource("classpath:aop/example07/aop.xml")
public class AopConfig {
}
2.切面类
public class ReperformanceIntorducer {
}
3.其他注解全部去除
4.xml文件
<?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">
<!-- 启动切面代理 -->
<aop:aspectj-autoproxy/>
<!-- 父接口实现类bean -->
<bean id="performanceImpl" class="com.qhf.aop.example07.PerformanceImpl"/>
<!-- 切面代理类bean -->
<bean id="reperformanceIntorducer" class="com.qhf.aop.example07.ReperformanceIntorducer"/>
<aop:config>
<!-- 相当于@Aspect 注解在声明切面的类 -->
<aop:aspect id="reperformanceIntorducer">
<!-- types-matching:需要添加新功能的父接口 -->
<!-- implement-interface:含新功能的子接口 -->
<!-- default-impl:直接标识委托,即子接口的实现类,通过字节码文件装配,不需要有bean -->
<!-- delegate-ref:间接标识委托,即子接口的实现类,需要有子接口的实现类的bean -->
<aop:declare-parents
types-matching="com.qhf.aop.example07.Performance+"
implement-interface="com.qhf.aop.example07.Reperformance"
default-impl="com.qhf.aop.example07.ReperformanceImpl"/>
</aop:aspect>
</aop:config>
</beans>