java 动态代理(详细图解)
动态代理
就是对象的执行方法,由代理proxy来负责,就比如user.get()方法,是由User对象亲自去执行,而使用代理就是由proxy去执行
-
动态代理和静态代理角色一样 动态代理的代理类是动态生成的,不是我们直接写的 动态代理分类两大类:基于接口的动态代理和基于类的动态代理
基于接口 JDK原生动态代理 基于类:cglib java字节码的动态代理
动态代理具体例子: 参考网站:
接口,有两个对象
public interface Ihello{ void sayHello(String name); void sayGoodBye(String name); }
实现接口类
public class Helloimplements implements IHello{ @Override public void sayHello(String name){ System.out.println("Hello"+name); } @Override public void sayGoodBye(String name){ System.out.println(name+"GoodBye"); } }
现在是多了一个需求,要求在实现类每次问候的时候,把问候的细节记录到日志中,也就是在修改成,在问候前答应一句 System.out.println(“问候之前的日志记录…”)
方法一: 直接在impl实现类上改
public class Helloimplements implements IHello{ @Override public void sayHello(String name){ System.out.println("问候之前的日志记录...") System.out.println("Hello"+name); } @Override public void sayGoodBye(String name){ System.out.println(name+"GoodBye"); } }
可是基本是不允许修改原来的Helloimplements类
方法二: 设计模式中的代理模式:
创建一个Java类作为代理类,实现hello接口,并且把impl的实例 通过一个set方法给传递到代理类中,在代理类上面增加新的功能
完整代码:
public class StaticProxy implements IHello{ //这里有一个新的类 private IHello iHello; public void setImpl(IHello impl){ this.iHello=impl; } @Override public void sayHello(String name){ System.out.println("问候之前的日志记录...") iHello.sayHello(name); } @Override public void sayGoodBye(String name){ iHello.sayGoodBye(name); } public void static main(String[] arg){ Helloimplements hello=new Helloimplements(); StaticProxy proxy=new StaticProxy(); //然后把对应实例引入 proxy.setImpl(hello); proxy.sayHello("Jerry") } }
方法三:动态代理的invocationHandler 其中InvocationHandler(接口)和Proxy(类)是最重要的
invocationHandler接口是proxy代理实例的调用处理程序的一个接口,每一个proxy代理实例都有一个关联的调用处理程序,在代理实例调用方法时,方法调用就会被编码分配到 invcationHandler的invoke方法中 Proxy类就是用来创建一个代理对象的类,其中的newProxyInstance就是最常见的方法
简单来说就是:
- 定义一个InvocationHandler实例,用来实现方法的调用
- 通过Proxy.newProxyInstance()创建实例,其中有三个参数(classloader,接口,用来处理接口方法调用的 invocationHandler(很可能是this))
- 将返回的object强制转型为接口
其中还有一个容易混淆的概念: method.invoke
method.invoke(Object obj,Object args[])的作用就是调用method类代表的方法,其中obj是对象名,args是传入method方法的参数 主要是这个invoke中的参数代表什么,好像是 先知道这个方法是什么,然后就是方法里的参数吧 就像 方法是:
public int intShow (int num) { return num; }
然后先通过反射获得方法: Method method=clazz.getMathod(“intShow”,int.class) //为什么后面这个是int.class 是因为本来也是返回的是class类型的
再进行调用 int num=(int)method.invoke(new InvokeObj(),89)