代理分为静态代理和动态代理。
- 静态代理
可以看下面代码
/**
* 静态代理中代理类和委托类也常常继承同一父类或实现同一接口。
* 普通业务类
* 通过接口更加灵活实现代理模式
*/
public interface Subject {
void visit();
}
/**
* 委托类
* 代理类和真实业务类都需要实现业务类的接口
*/
public class RealSubject implements Subject{
@Override
public void visit() {
//真实业务具体逻辑
System.out.println("Real Subject");
}
}
/**
* 代理类
* 代理类和委托类都需要实现业务类的接口
*/
public class ProxySubject implements Subject {
private Subject iSubject;//委托类
public ProxySubject(Subject subject){
//关键:关联委托类
this.iSubject = subject;
}
@Override
public void visit() {
//调用真实业务类的方法
iSubject.visit();
}
}
public class Client {
public static void main(String[] args){
//构造一个真实主题对象
RealSubject realSubject = new RealSubject();
//通过真实主题对象构造一个代理对象
ProxySubject proxySubject = new ProxySubject(realSubject);
//调用代理类的相关方法
proxySubject.visit();
}
}
其实可以看个几个关键点:
- 代理类和委托类公共实现同一个接口。(其实我觉得这个不是必然的。代理类可以不实现接口。而委托类实现接口是基于面向接口编程这个原则,实现接口使编程更加灵活而已)
- 这个是核心:就是代理类构建实例需要关联委托类。这样才能调用代理方法,实则是调用委托类的方法实现功能。
其实静态代理:在实际中不方便直接构建委托对象,而需要代理类实现具体的方法。
- 动态代理
public interface DynamicInterface {
//实现逻辑
void implement();
}
/**
委托类
* 实现接口
*/
public class DynamicRealSubject implements DynamicInterface{
@Override
public void implement() {
Log.e("DynamicRealSubject","DynamicRealSubject___动态代理模式");
}
}
/**
* 实现InvocationHandler的类是运行时将生成的代理类需要完成的具体任务即invoke方法里面
* 动态代理
*/
public class DynamicProxySubject implements InvocationHandler{
private Object sub;//需要被代理的对象
public DynamicProxySubject(Object sub){
this.sub = sub;
}
public DynamicProxySubject(){}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("DynamicProxySubject","动态代理前");
//真正被代理类的方法被调用 method就是被代理的类的方法
method.invoke(sub,args);
//proxy这个参数在方法里写会内存溢出
// method.invoke(proxy,args);
Log.e("DynamicProxySubject","动态代理后");
return null;
}
}
//实现结果
public static void main(String[] args) throws Exception {
DynamicRealSubject realSubject = new DynamicRealSubject();
InvocationHandler handler = new DynamicProxySubject(realSubject);
//一次性生成
DynamicInterface subject = (DynamicInterface)Proxy
.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);
//实现动态代理被代理类的方法
subject.implement();
}
- java JDK就提供了实现动态代理的方法。涉及到两个类:
1、InvocationHandler 实现委托类的方法的一个接口
2、Proxy 代理类
动态代理与静态代理最大的不同就是代理类非程序员预先定义好,而是在运行时才生成代理类。
实现InvocationHandler接口的类提示:
我开始时候以为实现InvocationHandler接口的就是代理类,其实是错误的。该类其实提供给Proxy类构造时关联用到的。每当生成代理类实例调用代理方法就会调用实现InvocationHandler接口的类中的invoke方法。
- 这里构造函数需要关联一下委托类。目的就是在invoke方法里面通过反射调用委托类的方法,其实实现的目的与静态类是一致的。
- invoke有三个参数 Object这个是代理类。Method 就是通过Proxy生成实例接口里面的方法。而args数组就是method的参数
看看这个InvocationHandler类到底如何与Proxy有联系的
DynamicRealSubject realSubject = new DynamicRealSubject();
InvocationHandler handler = new DynamicProxySubject(realSubject);
Class cls = realSubject.getClass();
DynamicInterface subject =
(DynamicInterface)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);
这样就将InvocationHandler类与Proxy类关联起来。
看看Proxy.newProxyInstance这个方法是做什么的
看到了cl这个变量明显就是一个类对象然后在生成构造函数再构建对象。构建对象时通过h即InvocationHandler这个实例关联一起。整个过程就是这样生成一个代理实例。
看看getProxyClass0方法生成类对象
Paste_Image.png
由于该方法太长截取关键部分:
这里的generateProxy就是生成类对象,之前的代码是进行缓存。
看看生成代理对象那代码:
Paste_Image.png Paste_Image.png生成代理对象时,把InvocationHandler实例传进去
所以它最终生成的代理类是会有InvocationHandler的痕迹的。这里我看了网上的说,生成的代理类是继承Proxy实现委托接口。在代理方法里面InvocationHandler通过反射调用invoke方法。
网友评论