想要更加透彻的理解动态代理,首先要熟悉下静态代理
总结来说:目标类和代理类实现了相同的接口,在代理类中依赖了目标类,代理类的方法中调用了目标类的方法,并做了一些增强性的工作。
要求,在某个类执行类中的方法时,上下文添加一些日志记录
1)定义接口
public interface Calculate {
int add(int num1,int num2);
}
2)定义委托类
public class Calculator implements Calculate {
@Override
public int add(int num1, int num2) {
System.out.println(num1 + "+" + num2 + "=" + num1 + num2);
return num1 + num2;
}
}
3)定义代理类
public class CalculatorWithLog implements Calculate {
private Calculator calculator;
public CalculatorWithLog(Calculator calculator) {
this.calculator = calculator;
}
@Override
public int add(int num1, int num2) {
System.out.println("add前添加一点日志");
int sum = calculator.add(num1, num2);
System.out.println("add后添加一点日志");
return sum;
}
}
4)测试
public static void main(String[] args) {
Calculator calculator = new Calculator();
CalculatorWithLog calculatorWithLog = new CalculatorWithLog(calculator);
calculatorWithLog.add(1, 2);
}
参考B站视频:https://www.bilibili.com/video/BV1HZ4y1p7F1?p=7&vd_source=7f24cfc4e2c729f062d4a78d958bfcdf
动态代理指的是:在程序的执行过程中,使用jdk的反射机制,创建代理对象,并动态的指定代理的目标类
动态代理的实现方式常用有两种:
- 使用JDK代理
- 通过CDLIB代理
jdk动态代理是基于Java的反射机制实现的,使用jdk反射包下的Proxy和InvocationHandler实现代理对象的动态创建
(jdk动态代理要求目标对象必须实现接口)
接口中就一个方法 :invoke()
你的代理类要完成的功能就写在invoke()中
代理类需要完成的功能:
方法原型:
Object proxy:jdk创建的代理对象,无需赋值
Method method:目标类中的方法
Object[] args:目标类中方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
通过Method可以执行某个目标类的方法
是最核心的一个类,使用静态方法 newProxyInstance() ,创建代理对象
方法原型:
ClassLoader loader:类加载器,负责向内存中加载对象(需要使用目标对象的类加载器)
Class>[] interfaces:目标对象实现的接口 InvocationHandler h:我们自己写的代理类需要实现的功能 返回值就是代理对象 public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces,
InvocationHandler h)
public interface Calculate {
int add(int num1,int num2);
}
public class Calculator implements Calculate {
@Override
public int add(int num1, int num2) {
System.out.println(num1 + "+" + num2 + "=" + (num1 + num2));
return num1 + num2;
}
}
public class MyInvocationHandler implements InvocationHandler {
private Object target = null;
//动态代理,目标对象是活动的,不是固定的,需要传入进来
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = method.invoke(target, args);
System.out.println("代理对象中进行功能增强....");
return res;
}
}
public class Test {
public static void main(String[] args) {
//1、创建目标对象
Calculator calculator = new Calculator();
//2、创建invocationHandler对象
InvocationHandler invocationHandler = new MyInvocationHandler(calculator);
Calculate proxyInstance =(Calculate) Proxy.newProxyInstance(calculator.getClass().getClassLoader(), calculator.getClass().getInterfaces(),
invocationHandler);
proxyInstance.add(1, 3);
}
}
断点打到InvocationHandler的invoke方法中,查看method和args参数
Proxy.newProxyInstance() 返回的对象,就是jdk创建的一个代理对象
在不改变原来目标方法功能的前提下,可以在代理中增强自己功能代码。
在程序开发中的意义:
- 你所在的项目中,有一个功能是其他人写好的,你可以使用,但是不能满足我的需求,我需要再增加点代码,这次就需要使用代理
来进行代码的增强,而不用改原来的代码
cglib是第三方的工具库,可以创建代理对象。cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中重写父类中的方法,实现功能的修改
(要求目标类不能是final,且目标类的方法不能是final修饰的)