动态代理小结
What:动态代理是什么?顾名思义,动态代理可以分为两部分学习,一个是代理设计模式,一个是动态,如何实现动态,java的反射机制很好解决了该问题,之后我们也能看到,由于java反射机制中是基于方法类(接口)实现的,所以由此会带来一系列的限制,在之后我们就能够看到了,之所谓成也风云,败也风云。
Why:为什么要使用动态代理?我们在spring等j2ee框架编码时,会编写很多代理类,编写这些代理类代码,除了方法不同,另外流程都是一样的,动态代理就在这种情况下诞生的,开发人员可以不用手工编写代理类代码就可以了
How:先理解代理设计模式;之后了解java相关接口,了解接口实现原理;再看下限制
Where:动态代理在哪里使用呢?
学习第一块:代理模式
代理模式是常用的java设计模式,特征是代理类与委托类有同样的接口,代理类负责为委托类处理消息、过滤消息、把消息转发给委托类以及事后处理消息。代理类一般与一个委托类相关联,代理类通过调用委托类对象的相关方法,提供特定服务。
按照代理的创建时期,我们分为静态代理和动态代理(程序运行时运用反射机制创建,即是本文的重点)
代码示例:
package com.wangshui; /** * Created by wenchao.zwc on 2015/4/12. */ public interface BookFace { public void addBook(); public void deleteBook(); } package com.wangshui; /** * Created by wenchao.zwc on 2015/4/12. */ public class BookFaceImp implements BookFace{ @Override public void addBook() { System.out.println("real adding working"); } @Override public void deleteBook() { System.out.println("real deteleing working"); } } package com.wangshui; /** * Created by wenchao.zwc on 2015/4/14. */ public class BookProxy implements BookFace{ private BookFace bookFaceImp; public BookProxy(BookFace bookFaceImp){ this.bookFaceImp = bookFaceImp; } @Override public void addBook() { System.out.println("static proxy adding"); bookFaceImp.addBook(); } @Override public void deleteBook() { System.out.println("static proxy deleting"); bookFaceImp.deleteBook(); } } package com.wangshui; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * Created by wenchao.zwc on 2015/4/12. */ public class TestMain { public static void main(String[] args){ BookFace book = new BookFaceImp(); BookFace bookface = new BookProxy(book); bookface.addBook(); bookface.deleteBook(); } }
学习第二块:动态代理 java相关代码
Java 动态代理的机制,首先需要了解以下相关的类或接口:一个接口 一个类:
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器 static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 static Class getProxyClass(ClassLoader loader, Class[] interfaces) // 方法 3:该方法用于判断指定类对象是否是一个动态代理类 static boolean isProxyClass(Class cl) // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象 // 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行 Object invoke(Object proxy, Method method, Object[] args)
每次生成动态代理类对象时都需要指定一个实现了该接口的调用处理器对象(参见 Proxy 静态方法 4 的第三个参数)。
每次生成动态代理类对象时都需要指定一个类装载器对象(参见 Proxy 静态方法 4 的第一个参数)
package com.wangshui; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Created by wenchao.zwc on 2015/4/12. */ public class BookFacePorxy implements InvocationHandler { private Object target; public BookFacePorxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("事物开始"); //执行方法 result = method.invoke(target, args); System.out.println("事物结束"); return result; } } package com.wangshui; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * Created by wenchao.zwc on 2015/4/12. */ public class TestMain { public static void main(String[] args){ BookFace bookFaceImp = new BookFaceImp(); BookFacePorxy ds = new BookFacePorxy(bookFaceImp); Class<?> cls = bookFaceImp.getClass(); BookFace bookFace = (BookFace) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), ds); bookFace.addBook(); bookFace.deleteBook(); } }
从Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), ds)由上述我们不难发现,java动态代理机制有一个很严重的限制,需要提供接口,如果此类的接口在某些情况下无法提供,则无法用该方案实现(Spring AOP机制便是受到此类实现限制,故只能提供弱AOP功能支持,其他需求需要用AspectJ实现)