代理模式(Proxy)
a) 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
b) 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问, 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
c) 代理模式一般涉及到的角色有:
(1)抽象角色:声明真实对象和代理对象的共同接口
(2)代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
(3)真实角色:代理角色所代表的真实对象,是我们最终要引用的对象
d) 按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
代理程序示例一:(静态代理)
package com.zp.pattern.proxy;
/**
* 这是接口类:为代理类和委托类提供接口;
*/
public interface Subject {
//为代理对象和真实对象定义一个接口;
public void request();
}
package com.zp.pattern.proxy;
/**
* 委托类:实现接口Subject
*/
public class RealSubject implements Subject{
@Override
public void request() {
System.out.println("realSubjectRequest....");
}
}
package com.zp.pattern.proxy;
/**
* 代理类:实现接口Subject
*/
public class ProxySubject implements Subject {
//对真实对象的引用;
private RealSubject real;
@Override
public void request() {
this.preRequest();//代理对象方法
if(null == real){
real = new RealSubject();
}
real.request();
this.lastRequest();//代理对象方法
}
//下面是代理对象自己的方法,可以放在request()方法中;
public void preRequest(){
System.out.println("proxypreRequest....");
}
public void lastRequest(){
System.out.println("proxylastRequest");
}
}
package com.zp.pattern.proxy;
/**
* 静态代理测试类
*/
public class Test {
public static void main(String[] args) {
ProxySubject p = new ProxySubject();
p.request();
}
}
结果:proxypreRequest....
realSubjectRequest....
proxy lastRequest
代理程序示例二:(动态代理)
package com.zp.pattern.dynamicProxy2;
/**
*接口类
*/
public interface Library {
public void addBook();
}
package com.zp.pattern.dynamicProxy2;
/**
* 委托类:实现了接口Library;
*/
public class LibraryImpl implements Library {
@Override
public void addBook() {
System.out.println("委托类增加图书的方法。。。。");
}
}
package com.zp.pattern.dynamicProxy2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理类:代理对象:$Proxy0(使用反射生成的代理对象,该对象实现了Library接口)
*
* 该代理类的内部属性是Object类型,实际使用的时候通过该类的bind()方法传递进来一个委托
* 对象,返回该委托的代理实例,此外,该类还实现了invoke方法,该方法中的method.invoke
* 其实就是调用被代理对象的将要执行的方法,方法参数是target和args,表示调用target实例* 的方法,该方法的参数是args,通过动态代理类,我们可以在执行委托的方法前后加入自己的一* 些额外方法。
*/
public class DynamicLibraryProxy implements InvocationHandler {
//委托类型的引用:Object类型,可以传入任何类型;
private Object target;
//绑定委托对象,并返回该委托的代理的实例
public Object bind(Object obj){
this.target = obj;
//创建代理对象:$Proxy0,通过委托对象来创建代理对象;
//该代理对象实现了委托对象实现的所有接口:obj.getClass().getInterfaces();
//this代表当前对象;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
obj.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[]args)
throws Throwable {
Object result = null;
System.out.println("代理类事务处理之前方法。。。。");
result = method.invoke(target,args);
System.out.println("代理类事物处理之后方法。。。。");
return result;
}
}
结果:代理类事务处理之前方法。。。。
委托类增加图书的方法。。。。
代理类事物处理之后方法。。。。
代码详解:
a) 静态代理:观察静态代理代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,这就必须使用动态代理完成。
b)动态代理:与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
动态代理详解:
JDK动态代理中包含一个类和一个接口:
(1)InvocationHandler接口(必须实现):
public interface InvocationHandler {
public Object invoke(Object proxy,Method method, Object[] args)
throws Throwable {}
}
参数说明:
Object proxy:指被代理的对象。
Method method:代理要调用的方法。
Object[] args:代理方法调用时所需要的参数。
可以将InvocationHandler接口的子类想象成一个代理的最终操作类。
(2)Proxy类(代理类):
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
newProxyInstance
(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例