人生很短,只有几百个月;人生很长,大约有31亿5千3百6十万秒,在保证身体的前提下,多学点东西,驱散自己的无知。。。
科学而完美的解释
代理模式指在不修改原始类(被代理类)的情况下提供一个代理对象,以达到控制原始类的访问以及给原始类引入新功能的目的。
代理模式是一种使用频率很高的设计模式,通常的实现有两种:
- 普通的代理:一般情况下我们使代理类和原始类实现同样的接口,如果原始类不是我们开发维护的(来自第三方类库),通常都是让代理类继承原始类,通过重写的方式引入代理增强。
- 动态代理:在程序运行时通过JDK的proxy
what is 动态代理
利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象),代理的是接口(Interfaces),不是类(Class),也不是抽象类。在运行时才知道具体的实现,spring aop就是此原理。 下图是Proxy类创建代理对象方法的一些说明,可以直接去Proxy类中查看调用方法,doc注释里面有详细的使用说明
类根据类类型等条件动态创建所需类的实例。简单讲步骤就是代理类实现InvocationHandler接口,实现invoke方法,在invoke方法中对对应的类实例进行增强。
使用场景分析
简单总结下什么情况下可以使用代理模式:
- 当不想将一个对象的访问对外曝光时,可以通过给这个对象的访问方法加上一个控制层,对该对象的访问都要通过控制层。以达到对被代理对象访问权限的控制。我理解这是一种强制的措施,想使用或者访问这个对象必须通过定义的代理对象
代理模式在监控,RPC,缓存中很常见,比如需要统计对请求的处理时间进行统计,为了将框架代码和业务代码解耦,代理模式就派上用场了。
案例分析
比如说,UserRealImpl是系统中的业务类,现在有需要要收集这个类中方法参数以及返回值的信息,如果不使用设计模式,我们就需要在UserRealImpl每个方法里面加入统计信息的代码,这种代码以后就很难维护;使用代理模式就可以在不改动原来代码的情况下,给userRealImpl类的方法加上一些附加功能,将统计方法入参和返回值的代码写在代理类中(CommonProxy、DenamicProxyHandler)
代理模式代码实现
//common 前置条件
//接口
public interface UserInterface {
boolean login();
}
//实现类
public class UserRealImpl implements UserInterface {
@Override
public boolean login() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
}
//非动态代理类
public class CommonProxy implements UserInterface {
private UserInterface userReal;
public CommonProxy(UserInterface realUserObject){
this.userReal = realUserObject;
}
@Override
public boolean login() {
long beginTime = System.currentTimeMillis();
boolean login = userReal.login();
long endTime = System.currentTimeMillis();
System.out.println("方法执行时间"+(endTime-beginTime));
return false;
}
}
//动态代理类
public class DenamicProxyHandler implements InvocationHandler {
private Object realObject;
public DenamicProxyHandler(Object realObject){
this.realObject = realObject;
}
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
System.out.println("代理类开始执行");
long beginTime = System.currentTimeMillis();
Object invoke = method.invoke(realObject, args);
long endTime = System.currentTimeMillis();
System.out.println("方法執行時間:"+(endTime-beginTime));
return invoke;
}
}
//调用测试
public class CountExecuteTime {
public static void main(String[] args) {
//非动态代理
UserInterface userReal = new UserRealImpl();
CommonProxy commonProxy = new CommonProxy(userReal);
commonProxy.login();
//动态代理
UserInterface userProxyObject = (UserInterface)Proxy.newProxyInstance(userReal.getClass().getClassLoader()
, userReal.getClass().getInterfaces()
, new DenamicProxyHandler(userReal));
userProxyObject.login();
}
}
代理模式在业务系统中使用的还是挺多的,比如针对统计系统中某些接口的流量、监控相关信息等,都能使用到代理模式,所以说代理模式还是挺常用的,实际上,Spring AOP 底层的实现原理就是基于动态代理。用户配置好需要给哪些类创建代理,并定义好在执行原始类的业务代码前后执行哪些附加功能。Spring 为这些类创建动态代理对象,并在 JVM 中替代原始类对象。原本在代码中执行的原始类的方法,被换作执行代理类的方法,也就实现了给原始类添加附加功能的目的。
noted:我这只是类似于读书笔记的博客,可以从我的博客入门,尝试自己使用设计模式,想更好的运用和设计代码,我还是推荐极客时间上的《设计模式》专栏,很详细。