InvocationHandler動態代理(反射機制) 切面


JDK動態代理,根據實體類生成代理對象,由該實體類的接口變量接收,進而調用接口方法
1,代理對象可以在被代理者代碼執行前后增加額外邏輯
2,被代理者發生變化,代理類不需改動
org.apache.ibatis.plugin.Interceptor代理思路:
1,@Intercepts({@Signature(method="prepare",type=StatementHandler.class,args ={Connection.class})}) 
2,針對StatementHandler類prepare方法的調用進行攔截(攔住就返回代理對象,未攔住返回原對象繼續執行原對象方法)
3,在代理對象的invoke方法中調用Interceptor的intercept(new Invocation(target, method, args))方法
4,intercept方法對真實對象target處理,最后調用.proceed()方法,進行反射機制調用method.invoke(target, args)

 

抽象角色:聲明真實對象和代理對象的共同接口,這樣可在任何使用真實對象的地方都可以使用代理對象。
  代理角色:代理對象內部含有真實對象的引用,從而可以在任何時候操作真實對象。代理對象提供一個與真實對象相同的接口,以便可以在任何時候替代真實對象。代理對象通常在客戶端調用傳遞給真實對象之前或之后,執行某個操作,而不是單純地將調用傳遞給真實對象,同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當於對真實對象進行封裝。
  真實角色:即為代理對象所代表的目標對象,代理角色所代表的真實對象,是我們最終要引用的對象。

https://www.cnblogs.com/LCcnblogs/p/6823982.html

靜態代理
interface Subject//抽象角色
{  
    public void doSomething();  
}
class RealSubject implements Subject//真實角色
{  
    public void doSomething()  
  {  
    System.out.println( "call doSomething()" );  
  }  
}
class SubjectProxy implements Subject//代理角色
{
  //代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。
  Subject subimpl = new RealSubject();
  public void doSomething()
  {
     System.out.println("before"); //調用目標對象之前可以做相關操作
     subimpl.doSomething();
     System.out.println("after");//調用目標對象之后可以做相關操作
  }
}
 
public class Test
{
    public static void main(String[] args) throws Exception
    {
        Subject sub = new SubjectProxy();
        sub.doSomething();
    }
}

 


可以看到,SubjectProxy實現了Subject接口(和RealSubject實現相同接口),並持有的是Subject接口類型的引用。這樣調用的依然是doSomething方法,只是實例化對象的過程改變了,結果來看,代理類SubjectProxy可以自動為我們加上了before和after等我們需要的動作。
如果將來需要實現一個新的接口,就需要在代理類里再寫該接口的實現方法,對導致代理類的代碼變得臃腫;另一方面,當需要改變抽象角色接口時,無疑真實角色和代理角色也需要改變。

JDK動態代理

interface Subject  
{  
    public void doSomething();  
}
class RealSubject implements Subject  
{  
    public void doSomething()  
  {  
     System.out.println( "call doSomething()" );  
  }  
}
class ProxyHandler implements InvocationHandler
{
    private Object tar;
    //綁定委托對象,並返回代理類
    public Object bind(Object tar)
    {
        this.tar = tar;
        //綁定該類實現的所有接口,取得代理類
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
                                      tar.getClass().getInterfaces(),
                                      this);
    }   
    public Object invoke(Object proxy , Method method , Object[] args)throws Throwable//不依賴具體接口實現
    {
        Object result = null;//被代理的類型為Object基類

        String decName = method.getDeclaringClass().getName();//獲取接口
        //這里就可以進行所謂的AOP編程了
        //在調用具體函數方法前,執行功能處理
        result = method.invoke(tar,args);
        //在調用具體函數方法后,執行功能處理
        return result;
    }
}
public class Test
{
    public static void main(String args[])
    {
           ProxyHandler proxy = new ProxyHandler();
           //綁定該類實現的所有接口
           Subject sub = (Subject) proxy.bind(new RealSubject());
           sub.doSomething();
    }
}

 


在調用過程中使用了通用的代理類包裝了RealSubject實例,然后調用了Jdk的代理工廠方法實例化了一個具體的代理類。最后調用代理的doSomething方法,還有附加的before、after方法可以被任意復用(只要我們在調用代碼處使用這個通用代理類去包裝任意想要需要包裝的被代理類即可)。當接口改變的時候,雖然被代理類需要改變,但是我們的代理類卻不用改變了。這個調用雖然足夠靈活,可以動態生成一個具體的代理類,而不用自己顯示的創建一個實現具體接口的代理類。



切面不能對接口做

org.aspectj.lang.JoinPoint:
<bean class="cn.com.xmh.gcoin.util.AccountTransactionAspect" id="accountTransactionAspect" />
    <aop:config>
    <!-- 定義切面,所有的service的所有方法 ,被MybatisRepository注解標識的
        <aop:pointcut id="txPointcut" expression="execution(* xx.xxx.xxxxxxx.service.*.*(..)) and @annotation(cn.com.xmh.gcoin.MybatisRepository)" />-->
        <aop:pointcut id="txPointcut" expression="execution(* cn.com.xmh.gcoin.logic.impl.QueryUseryTransactionsLogic.*(..)) " />

        <!-- 將切面應用到自定義的切面處理器上,-9999保證該切面優先級最高執行 -->
        <aop:aspect ref="accountTransactionAspect" order="-9999">
            <aop:before method="before" pointcut-ref="txPointcut" />
        </aop:aspect>
    </aop:config>
public class AccountTransactionAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
     public void before(JoinPoint point) {
           // 獲取到當前執行的方法名
           logger.info("****************進入AccountTransactionAspect切面");
           String methodName = point.getSignature().getName();            
            if("insert".equals(methodName)){
                TblAccountTransaction tblAccountTransaction = (TblAccountTransaction)(point.getArgs()[0]);
                tblAccountTransaction.setTbl(ConsistentHashingWithTable.getServer(tblAccountTransaction.getUserNo()));
            }
        }

org.aopalliance.intercept.MethodInterceptor:
<bean class="cn.com.xmh.gcoin.util.ClassInterceptor" id="classInterceptor"></bean>
    <aop:config>
        <!-- 定義切面,所有的service的所有方法 -->
        <aop:pointcut id="classPointcut" expression="execution(* cn.com.xmh.gcoin.logic.impl.QueryUseryTransactionsLogic.*(..)) " />

        <aop:advisor advice-ref="classInterceptor" pointcut-ref="classPointcut" />
        <!-- 將切面應用到自定義的切面處理器上,-9999保證該切面優先級最高執行
        <aop:aspect ref="accountTransactionAspect" order="-9999">
            <aop:before method="before" pointcut-ref="txPointcut" />
        </aop:aspect>-->
    </aop:config>
public class ClassInterceptor  implements MethodInterceptor{  
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("******"+invocation.getArguments());
        Object result = invocation.proceed();  
        System.out.println("*****");
        return null;
    }  
} 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM