JDK和cglib动态代理

动态代理的优点:

  • 可以在不改变源码的情况下,实现对业务方法功能的增强,提高了代码的复用,降低了耦合
  • 简化了编程工作,提高了开发效率,同时提高了软件系统的可扩展性

java动态代理主要就两种方式:

  • JDK 代理 : 基于接口的动态代理技术
  • cglib 代理:基于父类的动态代理技术

下面用计算类例子来说明动态代理技术

1、.不用动态代理的情况下

新建一个计算类Calculator

package org.fyd.spring.proxy.v1;

/**
 * fyd
 * 2023-09-18
 **/
public interface Calculator {

    int add(int a, int b);  // 加法
    int sub(int a, int b);  // 减法
    int mul(int a, int b);  // 乘法
    int div(int a, int b);  // 除法
}

实现类

package org.fyd.spring.proxy.v1;

/**
 * 业务代码和非业务代码混在一起
 */
public class CalculatorImpl implements Calculator {
 
    @Override
    public int add(int a, int b) {
        System.out.println("执行add方法,参数信息:" + a + "," + b);
        int result = a + b;
        System.out.println("add方法执行完毕,计算结果:" + result);
        return result;
    }
 
    @Override
    public int sub(int a, int b) {
        System.out.println("执sub方法,参数信息:" + a + "," + b);
        int result = a - b;
        System.out.println("sub方法执行完毕,计算结果:" + result);
        return result;
    }
 
    @Override
    public int mul(int a, int b) {
        System.out.println("执行mul方法,参数信息:" + a + "," + b);
        int result = a * b;
        System.out.println("mul方法执行完毕,计算结果:" + result);
        return result;
    }
 
    @Override
    public int div(int a, int b) {
        System.out.println("执行div方法,参数信息:" + a + "," + b);
        int result = a / b;
        System.out.println("div方法执行完毕,计算结果:" + result);
        return result;
    }
}

从上面可以看出,每种方法都有打印前和打印后信息,造成了代码冗余和重复,不利于维护

2、使用JDK的动态代理将打印信息抽离出来

package org.fyd.spring.proxy.v2;

import org.fyd.spring.proxy.v1.Calculator;

/**
 * 把业务代码和非业务代码分离
 * jdk 动态代理
 */
public class CalculatorImpl2 implements Calculator {
 
    @Override
    public int add(int a, int b) {
        int result = a + b;
        return result;
    }
 
    @Override
    public int sub(int a, int b) {
        int result = a - b;
        return result;
    }
 
    @Override
    public int mul(int a, int b) {
        int result = a * b;
        return result;
    }
 
    @Override
    public int div(int a, int b) {
        int result = a / b;
        return result;
    }
}

打印信息工具类

package org.fyd.spring.proxy.v2;
 
import java.util.Arrays;
 
public class Logging {
    /**
     * 方法执行前打印参数
     * @param className     类名
     * @param methodName    方法名
     * @param args          执行方法时的参数
     */
    public static void beforeMethod(String className, String methodName, Object[] args){
        System.out.println("执行" + className + "类中的" + methodName + "方法,参数:" + Arrays.toString(args));
    }
 
    /**
     * 方法执行后打印执行结果
     * @param className     类名
     * @param methodName    方法名
     * @param result        方法的返回值
     */
    public static void afterMethod(String className, String methodName, Object result){
        System.out.println(className + "类中的" + methodName + "方法执行完毕,结果:" + result);
    }
}

代理类

package org.fyd.spring.proxy.v2;
 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
public class MyProxy {
 
    // 目标对象,需要增强的对象
    private Object target;
 
    // 有参构造器为目标对象进行赋值
    public MyProxy(Object target) {
        this.target = target;
    }
 
