源码地址|https://github.com/DingMouRen/DesignPattern
代理模式:在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
静态代理类
在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式。
/**
* 抽象接口
*/
public interface Manager {
void doSomething();
}
/**
* 被代理类
*/
public class Admin implements Manager{
@Override
public void doSomething() {
System.out.println("Admin--doSomething");
}
}
/**
* 代理类
*/
public class AdminProxy1 implements Manager {
private Admin admin;
public AdminProxy1(Admin admin) {
this.admin = admin;
}
@Override
public void doSomething() {
System.out.println("adminProxy1 -- doSomething");
admin.doSomething();
}
}
/**
* 代理类
*/
public class AdminProxy2 implements Manager {
private Admin admin;
public AdminProxy2(Admin admin) {
this.admin = admin;
}
@Override
public void doSomething() {
System.out.println("adminProxy2 -- doSomething");
admin.doSomething();
}
}
/**
* 使用类
*/
public class Client {
public static void main(String[] args) {
Admin admin = new Admin();
//代理1执行
AdminProxy1 adminProxy1 = new AdminProxy1(admin);
adminProxy1.doSomething();
//代理2执行
AdminProxy2 adminProxy2 = new AdminProxy2(admin);
adminProxy2.doSomething();
}
}
缺点:静态代理中,需要将被代理类中所有的方法实现一遍,并且为每个方法附加相似的代码逻辑;另外如果要添加的附加功能
的类有多个,需要针对每个类创建一个代理类,增加维护成本。
动态代理
不用事先为每个原始类编写代理类,而是在运行的时候,动态的创建原始类对应的代理类,然后在系统中庸代理类替换原始类。
Java 语言本身就已经提供了动态代理的语法。
/**
* 抽象接口
*/
public interface Moveable {
void move();
}
/**
* 被代理类
*/
public class Car implements Moveable {
@Override
public void move() {
System.out.println("汽车行驶中...");
}
}
/**
* 事务处理器
*/
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
this.target = target;
}
/**
*
* @param proxy 被代理的对象
* @param method 被代理对象的方法
* @param args 方法参数
* @return 方法返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("汽车开始行驶");
method.invoke(target,args);
long stopTime = System.currentTimeMillis();
System.out.println("汽车结束行驶");
System.out.println("汽车行驶时间:"+(stopTime - startTime)+"毫秒");
return null;
}
}
/**
* 使用类
*/
public class Client {
public static void main(String[] args) {
Car car = new Car();
ClassLoader classLoader = car.getClass().getClassLoader();
Class<?>[] clsArr = car.getClass().getInterfaces();
InvocationHandler handler = new TimeHandler(car);
Moveable moveable = (Moveable) Proxy.newProxyInstance(classLoader,
clsArr,
handler);
moveable.move();
}
}
cglib代理
cglib代理使用需要引入额外的jar包 cglib.jar
/**
* 被代理类
*/
public class Train {
public void move(){
System.out.println("火车行驶中...");
}
}
/**
* 代理类
*/
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* @param obj 目标实例对象,被代理类
* @param method 被代理类的反射对象
* @param args 方法参数
* @param methodProxy 代理类的实例
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("日志开始");
methodProxy.invokeSuper(obj,args);
System.out.println("日志结束");
return null;
}
}
/**
* 使用类
*/
public class Client {
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
Train train = (Train) proxy.getProxy(Train.class);
train.move();
}
}
代理模式的应用场景
- 在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、日志等。我们将这些附加功能与业务功能解耦,放在代理类中统一处理,
- 开发一个接口请求,一个支持缓存,一个支持实时查询。开发两个接口增加开发成本,应该是动态代理。如果是基于 Spring 框架来开发的话,那就可以在 AOP 切面中完成接口缓存的功能。在应用启动的时候,我们从配置文件中加载需要支持缓存的接口,以及相应的缓存策略(比如过期时间)等。当请求到来的时候,我们在 AOP 切面中拦截请求,如果请求中带有支持缓存的字段(比如http://…?..&cached=true),我们便从缓存(内存缓存或者 Redis 缓存等)中获取数据直接返回。
附:
静态代理需要代理类与被代理类同时实现接口
动态代理类需要被代理类实现接口
cglib不需要代理类或者被代理类实现接口
网友评论