java动态代理

很久没写java代码了,继上次写完反射后我么这次来学习一下动态代理。

熟悉设计模式的人对于代理模式可 能都不陌生。 代理对象和被代理对象一般实现相同的接口,调用者与代理对象进行交互。

原始接口

public interface Calculator {
    public Integer add(Integer num1, Integer num2);
    public Integer minus(Integer num1, Integer num2);
}

被代理类

public class CalculatorImpl implements Calculator {
 
    @Override
    public Integer add(Integer num1, Integer num2) {
        int ret = num1 + num2;
        System.out.println("in calculatorImpl, res: " + ret);
        return ret;
    }
     
    @Override
    public Integer minus(Integer num1, Integer num2) {
        int ret = num1 - num2;
        System.out.println("int calculatorImpl, res: " + ret);
        return ret;
    }
 }

如上面所说代理对象和被代理对象一般实现相同的接口。
代理类

public class StaticCalculatorProxy implements Calculator {
    Calculator obj;
     
    public StaticCalculatorProxy(Calculator obj) {
        this.obj = obj; 
    }
 
    @Override
    public Integer add(Integer num1, Integer num2) {
        System.out.println("in StaticCalculatorProxy, before invocation");
        Integer ret = obj.add(num1, num2);
        System.out.println("in StaticCalculatorProxy, after invocation");
        return ret;
    }
 
    @Override
    public Integer minus(Integer num1, Integer num2) {
        System.out.println("in StaticCalculatorProxy, before invocation");
        Integer ret = obj.minus(num1, num2);
        System.out.println("in StaticCalculatorProxy, after invocation");
        return ret;
    }
 }

我们可以看到委托类和代理类都实现了同一个接口,这种称为静态代理。

  • 静态代理:代理类是在编译时就实现好的。也就是说 Java 编译完成后代理类是一个实际的 class 文件。

java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy) 
 
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces) 
 
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl) 
 
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, 
    InvocationHandler h)

java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
Object invoke(Object proxy, Method method, Object[] args)
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler handler)
{
    //1. 根据类加载器和接口创建代理类
    Class clazz = Proxy.getProxyClass(loader, interfaces); 
    //2. 获得代理类的带参数的构造函数
    Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });
    //3. 创建代理对象,并制定调用处理器实例为参数传入
    Interface Proxy = (Interface)constructor.newInstance(new Object[] {handler});
}

简化的动态代理对象创建过程

// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
InvocationHandler handler = new InvocationHandlerImpl(..); 
 
// 通过 Proxy 直接创建动态代理类实例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, 
     new Class[] { Interface.class }, 
     handler );

所以接下来我们要写一个

public class CalculatorHandler implements InvocationHandler {
     
    private Object obj; //被代理类
     
    public CalculatorHandler(Object obj) {
        this.obj = obj;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("in calculatorhandler, before invocation");
         
        Object ret = method.invoke(obj, args);  //执行被代理类方法
         
        System.out.println("in calculationhandler, after invocation");
        return ret;
    }
 }

最后要通过proxy的静态方法newProxyInstance来实现动态代理。

CalculatorImpl calculatorImpl = new CalculatorImpl();//被代理类
CalculatorHandler calculatorHandler = new CalculatorHandler(calculatorImpl);
Calculator calculator = (Calculator) Proxy.newProxyInstance(calculatorImpl.getClass().getClassLoader(), calculatorImpl.getClass().getInterfaces(), calculatorHandler);
System.out.println(calculator.add(1,2));
System.out.println(calculator.minus(1, 2));

最后附上一段干货

Object array = Array.newInstance(String.class, 10); //等价于 new String[10]
Array.set(array, 0, "Hello");  //等价于array[0] = "Hello"
Array.set(array, 1, "World");  //等价于array[1] = "World"
System.out.println(Array.get(array, 0));  //等价于array[0]

你可能感兴趣的:(java动态代理)