    // 获取代理对象的方法
    public Object getProxyObject(){
        // 代理对象
        Object proxyObject = null;
        // 获取类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 获取目标对象实现的所有接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        // 调用Proxy.newProxyInstance()方法,创建代理对象  new调用处理器
        proxyObject = Proxy.newProxyInstance(classLoader,interfaces, new InvocationHandler() {
            /**
             * @param proxy     代理对象
             * @param method    要执行的方法
             * @param args      执行方法时需要的参数
             * @return  调用目标对象方法后返回的执行结果
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 目标对象类名
                String targetClassName = target.getClass().getName();
                // 要执行的方法名
                String targetMethodName = method.getName();
                // 在方法调用之前,打印方法参数
                Logging.beforeMethod(targetClassName, targetMethodName, args);
                // 调用目标对象的方法
                Object result = method.invoke(target, args);
                // 调用方法之后,输出执行结果
                Logging.afterMethod(targetClassName, targetMethodName, result);
                // 将执行结果返回
                return result;
            }
        });
        // 将代理对象返回
        return proxyObject;
    }
}

3、用cgilib的动态代理

pom导入cglib坐标,如果已经导入spring-core坐标了,就不需要导入cglib坐标了

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

​​​​​​​

package org.fyd.spring.proxy.v3;

import org.fyd.spring.proxy.v1.Calculator;

/**
 * 把业务代码和非业务代码分离
 * cglib动态代理
 */
public class CalculatorImpl3  {
 
    public int add(int a, int b) {
        int result = a + b;
        return result;
    }
 
    public int sub(int a, int b) {
        int result = a - b;
        return result;
    }
 
    public int mul(int a, int b) {
        int result = a * b;
        return result;
    }
 
    public int div(int a, int b) {
        int result = a / b;
        return result;
    }

    @Override
    public String toString() {
        return "CalculatorImpl3{}";
    }
}
package org.fyd.spring.proxy.v3;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.fyd.spring.proxy.v2.Logging;

import java.lang.reflect.Method;

/**
 * fyd
 * 2023-09-18
 **/
public class MyProxy2 {

    private Object target;

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

    public Object getProxyObject(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //target父类   obj是代理后的子类  ,method是调用方法 ,args是方法入参 , proxy是MethodProxy代理对象
//                System.out.println(obj.toString()); //会报错
                System.out.println(target.toString());
                // 目标对象类名
                String targetClassName = target.getClass().getName();
                // 要执行的方法名
                String targetMethodName = method.getName();
                // 在方法调用之前,打印方法参数
                Logging.beforeMethod(targetClassName, targetMethodName, args);
                // 调用目标对象的方法
                Object result = method.invoke(target, args); //正确
//                Object result = methodProxy.invokeSuper(obj, args); //正确
//                Object result = method.invoke(obj, args); //错误
                // 调用方法之后,输出执行结果
                Logging.afterMethod(targetClassName, targetMethodName, result);
                // 将执行结果返回
                return result;
            }
        });
        return enhancer.create();
    }


}

运行类

package org.fyd;

import org.fyd.spring.proxy.v1.Calculator;
import org.fyd.spring.proxy.v1.CalculatorImpl;
import org.fyd.spring.proxy.v2.CalculatorImpl2;
import org.fyd.spring.proxy.v2.MyProxy;
import org.fyd.spring.proxy.v3.CalculatorImpl3;
import org.fyd.spring.proxy.v3.MyProxy2;

/**
 * fyd
 * 2023-09-18
 **/
public class Main {
    public static void main(String[] args) {
//        System.out.println("Hello world!");

        execV3();

    }

    public static void execV1(){
        CalculatorImpl calculator = new CalculatorImpl();
        calculator.add(1,1);
        calculator.sub(2,1);
        calculator.mul(100,2);
        calculator.div(444,2);
    }

    public static void execV2(){
        CalculatorImpl2 calculator = new CalculatorImpl2();
        MyProxy myProxy = new MyProxy(calculator);
        Calculator calculatorImpl2 = (Calculator) myProxy.getProxyObject();
        calculatorImpl2.add(1,3);
        calculatorImpl2.sub(444,4);
        calculatorImpl2.mul(3,7);
        calculatorImpl2.div(555,5);
    }

    public static void execV3(){

        CalculatorImpl3 calculator = new CalculatorImpl3();
        MyProxy2 myProxy = new MyProxy2(calculator);
        CalculatorImpl3 calculatorImpl3 = (CalculatorImpl3) myProxy.getProxyObject();
        calculatorImpl3.add(111,3);
        calculatorImpl3.sub(999,3);
        calculatorImpl3.mul(88,7);
        calculatorImpl3.div(888,2);

    }
}

参考博客:

Java中的动态代理_java动态代理的两种方式_qingfengmax的博客-CSDN博客

java动态代理_飞!!!!的博客-CSDN博客

https://www.cnblogs.com/lvbinbin2yujie/p/10284316.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值