代理模式:官方定义,为其他对象提供一个代理以控制对这个对象的访问。形象的说,代理模式就是提供一个代理对象,这个对象有被代理对象的相同的功能,实际上代理对象的功能实现也是通过调用被代理对象的方法实现的。
像c++中的指针对象,Java中的引用对象,也可以看做是一个代理对象,他们代理了所指向和引用的对象。现实中的中介、黄牛也是代理对象,他们是甲方、售票处的代理对象。
静态代理
一个简单的静态代理的例子
一个接口
public interface Mouse {
public void eat();
}
被代理类
public class Jack implements Mouse {
public void eat() {
System.out.println("老鼠吃东西。");
}
}
代理类
public class StatictProxy {
//保存代理对象
private Mouse mouse;
public StatictProxy(Mouse mouse){
this.mouse = mouse;
}
public void eat(){
//执行方法前可以做一些事情
System.out.println("开始代理。。。");
mouse.eat();
//执行方法后可以做一些事情
}
}
缺点:不易扩展,耦合高
动态代理
通过字节码重组生成一个与被代理对象实现相同接口,并且通过一个指定的handler来调度的代理对象。
- JDK的动态代理
JDK代理依赖于java.lang.reflect.InvocationHandler和java.lang.reflect.Proxy这两类。
Proxy是用于生成代理对象,而InvocationHandler则是代理对象执行方法是由其invoke方法来实现的。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy<T> implements InvocationHandler {
//被代理对象
private T t;
//获取代理对象
public T getInstance(T t){
this.t = t;
//获取被代理的类
Class<? > targetClass = t.getClass();
//通过Proxy的newProxyInstance获取代理对象
return (T)Proxy.newProxyInstance(targetClass.getClassLoader(), targetClass.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行代理");
method.invoke(this.t,args);
return null ;
}
}
测试
public static void main(String[] args) {
Object instance = new JDKProxy().getInstance(new Jack());
Mouse mouse = (Mouse) instance;
mouse.eat();
}
- cglib动态代理
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy<T> implements MethodInterceptor {
public T getProxyInstance(Class clazz){
//生成一个代理类
Enhancer enhancer = new Enhancer();
//设置代理类的父类
enhancer.setSuperclass(clazz);
//设置方法调用
enhancer.setCallback(this);
return (T) enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("start proxy");
methodProxy.invokeSuper(o, objects);
return null;
}
}
优势:被代理类可以不用实现接口