码迷,mamicode.com
首页 > 编程语言 > 详细

java动态代理

时间:2015-12-14 14:33:38      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:

简单的说,代理模式是在目标对象和访问对象之间增加了一层代理对象,所有的访问对象通过代理对象来实现对目标对象的调用。

        代理对象和目标对象实现同一个接口,由代理对象来调用目标对象,对于外部来说,代理对象就可以替代目标对象被调用。通过这种方式,代理对象中可以在正常的访问中增加额外的逻辑,比如缓存、权限控制、日志记录等。

        但是这种静态代理的模式需要增加额外的代理类的实现,Java 5开始引入了动态代理机制,实现了在运行时动态地创建出代理对象,这其实是一种方法调用的拦截,AOP就是利用了这种模式。

 

动态代理的使用例子 

1
<span style="font-size:16px;">package com.dynamic.jdk;<br><br>/**<br> * 目标类的接口定义<br> * <p/><br> * Created by Vincent Tse on 12/2/15.<br> */<br>public interface MyInterface {<br>    void doSomething();<br>}<br></span>
1
<span style="font-size:16px;">package com.dynamic.jdk;<br><br>/**<br> * 目标类的具体实现<br> * <p/><br> * Created by Vincent Tse on 12/2/15.<br> */<br>public class MyInterfaceImpl implements MyInterface {<br><br>    @Override<br>    public void doSomething() {<br>        System.out.println("here is my real operation!");<br>    }<br>}<br></span>
1
<span style="font-size:16px;">package com.dynamic.jdk;<br><br>import java.lang.reflect.InvocationHandler;<br>import java.lang.reflect.Method;<br><br>/**<br> * 自定义的InvocationHandler<br> * 封装具体的调用过程<br> * <p/><br> * Created by Vincent Tse on 12/2/15.<br> */<br>public class MyInvocationHandler implements InvocationHandler {<br>    //target是真正执行方法的目标对象<br>    private Object target;<br><br>    public MyInvocationHandler(Object target) {<br>        super();<br>        this.target = target;<br>    }<br><br>    /**<br>     * 代理对象调用的方法<br>     * @param proxy<br>     * @param method<br>     * @param args<br>     * @return<br>     * @throws Throwable<br>     */<br>    @Override<br>    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {<br>        System.out.println("before target‘s operation!");<br>        Object result = method.invoke(target, args);<br>        System.out.println("after target‘s operation");<br>        return result;<br>    }<br>}<br></span>
1
<span style="font-size:16px;">package com.dynamic.jdk;<br><br>import java.lang.reflect.Proxy;<br><br>/**<br> * 测试类<br> * <p/><br> * Created by Vincent on 12/2/15.<br> */<br>public class DynamicTest {<br><br>    public static void main(String[] args) {<br><br>        //生成目标对象<br>        MyInterface myInterface = new MyInterfaceImpl();<br><br>        //实例化invocationHandler对象,传入目标对象作为target<br>        MyInvocationHandler invocationHandler = new MyInvocationHandler(myInterface);<br><br>        //调用Proxy的方法生成代理对象<br>        MyInterface proxy = (MyInterface)Proxy.newProxyInstance(myInterface.getClass().getClassLoader(),<br>                new Class[]{MyInterface.class}, invocationHandler);<br><br>        //调用代理对象的方法<br>        proxy.doSomething();<br>    }<br>}<br></span>

输出结果:

before target‘s operation!

here is my real operation!

after target‘s operation! 

 

使用起来很简单,接下来看源码分析其中的原理

从Proxy的newProxyInstance()方法开始,这个方法就是用来生成代理对象的,需要传入类加载器、实现的接口以及一个InvocationHandler对象。 

1
<span style="font-size:16px;">public static Object newProxyInstance(ClassLoader loader,<br>                                      Class<?>[] interfaces,<br>                                      InvocationHandler h)<br>    throws IllegalArgumentException<br>{<br>    Objects.requireNonNull(h);<br><br>    final Class<?>[] intfs = interfaces.clone();<br>    final SecurityManager sm = System.getSecurityManager();<br>    if (sm != null) {<br>        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);<br>    }<br><br>    //通过传入的类加载器和实现接口生成代理类<br>    Class<?> cl = getProxyClass0(loader, intfs);<br><br>    /*<br>     * Invoke its constructor with the designated invocation handler.<br>     */<br>    try {<br>        if (sm != null) {<br>            checkNewProxyPermission(Reflection.getCallerClass(), cl);<br>        }<br>                  //反射获取代理类的构造函数<br>        final Constructor<?> cons = cl.getConstructor(constructorParams);<br>        final InvocationHandler ih = h;<br>        if (!Modifier.isPublic(cl.getModifiers())) {<br>            AccessController.doPrivileged(new PrivilegedAction<Void>() {<br>                public Void run() {<br>                    cons.setAccessible(true);<br>                    return null;<br>                }<br>            });<br>        }<br>        //反射生成实例,将invocationHandler传入,之后调用invoke方法就靠它了<br>        return cons.newInstance(new Object[]{h});<br>    } catch (IllegalAccessException|InstantiationException e) {<br>        throw new InternalError(e.toString(), e);<br>    } catch (InvocationTargetException e) {<br>        Throwable t = e.getCause();<br>        if (t instanceof RuntimeException) {<br>            throw (RuntimeException) t;<br>        } else {<br>            throw new InternalError(t.toString(), t);<br>        }<br>    } catch (NoSuchMethodException e) {<br>        throw new InternalError(e.toString(), e);<br>    }<br>} <br></span>

 

 

getProxyClass0()方法就是用来生成代理类的,首先检查实现接口数量,大于65535就抛异常,感觉应该不会有实现那么多接口的类吧。

1
<span style="font-size:16px;">private static Class<?> getProxyClass0(ClassLoader loader,<br>                                       Class<?>... interfaces) {<br>    if (interfaces.length > 65535) {<br>        throw new IllegalArgumentException("interface limit exceeded");<br>    }<br><br>       //从一个Cache中获取代理类,如果没有就重新生成<br>    return proxyClassCache.get(loader, interfaces);<br>}<br></span>

 

proxyClassCache是一个静态的WeakCache,定义在Proxy类里。

WeakCache里有两个factory,一个是subKeyFactory, java培训是一个映射函数(key, parameter)->sub-key, 另一个是valueFactory,是一个映射函数(key, parameter)->value。WeakCache的get方法需要两个参数,一个是key,另一个是parameter。

具体WeakCache的用法与原理这里不再赘述,请参考源码。

1
<span style="font-size:16px;">private static final WeakCache<ClassLoader, Class<?>[], Class<?>><br>    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());<br></span>

这里传入的KeyFactory和ProxyClassFactory是Proxy类中定义的静态类,分别对应了WeakCache中的subKeyFactory和valueFactory,都实现了BiFunction接口,并实现了apply()方法。ProxyClassFactory的apply()方法里完成的就是生成代理类的逻辑,最关键的是

1
<span style="font-size:16px;">byte[] proxyClassFile = ProxyGenerator.generateProxyClass(<br>    proxyName, interfaces, accessFlags);<br></span>

上面的方法用来生成代理类的字节码,这个代理类里会有接口的实现方法,在实现的方法中会调用InvocationHandler的invoke()方法,有兴趣的可以将生成的字节码写到本地,用反编译工具打开看一下。

 

那么ProxyClassFactory的apply()方法是在什么时候被调用的呢,回到WeakCache的get()方法

1
<span style="font-size:16px;">//生成subkey来获取对应的supplier<br>Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));<br>Supplier<V> supplier = valuesMap.get(subKey);<br>Factory factory = null;<br>//一直循环,直到从supplier中获取到value为止<br>//如果没有supplier就生成factory并加入到缓存中(源码说这是一个install的过程)<br>while (true) {<br>    if (supplier != null) {<br>        V value = supplier.get();<br>        if (value != null) {<br>            return value;<br>        }<br>    }<br>    <br>    if (factory == null) {<br>        //Factory是内部类,实现了Supplier接口,实现了get()方法<br>        //实际上在get()方法中调用了valueFactory(也就是ProxyClassFactory)的apply()方法<br>        //可以debug进去看<br>        factory = new Factory(key, parameter, subKey, valuesMap);<br>    }<br><br>    if (supplier == null) {<br>        supplier = valuesMap.putIfAbsent(subKey, factory);<br>        if (supplier == null) {<br>            supplier = factory;<br>        }<br>    } else {<br>        if (valuesMap.replace(subKey, supplier, factory)) {<br>            supplier = factory;<br>        } else {<br>            supplier = valuesMap.get(subKey);<br>        }<br>    }<br>}<br></span>

好辛苦,终于生成代理类了,回到newProxyInstance方法,有了代理类的Class对象,就可以通过反射生成实例(调用的是带InvocationHandler参数的构造函数),生成实例之后就可以用代理对象了。

java动态代理

标签:

原文地址:http://www.cnblogs.com/jinshiyill/p/5044943.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!