在前面的切面學習中,注意到可以在對象.方法運行前後引入切面,執行通知代碼,這本來就執行了多個方法,看起來卻是像是對象的多個方法。切面只是實現了它們所包裝的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>