动态代理
就是对象的执行方法,由代理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)