动态代理的两种方式以及区别

Posted 追梦ღ少年᭄ꦿ࿐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理的两种方式以及区别相关的知识,希望对你有一定的参考价值。

JDK动态代理

* 基于JDK动态代理
	使用前提:
        基于JDK动态代理 - 代理类和被代理之间是兄弟级别关系
            1.有顶层接口
            2.有接口实现类
接口
/**
 * 顶层接口
 */
public interface Dog {
    public void wang();

    public void eat(String food);

    public String dance();
}
实现类(切点所在类)
/**
 *  接口实现类(被代理类)
 */
public class HaShiQi implements Dog {
    public void wang() {
        System.out.println("wang...");
    }

    public void eat(String food) {
        System.out.println("吃了" + food + "...");
    }

    public String dance() {
        return "跳舞...";
    }
}
测试代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *  测试类
 */
public class JDKProxyTest {
    public static void main(String[] args) {
        //哈士奇是准备被增强对象
        final HaShiQi hsq = new HaShiQi();

        /**
         *  动态代理核心代码
         *      Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
         *      参数:
         *          ClassLoader loader      - 使用被代理对象的类加载器
         *          Class<?>[] interfaces   - 使用被代理对象实现的接口数组
         *          InvocationHandler h     - 执行处理器
         *      返回值:
         *
         */
        Dog JiXieHSQ = (Dog) Proxy.newProxyInstance(hsq.getClass().getClassLoader(), hsq.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 只要代理对象有任何方法执行,该方法都会运行
             * @param proxy     表示最终生成的代理对象
             * @param method    表示当前代理对象正在执行的方法
             * @param args      表示当前代理对象正在执行的方法的参数
             * @return          表示当前代理对象正在执行的方法的返回值
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //针对不同方法进行增强
                String methodName = method.getName();
                if("wang".equals(methodName)){
                    //前置增强
                    System.out.println("机械哈士奇喝了2两...");
                    //想要实现原有逻辑
                    Object result = method.invoke(hsq, args);
                    //后置增强
                    System.out.println("喝完吐了...");
                    return result;
                }else if("eat".equals(methodName)){
                    //前置增强
                    System.out.println("机械哈士奇喝了2两...");
                    //对于参数进行增强
                    args[0] = "香肠 + 火腿";
                    //想要实现原有逻辑
                    Object result = method.invoke(hsq, args);
                    //后置增强
                    System.out.println("打个嗝,睡了...");
                    return result;
                }else if("dance".equals(methodName)){
                    Object result = method.invoke(hsq, args);
                    return "唱..." + result + "rap...篮球...";
                }else {
                    //其他方法按照原有逻辑实现
                    return method.invoke(hsq, args);
                }
            }
        });

        //JiXieHSQ.wang();
        //JiXieHSQ.eat("香肠");
        String result = JiXieHSQ.dance();
        System.out.println(result);
    }
}

CGlib动态代理

* 基于CGlib动态代理
	使用前提:
        基于CGlib动态代理 - 代理类和被代理之间是父子级别关系
        	有父类(继承体系中)
        	
* CGlib动态代理实现步骤
        1.需要创建一个增强者对象
        2.设置要增强的父类对象
        3.设置方法拦截的回调函数
        4.获取代理对象,调用方法
父类(切点所在类)
/**
 * 顶层父类
 */
public class Cat {
    public void miao(){
        System.out.println("miao...");
    }
}
测试代码
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGlibProxyTest {
    public static void main(String[] args) {
        final Cat cat = new Cat();

        //1.创建一个增强者对象
        Enhancer enhancer = new Enhancer();
        //2.设置增强父类对象
        enhancer.setSuperclass(cat.getClass());
        //3.设置增强回调函数
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * 只要代理对象有任何方法执行,该方法都会运行
             * @param proxy         表示最终生成的代理对象
             * @param method        表示当前代理对象正在执行的方法
             * @param args          表示当前代理对象正在执行的方法的参数
             * @return              表示当前代理对象正在执行的方法的返回值
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                /*if("xxx".equals(method.getName())){
                    args[0] = "猫罐头";
                    return "吃吃吃吃...";
                }*/
                System.out.println("喝了2两...");
                Object result = method.invoke(cat, args);
                System.out.println("吐了...");
                return result;
            }
        });

        //4.构建增强对象
        Cat pop = (Cat) enhancer.create();
        pop.miao();
    }
}

以上是关于动态代理的两种方式以及区别的主要内容,如果未能解决你的问题,请参考以下文章

Spring的两种动态代理:Jdk和Cglib 的区别和实现

Spring的两种动态代理:Jdk和Cglib 的区别和实现

java的动态代理的两种方式和spring的aop面向切面编程的对比

动态代理的两种方式

MyBatis开发Dao层的两种方式(Mapper动态代理方式)

MyBatis开发Dao层的两种方式(Mapper动态代理方式)