淺析AOP

對(duì)AOP的簡(jiǎn)單理解

AOP就是面向切面編程,這種方式讓我們有更多精力放在核心業(yè)務(wù)邏輯上,下面這個(gè)圖可以方便我們理解

APO1.png

左圖的驗(yàn)證用戶功能就是每個(gè)操作中的橫切點(diǎn),整個(gè)系統(tǒng)中所有該功能的點(diǎn)連起來(lái)就成為了一個(gè)橫切面,我們可以將這個(gè)功能做成一個(gè)切面類(lèi),當(dāng)其他地方要使用的時(shí)候,直接將其置入里面就好了
這篇博客址講述AOP的實(shí)現(xiàn)方式,并不直接講述SpringAOP的使用方式,當(dāng)然SpringAOP的實(shí)現(xiàn)也用到了后面的動(dòng)態(tài)生成代理類(lèi)原理,如果只想看SpringAOP的簡(jiǎn)單使用請(qǐng)看這篇SpringAOPdemo

實(shí)現(xiàn)AOP的兩種方式(靜態(tài)、動(dòng)態(tài)代理)

靜態(tài)代理

我們首先看一下代理模式的結(jié)構(gòu)類(lèi)圖。Proxy就是我們的代理類(lèi),持有一個(gè)被代理對(duì)象的引用,和被代理對(duì)象共同實(shí)現(xiàn)了我們定義的業(yè)務(wù)接口,靜態(tài)代理就是通過(guò)代理模式來(lái)實(shí)現(xiàn)的


代理模式.png

只簡(jiǎn)單的說(shuō)一下實(shí)現(xiàn)

public interface IBankOperation(){  //銀行業(yè)務(wù)操作接口
    public void drawMoney (int account); //取款
    public int transferMoney(int account); //轉(zhuǎn)賬
}


public class BankOperationImp implement IBankOperation(){//具體實(shí)現(xiàn)
   public void drawMoney(int account){    
        ...                        //實(shí)現(xiàn)查找核心的業(yè)務(wù)邏輯
        xxxDao.drawmoney(account);    //從持久層查找數(shù)據(jù)
        ...
   }
  public int transferMoney(int account){
        ...                       //實(shí)現(xiàn)轉(zhuǎn)帳的核心業(yè)務(wù)邏輯
        xxxDao.transferMoney(account);   //持久層數(shù)據(jù)改變
  }
}

下面我們需要在IBankOperation接口的所有方法操作前進(jìn)行驗(yàn)證操作,變使用代理對(duì)象來(lái)完成驗(yàn)證功能,并持有一個(gè)操作實(shí)現(xiàn)類(lèi)的引用,調(diào)用實(shí)現(xiàn)類(lèi)的方法來(lái)代替執(zhí)行
public class BankOperationProxy implement IBankOperation(){ //銀行操作代理類(lèi)
   BankOperationImp operation;      //持有一個(gè)被代理對(duì)象的引用
   public void validate(){    //驗(yàn)證方法
   }
   public void drawMoney(int account){    
       validate();
       operation.drawMoney(account);
   }
   public int transferMoney(int account){
      validate();
      operation.drawMoney(account);
  }
}

靜態(tài)代理存在明顯的弊端

  1. 一個(gè)代理類(lèi)只能為一個(gè)類(lèi)服務(wù),不同的類(lèi)需要各自的代理類(lèi)
  2. 被代理類(lèi)進(jìn)行了功能的擴(kuò)展,比如實(shí)現(xiàn)了另外一個(gè)接口,我們的代理類(lèi)也需要實(shí)現(xiàn)對(duì)應(yīng)的接口,并作實(shí)現(xiàn)

動(dòng)態(tài)代理(JDKProxy&&CGLibProxy)

package cn.cherish.service;

public interface PersonService {         //業(yè)務(wù)類(lèi)接口
    public void save(String name);
    public void update(String name, Integer personid);
    public String getPersonName(Integer personid);
}
package cn.cherish.service.impl;

import cn.cherish.service.PersonService;

public class PersonServiceBean implements PersonService{ //業(yè)務(wù)實(shí)現(xiàn)類(lèi)
    private String user = null;
    
    public String getUser() {
        return user;
    }

    public PersonServiceBean(){}
    
    public PersonServiceBean(String user){
        this.user = user;
    }

    public String getPersonName(Integer personid) {
        System.out.println("調(diào)用了etPersonName()方法");
        return "xxx";
    }

