设计模式-代理模式(8)
代理模式也叫做委托模式, 它是一项基本设计技巧。而且在日常的应用中, 代理模式可以提供非常好的访问控制。
代理模式的优点
● 职责清晰
真实的角色就是实现实际的业务逻辑, 不用关心其他非本职责的事务, 通过后期的代理完成一件事务, 附带的结果就是编程简洁清晰。
● 高扩展性
具体主题角色是随时都会发生变化的, 只要它实现了接口, 甭管它如何变化, 都逃不脱如来佛的手掌(接口) , 那我们的代理类完全就可以在不做任何修改的情况下使用。
● 智能化
这在我们以上的讲解中还没有体现出来, 不过在我们以下的动态代理章节中你就会看到代理的智能化有兴趣的读者也可以看看Struts是如何把表单元素映射到对象上的。
代理模式的使用场景
非常典型的动态代理Spring AOP
代理模式的实现方式
静态代理
JDK动态代理
CGLib动态代理
静态代理
/**
* @Title: Subject
* @Description: 目标
* @author chy
* @date 2018/5/12 16:23
*/
public interface Subject {
public void request();
}
/**
* @Title: RealSubject
* @Description: 代理目标
* @author chy
* @date 2018/5/12 16:23
*/
public class RealSubject implements Subject {
public void request(){
System.out.println("Real subject invoked!");
}
}
/**
* @Title: Proxy
* @Description:代理
* @author chy
* @date 2018/5/12 16:23
*/
public class Proxy implements Subject{
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("Proxy start invoked!");
subject.request();
System.out.println("Proxy end invoked!");
}
}
/**
* @Title: Client
* @Description: 静态代理
代理模式: 为其他对象提供一种代理以控制对这个对象的访问。
关键词: 控制
打个比方,好比犯人被囚禁起来,犯人在做什么事之前和之后,都在监狱警察的监控中。
* @author chy
* @date 2018/5/12 16:44
*/
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy(new RealSubject());
proxy.request();
}
}
JDK动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理
/**
* @Title: Proxy
* @Description: JDK动态代理
* @author chy
* @date 2018/3/22 15:06
*/
public class DynamicProxy implements InvocationHandler {
private Object tar;
/**
* 绑定委托对象,并返回代理类
* @param tar
* @return
*/
public Object bind(Object tar)
{
this.tar = tar;
//绑定该类实现的所有接口,取得代理类
return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
tar.getClass().getInterfaces(),
this);
}
/**
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
public Object invoke(Object proxy , Method method , Object[] args)throws Throwable
{
Object result = null;
System.out.println("Proxy start invoked!");
//这里就可以进行所谓的AOP编程了
//在调用具体函数方法前,执行功能处理
result = method.invoke(tar,args);
System.out.println("Proxy start invoked!");
//在调用具体函数方法后,执行功能处理
return result;
}
}
public class Client {
public static void main(String[] args) {
DynamicProxy proxy = new DynamicProxy();
Subject subject = (Subject) proxy.bind(new RealSubject());
subject.request();
}
}
CGLIB动态代理
cglib是针对类来实现代理的
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,
并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,
但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,
因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。
同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
public class DynamicProxy implements MethodInterceptor {
/**
* 业务类对象,供代理方法中进行真正的业务方法调用
*/
private Object target;
/**
* 相当于JDK动态代理中的绑定
* @param target
* @return
*/
public Object getInstance(Object target) {
//给业务对象赋值
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
/**
* 实现回调方法
* @param obj
* @param method
* @param args
* @param proxy
* @return
* @throws Throwable
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Proxy start invoked!");
//调用业务类(父类中)的方法
proxy.invokeSuper(obj, args);
System.out.println("Proxy start invoked!");
return null;
}
}
public class Client {
public static void main(String[] args) {
DynamicProxy proxy = new DynamicProxy();
Subject subject = (Subject) proxy.getInstance(new RealSubject());
subject.request();
}
}