Spring實戰08——爲bean對象引入新方法

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章