代理主要为代理对象提供一个真实对象的引用,由代理对象控制真实对象的行为,调用者不直接持有真实对象,有代理对象负责调度,类似中介模式。
(1)通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性;
(2)通过代理对象对访问进行控制;
静态代理
静态代理:一般是定义一个接口类或者抽象类,分别有真实对象和代理对象实现
接口类:
public interface Message {
void message();
}
真实对象:
public class TextMessage implements Message{
@Override
public void message() {
System.out.println("this is text!");
}
}
代理对象:
public class MessProxy implements Message{
private Message message = new TextMessage();
@Override
public void sayHello() {
System.out.println("is before invoke" );
message.message();
System.out.println("is after invoke");
}
}
直接调用代理对象即可
MessProxy messProxy = new MessProxy();
messProxy.message();
问题:
静态代理,一对一则会出现时静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代
理对象会出现扩展能力差的问题。
动态代理
在运行时再创建代理类和其实例,因此显然效率更低。要完成这个场景,需要在运行期动态创建一个Class。JDK提 供了 Proxy 来完成这件事情。基本使用如下:
//抽象角色
interface Api {
void test(String a);
}
//真实角色
class ApiImpl{
@Override public void test(String a) {
System.out.println("真实实现:" + a);
}
}
//创建真实角色实例
ApiImpl api = new ApiImpl();
//JDK动态代理:
Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{Api.class}, //JDK实现只能代理接口
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行真实对象方法 、
return method.invoke(api, args);
}
})
实际上, Proxy.newProxyInstance 会创建一个 Class,与静态代理不同,这个 Class 不是由具体的.java源文件编译
而来,即没有真正的文件,只是在内存中按照 Class 格式生成了一个 Class。
String name = Api.class.getName()+"$Proxy0";
//生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Api.class});
FileOutputStream fos = new FileOutputStream("lib/" + name+".class");
fos.write(bytes); fos.close();
在初始化的时候得到所有的方法,在调用方法时,先会调用到生成的代理类的方法,然后通过 我们传入的 InvocationHandler 对象调用 对应的方法,将调用回调出来。