    public void save(String name) {
        System.out.println("調(diào)用了save()方法");
    }

    public void update(String name, Integer personid) {
        System.out.println("調(diào)用了update()方法");
    }

}

JDKProxy
package cn.cherish.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import cn.cherish.service.impl.PersonServiceBean;

public class JDKProxyFactory implements InvocationHandler{
    private Object targetObject;
    
    public Object createProxyIntance(Object targetObject){
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), 
                this.targetObject.getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {          //環(huán)繞通知
        PersonServiceBean bean = (PersonServiceBean) this.targetObject;
        Object result = null; 
        if(bean.getUser()!=null){
            //..... advice()-->前置通知
            try {
                result = method.invoke(targetObject, args);
                // afteradvice() -->后置通知
            } catch (RuntimeException e) {
                //exceptionadvice()--> 異常通知
            }finally{
                //finallyadvice(); -->最終通知
            }
        }
        return result;
    }
}

簡(jiǎn)單的分析一下上面這段代碼:

  1. 首先我們必須明確,要通過(guò)JDKProxy方式動(dòng)態(tài)獲取到代理對(duì)象,必須實(shí)現(xiàn)InvocationHandler接口,再通過(guò)反射包下的Proxy類(lèi)動(dòng)態(tài)獲取代理對(duì)象
  2. invoke()方法的三個(gè)參數(shù),分別是代理對(duì)象,被代理對(duì)象被調(diào)用的方法,和被調(diào)用方法的參數(shù)集合
  3. Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),this.targetObject.getClass().getInterfaces(), this);這就是我們通過(guò)目標(biāo)對(duì)象生成代理對(duì)象的代碼,三個(gè)類(lèi)分別是被代理對(duì)象的類(lèi)加載器,實(shí)現(xiàn)的接口,以及之后代理對(duì)象需要調(diào)用的方法,this表示被代理對(duì)象方法被調(diào)用時(shí),調(diào)用當(dāng)前類(lèi)的invoke()方法
  4. invoke()方法中判斷用戶不為空之后,method.invoke(targetObject,args)表示調(diào)用targetObject的save()方法這里的method是通過(guò)反射獲取到的當(dāng)前被代理對(duì)象被調(diào)用的方法
  5. 最后注意,雖然method.invoke(targetObject,args)返回值為空,但是我們還是需要返回一下的

測(cè)試結(jié)果:

package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import cn.cherish.aop.CGlibProxyFactory;
import cn.cherish.aop.JDKProxyFactory;
import cn.cherish.service.PersonService;
import cn.cherish.service.impl.PersonServiceBean;

public class AOPTest {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    }

    @Test public void proxyTest(){
        JDKProxyFactory factory = new JDKProxyFactory();
        PersonService service = (PersonService) factory.createProxyIntance(new PersonServiceBean("xxx"));
        service.save("888");
    }
}
結(jié)果:當(dāng)我們給定參數(shù)xxx的時(shí)候,才會(huì)輸出“調(diào)用了save()方法”,因?yàn)槲覀冊(cè)诖韺?duì)象中加入了user字段非空判斷
CGLibProxy

JDK的動(dòng)態(tài)代理機(jī)制只能代理實(shí)現(xiàn)了接口的類(lèi),而不能實(shí)現(xiàn)接口的類(lèi)就不能實(shí)現(xiàn)JDK的動(dòng)態(tài)代理,cglib是針對(duì)類(lèi)來(lái)實(shí)現(xiàn)代理的,他的原理是對(duì)指定的目標(biāo)類(lèi)生成一個(gè)子類(lèi),并覆蓋其中方法實(shí)現(xiàn)增強(qiáng),但因?yàn)椴捎玫氖抢^承,所以不能對(duì)final修飾的類(lèi)進(jìn)行代理。

package cn.cherish.aop;
import java.lang.reflect.Method;
import cn.cherish.service.impl.PersonServiceBean;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGlibProxyFactory implements MethodInterceptor{
    private Object targetObject;
    
    public Object createProxyIntance(Object targetObject){
        this.targetObject = targetObject;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.targetObject.getClass());//非final
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy  methodProxy) throws Throwable {
        PersonServiceBean bean = (PersonServiceBean) this.targetObject;
        Object result = null;
        if(bean.getUser()!=null){
            result = methodProxy.invoke(targetObject, args);
        }
        return result;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容