简介
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口,即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
类图
1.静态代理
/**
* 抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口
* @author: 张彬
* @date: 2018年6月4日 下午3:27:30
* @version: V1.0
* @review: 张彬/2018年6月4日 下午3:27:30
*/
public interface Subject {
void visit();
}
/**
* 真实主题角色,是实现抽象主题接口的委托类。
* @author: 张彬
* @date: 2018年6月4日 下午3:28:47
* @version: V1.0
* @review: 张彬/2018年6月4日 下午3:28:47
*/
public class RealSubject implements Subject {
@Override
public void visit() {
System.out.println("in RealSubject");
}
}
/**
* 代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。
* 同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
* @author: 张彬
* @date: 2018年6月4日 下午3:29:47
* @version: V1.0
* @review: 张彬/2018年6月4日 下午3:29:47
*/
public class ProxySubject implements Subject{
private RealSubject subject;
@Override
public void visit() {
System.out.println("静态代理开始");
if(subject==null) subject = new RealSubject();
subject.visit();
System.out.println("静态代理结束");
}
}
/**
* 静态代理测试
* 代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
* @author: 张彬
* @date: 2018年6月4日 下午3:30:53
* @version: V1.0
* @review: 张彬/2018年6月4日 下午3:30:53
*/
public class Client {
public static void main(String[] args) {
ProxySubject subject = new ProxySubject();
subject.visit();
}
}
输出结果:
静态代理开始
in RealSubject
静态代理结束
2.动态代理-JDK
/**
* 动态代理类,实现InvocationHandler接口,并重写该invoke方法
* @author: 张彬
* @date: 2018年6月4日 下午3:34:55
* @version: V1.0
* @review: 张彬/2018年6月4日 下午3:34:55
*/
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理开始");
Object result = method.invoke(object, args);
System.out.println("动态代理结束");
return result;
}
}
/**
* 动态代理测试
* Subject接口与RealSubject实现类不再重敲与 1.静态代理 相同
* 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象,代理接口InvocationHandler所在包:java.lang.reflect.Proxy
* @author: 张彬
* @date: 2018年6月4日 下午3:36:35
* @version: V1.0
* @review: 张彬/2018年6月4日 下午3:36:35
*/
public class ClientJDK {
public static void main(String[] args) {
// 创建一个实例对象,这个对象是被代理的真实对象
Subject realSubject = new RealSubject();
// ,创建一个与代理对象相关联的InvocationHandler动态代理对象
InvocationHandler proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
// 创建一个代理对象subject来代理realSubject,代理对象的每个执行方法都会替换执行proxy中的invoke方法
//classLoader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
//Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
//proxy:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy);
//代理执行真实对象的方法
subject.visit();
}
}
输出结果:
动态代理开始
in RealSubject
动态代理结束
3.动态代理-cglib
/**
* 使用cglib动态代理
* 有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
* 需要引入cglib的jar文件,Spring的核心包中已经包括了Cglib功能:Spring-core-3.2.5.jar
* @author: 张彬
* @date: 2018年6月4日 下午4:23:58
* @version: V1.0
* @review: 张彬/2018年6月4日 下午4:23:58
*/
public class CGLibProxy implements MethodInterceptor {
private Object targetObject;// CGLib需要代理的目标对象
/**
* 创建代理对象
* @param obj
* @return
*/
public Object getInstance(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass());
enhancer.setCallback(this);
return enhancer.create();// 返回代理对象
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib开始...");
Object result = method.invoke(targetObject, args);
System.out.println("cglib结束...");
return result;
}
}
/**
* cglib测试
* @author: 张彬
* @date: 2018年6月4日 下午4:35:08
* @version: V1.0
* @review: 张彬/2018年6月4日 下午4:35:08
*/
public class ClientCglib {
public static void main(String[] args) {
CGLibProxy cglib=new CGLibProxy();
RealSubject bookCglib=(RealSubject)cglib.getInstance(new RealSubject());
bookCglib.visit();
}
}
输出结果:
cglib开始...
in RealSubject
cglib结束...
总结
优点:1、职责清晰。2、高扩展性。3、智能化。
缺点:1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
静态代理:优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.
动态代理:
JDK:代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理;对于没有实现接口的类,不便使用该方方式实现动态代理
cglib:代理的类不能为final,否则报错,目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
dong