IntroductionInterceptor

對於之前介紹過的 Before Advice After Advice Around Advice Throw Advice ,從使用者的角度來看,它們「影響了目標物件上某些方法的行為」,例如讓某些方法看來似乎增加了一些記錄的動作。

Introduction是個特別的Advice,從使用者的角度來看,它「影響了目標物件的行為定義,直接增加了目標物件的職責(具體來說就是增加了可 操作的方法)」,例如讓某個已定義好的物件,在不修改該物件之類別檔案的情況下,卻可以增加一些額外的操作方法到物件之上。

就Java程式語言類別設計的觀點來說,動態為物件增加可操作的方法顯得不可思議,事實上在Spring AOP中,您可以透過實作org.springframework.aop.IntroductionInterceptor來實現Introduction。

IntroductionInterceptor繼承了MethodInterceptor與DynamicIntroductionAdvice介面, 其中implementsInterface()方法(繼承自DynamicIntroductionAdvice)如果返回true的話,表示目前的 IntroductionInterceptor實作了給定的介面(也就是要額外增加行為的介面),此時您要使用invoke()呼叫介面上的方法,讓目 標物件執行額外的行為,您不可能使用MethodInvocation的proceed()方法,因為您要執行的是物件上原來沒有的行為,呼叫 proceed()方法沒有意義。

從文字上來理解Introduction會比較抽象,舉個實際的例子來說,假設您的系統中已經有以下的類別:
  • ISome.java
package onlyfun.caterpillar;

public interface ISome {
    public void doSome();
}

  • Some.java
package onlyfun.caterpillar;

public class Some implements ISome { 
    public void doSome() {
        System.out.println("原來物件的職責。。。");
    }
}

您希望在不修改原始檔案的情況下,為Some類別增加一些可操作的方法,也許您甚至連原始碼檔案都沒有,只有.class檔案,您唯一知道的也許是他們的API說明,在不對它們作出修改的情況下,您希望Some類別可以增加doOther()方法。

在Spring中,您可以藉由實作IntroductionInterceptor介面來完成上面的任務,首先您為doOther()方法建立介面:
  • IOther.java
package onlyfun.caterpillar; 

public interface IOther {  
    public void doOther();
}

接著定義一個OtherIntroduction類別實作IntroductionInterceptor介面,並在實作IntroductionInterceptor介面的同時,也實作IOther介面,例如:
  • OtherIntroduction.java
package onlyfun.caterpillar;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.IntroductionInterceptor;

public class OtherIntroduction 
              implements IntroductionInterceptor, IOther {   
    // 是否實作自IOther介面
    public boolean implementsInterface(Class clazz) {
        return clazz.isAssignableFrom(IOther.class);
    }
    
    public Object invoke(MethodInvocation methodInvocation) 
                                      throws Throwable {
        // 如果呼叫的方法來自IOther介面的定義
        if(implementsInterface(
            methodInvocation.getMethod().getDeclaringClass())) {
            // 呼叫執行額外加入(mixin)的行為
            return methodInvocation.getMethod().
                    invoke(this, methodInvocation.getArguments());
        }
        else {
            return methodInvocation.proceed();
        }
    }
    
    public void doOther() {
        System.out.println("增加的職責。。。");
    }
}

接著您要在Bean定義檔中將Introduction縫合至Some物件之上,使用org.springframework.aop.support.DefaultIntroductionAdvisor就可以了,例如:
  • beans-config.xml
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" 
  "http://www.springframework.org/dtd/spring-beans.dtd"> 

<beans> 
    <bean id="some" 
          class="onlyfun.caterpillar.Some"/> 

    <bean id="otherIntroduction" 
          class="onlyfun.caterpillar.OtherIntroduction"/> 
          
    <bean id="otherAdvisor" 
          class="org.springframework.aop.support.DefaultIntroductionAdvisor"> 
          <constructor-arg index="0">
              <ref bean="otherIntroduction"/>
          </constructor-arg>  
          <constructor-arg index="1">
              <value>onlyfun.caterpillar.IOther</value>
          </constructor-arg>  
    </bean>
   
    <bean id="proxyFactoryBean" 
          class="org.springframework.aop.framework.ProxyFactoryBean"> 
        <property name="proxyInterfaces"> 
            <value>onlyfun.caterpillar.ISome</value> 
        </property> 
        <property name="target"> 
            <ref bean="some"/> 
        </property> 
        <property name="interceptorNames"> 
            <list> 
                <value>otherAdvisor</value> 
            </list> 
        </property> 
    </bean> 
</beans>

DefaultIntroductionAdvisor在建構時,需要給它IntroductionInterceptor的實例,以及所要代理額外行為的介面,現在,來撰寫一個簡單的程式測試,從這個程式當中,您可以更進一步了解何謂為物件額外增加行為:
  • SpringAOPDemo.java
package onlyfun.caterpillar;

import org.springframework.context.ApplicationContext;
import org.springframework.context.
              support.FileSystemXmlApplicationContext;

public class SpringAOPDemo {
    public static void main(String[] args) {
        ApplicationContext context = 
            new FileSystemXmlApplicationContext(
                    "beans-config.xml"); 
    
        ISome some = 
            (ISome) context.getBean("proxyFactoryBean"); 
    
        some.doSome();
    
        // 看來好像some物件動態增加了職責
        ((IOther) some).doOther();
    }
} 

對於some所參考的物件來說,它原先並不會有doOther()方法可供操作,然而透過Spring AOP的Introduction機制,現在some所參考的物件多了doOther()方法可以操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: AOP中的introduction是用于给目标引入新的接口的功能。它可以通过IntroductionInterceptor接口来实现。通过实现该接口,我们可以在目标对象上添加新的接口,比如锁、状态功能等。实现一个introduction需要三个内容:将要添加的新接口的定义、该新接口的实现以及实现类中必须实现Spring的IntroductionInterceptor接口和IntroductionAdvisor接口。\[3\]在使用introduction时,我们可以通过调用implementsInterface方法来判断该introduction实现是否实现了目标接口类,并通过invoke方法来完成相应的任务。\[3\]总的来说,introduction是AOP中的一种功能,用于给目标对象引入新的接口。 #### 引用[.reference_title] - *1* *3* [Spring AOP中的introduction介绍](https://blog.csdn.net/JewaveOxford/article/details/107283525)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Spring AOP 之 Introductions](https://blog.csdn.net/weixin_42041788/article/details/107282565)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值