动态代理-CGlib和JDK动态代理

重温jdk动态代理和cglib代理的区别:

jdk动态代理

  1. 实现InvocationHandler接口,重写invoke方法,加上自己想要的逻辑代码。
  2. 创建代理目标对象
  3. 通过Proxy.newInstance(classLoader,interfaces,InvocationHandler子类);去创建代理类,之后强转或者使用泛型方法。
  4. 通过代理类来进行方法的调用。

要求:代理类和目标对象需要实现同一个接口!!!

可以看出,jdk动态代理依赖于其实现了接口,并且对接口进行“增强”。若类不实现一个接口时,则无法使用jdk动态代理。

cglib就是弥补了jdk动态代理的不足。

 

CGLib

  1. 实现MethodInterceptor接口,重写intercept方法对代理对象的方法进行拦截。
  2. 通过创建Enhance(增强)来设置超类,去通过enhance.create()创建代理对象的子类,对超类中的方法进行拦截,从而实现自己额外的业务逻辑(性能检测,权限控制,事务,日志等)。

原理:通过动态生成复杂的字节码,创建目标类的子类,进行代理实现。final修饰的类不能进行代理。

 

JDK动态代理通过反射调用目标对象,cglib采用类似索引的方式直接调用目标对象中的方法。

JAVA实现

JDKDynamic 代理:

package com.logan;

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

/**
 * JDK 动态代理:被代理的对象需要实现一个接口,代理类对被代理类的方法进行拦截,在实际执行被代理类的方法前后,加上日志,事务,权限控制等。。
 *
 * 1.事务,日志,权限控制是和业务逻辑不相干的,它们是垂直正交的关系。则可看做AOP中的"切面"。
 * 2.切入的方法,比如在Dao层所有的add*,update*,delete*之前的方法加上事务,成功了就提交事务,失败了就回滚。
 *   可称之为切点 CutPoint
 *
 *
 * JDK 动态代理 : spring 中默认使用JDK动态代理,若想使用CGLib,则需要配置  默认为false
 * 随着JDK版本的不断升级,最开始jdk动态代理的效率逐渐在提高。
 *
 * 优点:
 * 1.对比静态代理来说,动态代理可以代码复用。
 * 2.使用静态代理时,如果代理类和被代理类同时实现了一个接口,当接口方法有变动时,代理类也必须同时修改。
 *
 * 缺点:
 * 1.只能代理实现了接口的类,否则将不能使用JDK 动态代理。
 *
 *
 * @author logan
 *
 * @Date 2019年04月20日15:12:42
 *
 */
public class JDKDynamicProxy implements InvocationHandler {

    private Object target;

    public JDKDynamicProxy(Object target){
        this.target = target;
    }

    public  T getProxy(){
        return  (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                this.target.getClass().getInterfaces(), this);
    }



    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk dynamic proxy before .....");
        long startTime = System.currentTimeMillis();
        Object object = method.invoke(target, args);
        long endTime = System.currentTimeMillis();
        System.out.println("jdk dynamic proxy after .....");
        System.out.println("jdk dynamic proxy spend time is " + (endTime - startTime) );
        return object;
    }

}

CGLib Demo :

package com.logan;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


/**
 *
 * CGLibProxy demo
 *
 * 为了弥补JDK动态代理的不足,cglib代理在底层字节码的基础上创建类,因为需要动态的去创建类,所以创建类所花费的时间要大于JDK动态代理
 * 若一次创建,多次服务,那么效果还是比较好的。
 *
 *
 * @author logan
 */
public class CGLibProxy implements MethodInterceptor {

    private Object target;
    private Enhancer enhancer = new Enhancer();

    public CGLibProxy(Object target){
        this.target = target;
    }

    /**
     * get proxy object
     * @param 
     * @return
     */
    public  T getProxy(){
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return (T) enhancer.create();
    }


    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("proxy before .....");
        long startTime = System.currentTimeMillis();
        //Object object = methodProxy.invoke(target, args);
        Object object = methodProxy.invokeSupper(o, args);
        long endTime = System.currentTimeMillis();
        System.out.println("proxy after .....");
        System.out.println("spend time is " + (endTime - startTime) );
        return object;
    }
}

 

测试接口:

package com.logan;

public interface IMaster {

    void sayHello(String name);

    String select(String name);

}

测试实现类:

package com.logan;

public class Master implements IMaster {

    public void sayHello(String name){
        System.out.println("Hello, " + name);
    }

    public String select(String name){
        return "name = " + name;
    }

}

Tester类:

package com.logan;


/**
 * 测试类
 */
public class Tester {

    public static void main(String[] args) {

        IMaster master = new CGLibProxy(new Master()).getProxy();
        master.sayHello("Logan");
        System.out.println(master.select("Nancy"));
        System.out.println("=============");

        IMaster proxyMaster = new JDKDynamicProxy(new Master()).getProxy();
        proxyMaster.sayHello("xiaoma");
        System.out.println(proxyMaster.select("123"));

    }

}

 

 

 

你可能感兴趣的:(Java,规范)