动态代理模式

来源:互联网 发布:skype官方下载 mac 编辑:程序博客网 时间:2024/05/23 10:27

最近在看项目中关于aop的一些东西,正好想起之前没毕业的时候去唯品会面试,面试官问我知不知道aop底层实现原理,当时真是一脸懵逼啊。现在工作后对aop怎么使用稍微了解了一点,也知道底层原理其实是动态代理,具体怎么实现还不是很清楚所以这篇就聊一聊动态代理设计模式。在这里分享一下之前无意中看到的大神对aop的比喻,感觉很有道理。

aop切面编程就是在常规的执行java类中方法前或执行后加入自定义的方法。比如你本来每天都去打酱油,去,打酱油,回。现在我每天在你打酱油路上等着,你去打酱油的时候我打你一顿,回来的时候给你点糖果吃。你根本不知道为什么我会在路上拦住打你。所以在切面中插入你自定义的方法,这个方法的执行和本身要执行的类方法无关系,也就是不是这个类的方法来调用你写的方法的,你写的方法什么时候执行都是要通过在配置指定。我打完你,你该打酱油还是去打酱油,当然我如果是拦住你让你酱油打少点,你打酱油的时候还是会打那么多,但是在你打完酱油回来的时候我可以把你的酱油倒些出去,所以嵌入的自定义方法对要调用的类方法本身没有影响,但是可以操纵这个方法的返结果或者处理结果。

上面这段话我觉得还是很形象的,我现在接触到的aop的应用一般是日志以及异常处理,session之类的还不是很了解。

按照我现在的理解,我觉得动态代理只要有两个地方比较重要,一个是InvocationHandler接口,还有一个是Proxy类。

为什么要有代理模式?

在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。比如我们买二手房,往往只能通过中介,因为我们这时候不能直接接触到客户,但是中介可以。

代理模式代码如下:

首先建立buyHouse接口

public interface BuyHouse {public void buyHouse();}
建立一个realSubject

public class RealSubject implements BuyHouse {@Overridepublic void buyHouse() {System.out.println("我要在外滩旁边买一套房");}}
定义一个动态代理类,实现InvocationHandler接口

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class DynamicProxy implements InvocationHandler {private Object object;public DynamicProxy(Object object){this.object = object;}@Overridepublic Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Throwable {//实现真实对象前可以添加自己想实现的业务,实际可能是日志,权限验证等等System.out.println("你必须给我中介费先付5w");//实现真实对象方法paramMethod.invoke(object, paramArrayOfObject);//之后继续实现一些业务,可以通过回调System.out.println("中介费尾款给我");return null;}}
最后看一下测试类

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class TestDynamicProxy {public static void main(String[] args) {// TODO Auto-generated method stubBuyHouse buyHouse = new RealSubject();InvocationHandler handler = new DynamicProxy(buyHouse);BuyHouse proxyHouse = (BuyHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), buyHouse.getClass().getInterfaces(), handler);proxyHouse.buyHouse();}}
控制台输出结果为

你必须给我中介费先付5w
我要在外滩旁边买一套房
中介费尾款给我


到此建议动态代理结束,我们看下jdk1.8中InvocationHandler以及Proxy源码。首先是InvocationHandler

public abstract interface InvocationHandler{  public abstract Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject)    throws Throwable;}
InvocationHandler接口中只有一个invoke方法,该方法三个参数分别指 真实对象,调用对象的method方法,最后一个不是很明白作用,待以后补充,或者知道的大神解答下

Proxy



Proxy类在jdk1.8中定义的属性如图,这里我们主要使用newProxyInstance这个方法(我也不知道为什么,我一看到Instance这个就想到反射),代码如下

  public static Object newProxyInstance(ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler)    throws IllegalArgumentException  {    Objects.requireNonNull(paramInvocationHandler);    Class[] arrayOfClass = (Class[])paramArrayOfClass.clone();    SecurityManager localSecurityManager = System.getSecurityManager();    if (localSecurityManager != null) {      checkProxyAccess(Reflection.getCallerClass(), paramClassLoader, arrayOfClass);    }    Class localClass = getProxyClass0(paramClassLoader, arrayOfClass);    try    {      if (localSecurityManager != null) {        checkNewProxyPermission(Reflection.getCallerClass(), localClass);      }      Constructor localConstructor = localClass.getConstructor(constructorParams);      localObject = paramInvocationHandler;      if (!Modifier.isPublic(localClass.getModifiers())) {        AccessController.doPrivileged(new PrivilegedAction()        {          public Void run()          {            this.val$cons.setAccessible(true);            return null;          }        });      }      return localConstructor.newInstance(new Object[] { paramInvocationHandler });    }    catch (IllegalAccessException|InstantiationException localIllegalAccessException)    {      throw new InternalError(localIllegalAccessException.toString(), localIllegalAccessException);    }    catch (InvocationTargetException localInvocationTargetException)    {      Object localObject = localInvocationTargetException.getCause();      if ((localObject instanceof RuntimeException)) {        throw ((RuntimeException)localObject);      }      throw new InternalError(((Throwable)localObject).toString(), (Throwable)localObject);    }    catch (NoSuchMethodException localNoSuchMethodException)    {      throw new InternalError(localNoSuchMethodException.toString(), localNoSuchMethodException);    }  }
这段代码我只能看个大体,基本就是利用反射获取构造函数对象并生成一个代理类,看一下他的三个参数:

ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler)
paramClassLoader指类装载器,paramArrayOfClass 一般表示需要提供给代理对象的需要的接口,最后InvocationHandler不多做介绍了。










0 0
原创粉丝点击