Spring-代理

Spring-代理

存在一个类,实现两个数的加减乘除功能,并想在功能实现的前后加上日志,日志内容为进行了什么操作,输出结果是什么

我们可以在每一个方法中,使用print的方式来打印日志,但这十分麻烦且有大量的冗余代码

使用代理模式来解决这个问题

public interface Calculator {
    
    int add(int i, int j);
    
    int sub(int i, int j);
    
    int mul(int i, int j);
    
    int div(int i, int j);
    
}
import org.springframework.stereotype.Component;

@Component
public class CalculatorPureImpl implements Calculator {
    
    @Override
    public int add(int i, int j) {
    
        int result = i + j;
    
        return result;
    }
    
    @Override
    public int sub(int i, int j) {
    
        int result = i - j;
    
        return result;
    }
    
    @Override
    public int mul(int i, int j) {
    
        int result = i * j;
    
        return result;
    }
    
    @Override
    public int div(int i, int j) {
    
        int result = i / j;
    
        return result;
    }
}

静态代理

新建一个代理类同样实现功能接口,但代理类不做具体的功能实现,只负责日志的打印

将实现类作为代理类的属性,并在构造方法将实现类注入到代理类中

在重写的功能方法中,先打印所需要的日志,再调用实现类中的方法去完成具体的功能实现

public class CalculatorStaticProxy implements Calculator {

    Calculator calculator = new CalculatorPureImpl();

    public CalculatorStaticProxy(Calculator calculator) {
        this.calculator = calculator;
    }

    @Override
    public int add(int i, int j) {
        System.out.println("i = " + i + ", j = " + j);
        int result = calculator.add(i, j);
        System.out.println("result = " + result);
        return result;
    }

    @Override
    public int sub(int i, int j) {
        System.out.println("i = " + i + ", j = " + j);
        int result = calculator.sub(i, j);
        System.out.println("result = " + result);
        return result;
    }

    @Override
    public int mul(int i, int j) {
        System.out.println("i = " + i + ", j = " + j);
        int result = calculator.mul(i, j);
        System.out.println("result = " + result);
        return result;
    }

    @Override
    public int div(int i, int j) {
        System.out.println("i = " + i + ", j = " + j);
        int result = calculator.div(i, j);
        System.out.println("result = " + result);
        return result;
    }
}

动态代理

JDK动态代理:JDK提供了原生的动态代理的实现方式,他必须需要被代理的实现类的接口,会根据接口动态生成一个代理对象

cglib:第三方技术(被Spring集成),通过被代理的实现类直接生成一个代理类,不需要实现类的接口


JDK动态代理

尚硅谷提供了一个基于JDK动态代理的生成工具类

和静态代理类一样,将实现类对象作为代理类的属性注入,在这里为了实现动态,类的类型是Object

Proxy.newProxyInstance()方法需要三个参数

  • classLoader:实现类的类加载器
  • interfaces:实现类的接口
  • invocationHandler:具体的代理类的功能类,其参数需要重写抽象方法,其中具体的实现使用到反射
    • 抽象方法提供了三个参数,proxy(实现类的对象),method(实现类的功能方法),args(方法所对应的参数)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class ProxyFactory {

    private Object target;

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

    public Object getProxy(){

        /**
         * newProxyInstance():创建一个代理实例
         * 其中有三个参数:
         * 1、classLoader:加载动态生成的代理类的类加载器
         * 2、interfaces:目标对象实现的所有接口的class对象所组成的数组
         * 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法
         */
        ClassLoader classLoader = target.getClass().getClassLoader(); // 获取到实现类的类加载器
        Class<?>[] interfaces = target.getClass().getInterfaces(); // 获取实现类的接口
        InvocationHandler invocationHandler = new InvocationHandler() {
            // 通过匿名内部类的方式重写了InvocationHandler的抽象方法invoke
            // 这个方法就是代理类具体要做的事
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /**
                 * proxy:代理对象
                 * method:代理对象需要实现的方法,即其中需要重写的方法
                 * args:method所对应方法的参数
                 */
                Object result = null;
                try {
                    System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                    result = method.invoke(target, args);
                    System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
                } finally {
                    System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                }
                return result;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

AOP框架就是封装了动态代理技术