代理的目的是什么?
不修改函数代码同时扩展函数的功能
代理实现有几种?
静态代理和动态代理
静态代理是啥?
比如有个A类,里面有个b函数,处理事情c,返回结果d
class A{
public String b() {
System.out.println("c...");
return "d";
}
}
//怎么调用?
A a=new A();
a.b();
如果现在有一个需求:不改变A类的b方法里面的代码,但是又要扩展b函数的功能,要有一些新功能,你咋整?可能的思路有这么几个1、写一个E类继承A然后重写b方法 2、写一个F类,F持有A的实例,F也有一个b方法,F的b方法里面会调用A的b方法,同时F的b方法还有一些新功能代码。其实思路1就是继承出现的原因,思路2就是代理出现的原因,我们写出思路2的代码
class E{
class A a;
E (A az){
a=az;
}
public String b() {
insertNew();//这里插入新功能代码
String z=a.b();//我们调用了A类的b函数
return z;
}
}
//怎么调用?
A a=new A();
E e=new E(a);
e.b();
//很明显,我们调用E的b函数的时候,除了会完成A的b函数方法之外,还会完成新功能代码
那以前调用是A.b,现在调用是E.b这样子就需要修改调用方法的地方,那怎么做到不需要修改调用者呢?接口就出现了。
public interface G{
public String b();
}
我们将有b函数的类抽象成为一个接口,所有实现了b函数的类,都可以用接口来调用,当然我们看下修改后的代码
class A implements G{
public String b() {
System.out.println("c...");
return "d";
}
}
//怎么调用?
G g=new A();
g.b();
class E implements G{
class A a;
E (G az){
a=az;
}
public String b() {
insertNew();//这里插入新功能代码
String z=a.b();//我们调用了A类的b函数
return z;
}
}
//怎么调用?
G a=new A();
G g=new E(a);
g.b();//这就是接口调用
动态代理是啥
回顾下静态代理,总结就是:代理类和原始类实现同一个接口、在代理类中持有原始类、代理类的方法中调用原始类的函数(同时可以写新功能代码扩充功能)。静态代理就一个个这样子实现,动态代理就是任意给一个类自动实现这种代理模式。动态到底啥意思?就是动态创建对象,动态调用函数。
怎么动态创建类?
Proxy类newProxyInstance的就可以动态创建类的对象。
怎么动态调用函数?
InvocationHandler接口的invoke就可以动态调用函数
public class Proxy implements java.io.Serializable {
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
我们跟踪Proxy 和InvocationHandler 源码发现,Proxy可以帮助我们动态创建类,代理类和原始类都实现了InvocationHandler接口的invoke方法,这样子就实现了动态代理。我们看个具体的例子
public class E implements InvocationHandler{
//代理类中的真实对象
private Object obj;
public E() {
}
//构造函数,给我们的真实对象赋值
public E(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在真实的对象执行之前我们可以添加自己的操作
System.out.println("before invoke。。。");
Object invoke = method.invoke(obj, args);
//在真实的对象执行之后我们可以添加自己的操作
System.out.println("after invoke。。。");
return invoke;
}
}
//怎么调用
//新建原始类的对象
Object target =new A();
//指明动态调用的函数
TransactionHandler handler =new InvocationHandler(a);
//动态生成代理类
G g= (G)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),handler);
//接口进行方法调用
g.b();
动态代理的本质
其实动态代理的本质,就是将写静态代理的代码的过程的交给编译器帮我们去实现了。我们编译程序之后找到E.class字节码,然后用JD打开就可以看到java代码,其实里面的和我们手动写的静态代理代码差不多。
参考资料
Java动态代理详解 https://v.ixigua.com/ecVBtkS/
JDK动态代理的底层实现之Proxy源码分析 https://www.cnblogs.com/liuyun1995/p/8157098.html