Java動態代理機制

(1)什麼是代理?java

大道理上講代理是一種軟件設計模式,目的地但願能作到代碼重用。具體上講,代理這種設計模式是經過不直接訪問被代理對象的方式,而訪問被代理對象的方法。這個就比如 商戶---->明星經紀人(代理)---->明星這種模式。咱們能夠不經過直接與明星對話的狀況下,而經過明星經紀人(代理)與其產生間接對話。spring

 

(2)什麼狀況下使用代理?編程

(1)設計模式中有一個設計原則是開閉原則,是說對修改關閉對擴展開放,咱們在工做中有時會接手不少前人的代碼,裏面代碼邏輯讓人摸不着頭腦(sometimes the code is really like shit),這時就很難去下手修改代碼,那麼這時咱們就能夠經過代理對類進行加強。設計模式

(2)咱們在使用RPC框架的時候,框架自己並不能提早知道各個業務方要調用哪些接口的哪些方法 。那麼這個時候,就可用經過動態代理的方式來創建一箇中間人給客戶端使用,也方便框架進行搭建邏輯,某種程度上也是客戶端代碼和框架鬆耦合的一種表現。框架

(3)Spring的AOP機制就是採用動態代理的機制來實現切面編程。ide

 

(3)靜態代理和動態代理性能

咱們根據加載被代理類的時機不一樣,將代理分爲靜態代理和動態代理。若是咱們在代碼編譯時就肯定了被代理的類是哪個,那麼就能夠直接使用靜態代理;若是不能肯定,那麼可使用類的動態加載機制,在代碼運行期間加載被代理的類這就是動態代理,好比RPC框架和Spring AOP機制this

 

(4)動態代理類型spa

  • JDK動態代理
  • CGLIB動態代理

JDK動態代理示例設計

public interface Manager {
    public void modify(String msg);
}

public class ManagerImpl implements Manager {
    @Override
    public void modify(String msg) {
        System.out.println("*******modify()方法被調用" + msg);
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class BusinessHandler implements InvocationHandler {
    public Object delagate = null;
    
    public Object bind(Object obj){
        this.delagate = obj;
        return Proxy.newProxyInstance(this.delagate.getClass().getClassLoader(), this.delagate.getClass().getInterfaces(), this);
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("do something before method");
        Object ret = method.invoke(this.delagate, args);
        System.out.println("do something after method");
        return ret;
    }
}


public class TestJDKProxy {
    public static void main(String[] args) {
        // 元對象(被代理對象)
        ManagerImpl managerImpl = new ManagerImpl();

        // 業務代理類
        BusinessHandler securityHandler = new BusinessHandler();
        Manager managerProxy = (Manager) securityHandler.bind(managerImpl);
        managerProxy.modify("hello steve!");
    }
}

  

CGLIB動態代理示例

public interface BookFacade {
    public void addBook(); 
}

public class BookFacadeImpl implements BookFacade {
    @Override
    public void addBook() {
        System.out.println("增長圖書的普通方法...");  
    }
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class BookFacadeCglib implements MethodInterceptor {
    private Object target;

    /**
     * 建立代理對象
     * 
     * @param target
     * @return
     */
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回調方法  
        enhancer.setCallback(this);
        // 建立代理對象  
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("事物開始");
        proxy.invokeSuper(obj, args);
        System.out.println("事物結束");
        return null;
    }
}
public class TestCglib {
    public static void main(String[] args) {
        BookFacadeCglib cglib = new BookFacadeCglib();
        BookFacade bookCglib = (BookFacade) cglib.getInstance(new BookFacadeImpl());
        bookCglib.addBook();
    }
}

  

二者區別

1、簡單來講:

  1. JDK動態代理只能對實現了接口的類生成代理,而不能針對類
  2. CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法(繼承)

2、Spring在選擇用JDK仍是CGLiB的依據:

  1. 當Bean實現接口時,Spring就會用JDK的動態代理
  2. 當Bean沒有實現接口時,Spring使用CGlib是實現
  3. 能夠強制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

3、CGlib比JDK快?

  1. 使用CGLib實現動態代理,CGLib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類,比使用Java反射效率要高。惟一須要注意的是,CGLib不能對聲明爲final的方法進行代理,由於CGLib原理是動態生成被代理類的子類。
  2. 在對JDK動態代理與CGlib動態代理的代碼實驗中看,1W次執行下,JDK7及8的動態代理性能比CGlib要好20%左右。
相關文章
相關標籤/搜索