1.为什么要动态代理
现在有这样一个需求:在聊天系统中,把每一个所说的话记录到日志文件里面,初学者可能是这样来设计
在speak方法中调用log方法,记录到数据库。这样设计有明显的不足:1、log方法不应该属于Person类中 2、如果改类库已经编译,我们就不能修改原有代码,在其方法内部增加代码。此时,有经验的开发者可能会想到代理模式。我们修改一下类图
我们将讲话给抽象出来,客户端使用接口声明,LogProxy与Person依赖,共同实现Speak接口,然后在LogPersonProxy中实现记录日志,这样就可以解决之前的问题。但是新问题又来了:我们必须为为委托类维护一个代理,不易管理而且增加了代码量。
2.JDK中的动态代理
JAVA的动态代理机制可以动态的创建代理并动态的处理代理方法调用,只要简单指定一组接口及为拖累对象,就能动态的获取代理类,JAVA已经给我们提供了强大的支持,其具体实现可以参照马士兵的动态代理视频。核心类是Proxy,负责创建所有代理类,并且创建的代理类都是其子类,而且这些子类继承所代理的一组接口,因此它就可以安全的转换成需要的类型,进行方法调用。InvocationHandler是调用处理器的接口,它自定义了一个invoke方法,用于机制处理在动态代理类上的方法调用,通常在该方法中实现对委托类的代理访问。相关类图如下
具体代理要实现InvocationHandler接口详细代码如下
我们可以在invoke方法中接到一下参数:Object proxy, Method method, Object[] args
其中,proxy是被代理的类,第二个参数表示被执行的委托方法,第三个参数表被执行的委托方法,我们在客户端测试一下,代码如下
现在有这样一个需求:在聊天系统中,把每一个所说的话记录到日志文件里面,初学者可能是这样来设计
在speak方法中调用log方法,记录到数据库。这样设计有明显的不足:1、log方法不应该属于Person类中 2、如果改类库已经编译,我们就不能修改原有代码,在其方法内部增加代码。此时,有经验的开发者可能会想到代理模式。我们修改一下类图
我们将讲话给抽象出来,客户端使用接口声明,LogProxy与Person依赖,共同实现Speak接口,然后在LogPersonProxy中实现记录日志,这样就可以解决之前的问题。但是新问题又来了:我们必须为为委托类维护一个代理,不易管理而且增加了代码量。
2.JDK中的动态代理
JAVA的动态代理机制可以动态的创建代理并动态的处理代理方法调用,只要简单指定一组接口及为拖累对象,就能动态的获取代理类,JAVA已经给我们提供了强大的支持,其具体实现可以参照马士兵的动态代理视频。核心类是Proxy,负责创建所有代理类,并且创建的代理类都是其子类,而且这些子类继承所代理的一组接口,因此它就可以安全的转换成需要的类型,进行方法调用。InvocationHandler是调用处理器的接口,它自定义了一个invoke方法,用于机制处理在动态代理类上的方法调用,通常在该方法中实现对委托类的代理访问。相关类图如下
具体代理要实现InvocationHandler接口详细代码如下
public class LogProxy implements InvocationHandler {
private Object object;
public LogProxy(Object object) {
super();
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
method.invoke(this.object, args);
System.out.println("记录到数据库..");
return null;
}
public void setObject(Object object) {
this.object = object;
}
public Object getObject() {
return object;
}
}
public class PowerProxy implements InvocationHandler {
private Object object;
public PowerProxy(Object object) {
super();
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("进行权限验证..是否是黑名单..");
method.invoke(this.object, args);
return null;
}
public void setObject(Object object) {
this.object = object;
}
public Object getObject() {
return object;
}
}
我们可以在invoke方法中接到一下参数:Object proxy, Method method, Object[] args
其中,proxy是被代理的类,第二个参数表示被执行的委托方法,第三个参数表被执行的委托方法,我们在客户端测试一下,代码如下