JDK動態代理與CGLIB代理

AOP 即面向切面編程。通常用來處理具有橫切性質的系統級別服務,比如事務,安全,緩存等。


AOP 代理主要分爲兩大類:

靜態代理:使用 AOP 框架提供的命令進行編譯,從而在編譯階段就可生成 AOP 代理類,因此也稱爲編譯時增強;靜態代理以 AspectJ 爲代表。

動態代理:在運行時藉助於 JDK 動態代理、CGLIB 等在內存中“臨時”生成 AOP 動態代理類,因此也被稱爲運行時增強。Spring AOP 用的就是 動態代理。


AspectJ靜態代理就不介紹了。


下面介紹動態代理的兩種方式。

第一種:JDK動態代理

代碼如下

接口

package com.cbf4life;

/**
 * Created by Maggie on 2017/6/7.
 */
public interface Bean {
    void print();
}
實現累

package com.cbf4life.common;

import com.cbf4life.Bean;

/**
 * Created by Maggie on 2017/6/7.
 */
public class TargetBean implements Bean{
    private String name;

    public TargetBean(){}

    public TargetBean(String name){this.name = name;}

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void print(){
        System.out.println("hello world");
    }
}

代理工廠

package com.cbf4life;

import com.cbf4life.common.TargetBean;

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

/**
 * Created by Maggie on 2017/6/7.
 */
public class ProxyFactory implements InvocationHandler {

    private Object bean;
    public Object createBeanProxy(Object be){
        this.bean = be;
        return Proxy.newProxyInstance(be.getClass().getClassLoader(),
                be.getClass().getInterfaces(), this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        TargetBean s = (TargetBean)bean;
        Object object = null;
        if(s.getName() != null)
            object = method.invoke(bean, args);
        else
            System.out.println("名字爲空,代理類已經攔截!");
        return object;
    }
}

這就是JDK動態代理,下面是解釋

  • 目標對象必須實現接口。
  • 調用Proxy.newProxyInstance()方法,返回創建的代理對象。
  • 由於該方法需要一個實現了InvocationHandler接口的對象,所以我們還要重寫該接口的invoke()方法。
  • 我們的限制條件就可以放在這個invoke()方法中,當滿足條件,就調用method.invoke()真正的調用目標對象的方法,否則,不做任何事情,直接過濾。

第二種:CGLIB動態代理

需要jar包:

代碼實例

package com.cbf4life;

import com.cbf4life.common.TargetBean;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.annotation.Target;
import java.lang.reflect.Method;

/**
 * Created by Maggie on 2017/6/7.
 */
public class CGlibProxyFactory implements MethodInterceptor {

    private Object object;
    public Object createTargetBean(Object object){
        this.object = object;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    public Object getObject() {
        return object;
    }
    public void setObject(Object object) {
        this.object = object;
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args,
                            MethodProxy methodProxy) throws Throwable {
        TargetBean stu = (TargetBean)object;
        Object result = null;
        if(stu.getName() != null)
            result = methodProxy.invoke(object, args);
        else
            System.out.println("方法已經被攔截...");
        return result;
    }


}

總體來說,使用CGlib的方法和使用Proxy的方法差不多,只是Proxy創建出來的代理對象和目標對象都實現了同一個接口。而CGlib的方法則是直接繼承了目標對象。


下面是main方法的測試

public static void main(String[] args) {
    Bean stu1 = (Bean)(new ProxyFactory().createBeanProxy(new TargetBean()));
    Bean stu2 = (Bean)(new ProxyFactory().createBeanProxy(new TargetBean("aaa")));
    TargetBean stu3 = (TargetBean)(new CGlibProxyFactory().createTargetBean(new TargetBean()));
    TargetBean stu4 = (TargetBean)(new CGlibProxyFactory().createTargetBean(new TargetBean("aaa")));
    stu1.print();
    stu2.print();
    stu3.print();
    stu4.print();
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章