23种设计模式
8> 代理模式
这篇文章写的较简洁易懂:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
分为静态代理、动态代理。动态代理又有两种实现:JDK动态代理、cglib动态代理
静态代理:
interface Subject {
void request();
}
class RealSubject implements Subject {
public void request(){
System.out.println("RealSubject");
}
}
class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("begin");
subject.request();
System.out.println("end");
}
}
public class ProxyTest {
public static void main(String args[]) {
RealSubject subject = new RealSubject();
Proxy p = new Proxy(subject);
p.request();
}
}
静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。
* 动态代理(JDK动态代理)
interface Subject {
void request();
}
class RealSubject implements Subject {
public void request(){
System.out.println("RealSubject");
}
}
public class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy() {
}
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling method");
method.invoke(obj, args);
System.out.println("after calling method");
return null;
}
客户端
public class Client {
public static void main(String[] args) {
Subject sub = new SubjectImpl();
//这里指定被代理类
InvocationHandler ih = new DynamicProxy(sub);
Class<?> cla = sub.getClass();
//以下是一次性生成代理
Subject subject = (Subject) Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), ih);
//这里可以通过运行结果证明subject是Proxy的一个实例,这个实例实现了Subject接口
System.out.println(subject instanceof Proxy);
System.out.println("subject的Class类是:"+subject.getClass().toString());
System.out.print("subject中的属性有:");
Field[] field = subject.getClass().getDeclaredFields();
for(Field s:field){
System.out.println(s.getName());
}
System.out.print(" "+"subject中的方法有:");
Method[] method=subject.getClass().getDeclaredMethods();
for(Method m:method){
System.out.print(m.getName()+", ");
}
System.out.println(" "+"subject的父类是:"+subject.getClass().getSuperclass());
System.out.print(" "+"subject实现的接口是:");
Class<?>[] interfaces=subject.getClass().getInterfaces();
for(Class<?> i:interfaces){
System.out.print(i.getName()+", ");
}
System.out.println(" "+"运行结果为:");
subject.method();
}
}
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
Ps:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jrelibext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
动态代理
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
动态代理(cglib动态代理)
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
示例:
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
Object obj = enhancer.create();
return obj;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
}
测试类
public class CglibTest {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
SubjectImpl sub = (SubjectImpl) proxy.getProxy(SubjectImpl.class);
sub.method();
}
}