java動態代理 cglib之間的關系


什么是aop?

 

aop(Aspect Oriented Programming)面向切面編程。是oop面向對象思想的一種補充和延續。也是Spring框架的一種重要的組件!

 

Spring中Aop代理是由SpringIOC容器負責生成、管理,其依賴關系也是由IOC容器負責處理的。

 

在Spring中,默認情況下是使用java動態代理技術來實現

 

當需要代理的類不是接口類型的時候,Spring會自動切換為CGLIB來進行代理,也可以強制的選擇使用CGLIB來進行代理

 

可以看一下SpringAOP的源代碼

package org.springframework.aop.framework;

import java.io.Serializable;
import java.lang.reflect.Proxy;

import org.springframework.aop.SpringProxy;


@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
  //創建Aop代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      //判斷配置是否有效,配置中有代理類信息,判斷有沒有用戶自己定義的解析接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); }
        //如果是接口,或者Proxy的類,返回默認的JDK動態代理對象
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); }
        //配置中有用戶自己指定的代理信息,則使用cglib進行代理
return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }

首先從通過配置信息解析有沒有指定的解析方法。

 

如果配置信息中沒有的話,就使用默認的JdkDynamicAopProxy()來進行代理

 

好了,現在知道了Spring在什么情況下使用什么代理。下面開始深入了解一下jdk代理和cglib代理吧

 

動態代理是jdk1.5引進的新的技術。動態代理的類位於Java.lang.reflect包下

先舉個栗子!

BookStore.java
public interface BookStore {
     public void addBook();  
     public void deleteBook();
}

還有一個實現該接口的實現類

BookStoreImpl.java
package test;

public class BookStoreImpl implements BookStore {

    public void addBook() {
        System.out.println("增加圖書方法。。。");
    }

    public void deleteBook() {
        System.out.println("我現在要刪除一個書");

    }

}
BookStoreProxy.java
package test;

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

public class BookStoreProxy implements InvocationHandler {
    private Object target;

    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object result = null;

        System.out.println("代理事務開始啦");
        result = method.invoke(target, args);
        System.out.println("代理事務結束啦");
        return result;
    }

}

測試一下

package test;

public class TestProxy {
    public static void main(String[] args) {
        BookStoreProxy proxy = new BookStoreProxy();
        BookStore bs = (BookStore) proxy.bind(new BookStoreImpl());
        bs.addBook();
        System.out.println("-------------------");
        bs.deleteBook();
    }

}

輸出結果

代理事務開始啦
增加圖書方法。。。
代理事務結束啦
-------------------
代理事務開始啦
我現在要刪除一個書
代理事務結束啦

 

從測試的過程中可以看到,我們沒有改變原來的那個BookStore接口和BookStoreImpl實現類。

 

但是實現了方法的注入

 

這就是動態代理了,它的作用有以下幾點

  1.Proxy類的代碼量可以降下來,不會因為業務的增大而龐大起來

  2.可以實現aop編程,雖然靜態代理也可以實現

  3.降低耦合性,通過參數就可以判斷真實的類,不需要事先實例化,比較靈活

 

jdk代理很好啊,但是仔細想一下還是有缺陷啊,Proxy類只能代理接口類

 

所以cglib(Code generation Library)就出現了,完美的拓展了proxy的性能,它可以代理接口的和類。碉堡了

 

再舉個栗子!

 

action.java

package cglib.test;

public class Action {
    public void playGame(){
        System.out.println("上班玩游戲...");
    }
    public void smoke(){
        System.out.println("上班抽煙...");
    }
}

ActionFactory.java

package cglib.test;

public class ActionFactory {
    public static Action action = new Action();
    
    public static Action getActionInstance(){
        return action;
    }
}

ActionTest.java

package cglib.test;

import org.junit.Before;
import org.junit.Test;

public class ActionTest {

    @Before
    public void setUp() throws Exception {
    }

    @Test
    public void test() {
        Action action = ActionFactory.getActionInstance();
        action.playGame();
        action.smoke();
    }
}

 

好了,運行沒有問題。playGame和smoke兩個動作可以完成,但是新的需求來了

老板說,只有他能在上班的時候玩游戲!之前的類不能動!

用jdk中的動態代理當然可以實現,但是我們這沒有Action的接口。要是使用jdk動態代理的話,我們還需要創建新的接口!老板說了不能動原來的類。

所以我們選用cglib

 

再搞一個

ActionCglibProxy.java
package cglib.test;

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 ActionCglibProxy implements MethodInterceptor {

    private String name;

    private Enhancer enhancer = new Enhancer();

    public ActionCglibProxy(String name) {
        super();
        this.name = name;
    }

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if ("zhyonk".equals(name)) {
            Object result = proxy.invokeSuper(obj, args);
            return result;
        }
        System.out.println(name + "你不可以抽煙哦");
        return null;
    }
    public Action getAction(){
        enhancer.setSuperclass(Action.class);
        enhancer.setCallback(this);
        return (Action) enhancer.create();
    }
}

 

 

測試一下

    @Test
    public void TestCglibAction() {
        ActionCglibProxy proxy = new ActionCglibProxy("老板");
        Action action = proxy.getAction();
        action.playGame();
        action.smoke();
    }

 

成功代理了,這個過程中沒有用到接口。

 

通過Enhancer進行對類的注入。

 

getAction()返回的是原有的被代理類Action的子類

 

暫時就是這樣啦!

 


免責聲明!

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



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