Java 动态代理
2016-07-12 00:00
232 查看
#Java 动态代理
##1.代理模式
首先了解下设计模式中的代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
UML类图:
代码:
输出为:
before this methodA
this is methodA
before this methodB
this is methodB
##2.JDK动态代理
###2.1了解 java.lang.reflect.Proxy类
###2.2了解java.lang.reflect.InvocationHandler类
###2.3代码实现
输出结果为:before method invoke
HelloWorld!
after method invoke
##3.CGLib动态代理
###3.1介绍:
CGLib是通过生成java字节码从而动态的产生代理对象,因此需要字节码解析处理的依赖asm类库,字节码动态生成的代理对象实际上是继承了真实委托类的。这种实现方式需要导入cglib和asm的类库。
###3.2原理:
通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。
###3.2代码实现:
输出为:before
Tiger is running
after
##4.JDK动态代理和CgLib动态代理比较
##1.代理模式
首先了解下设计模式中的代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
UML类图:
代码:
//Subject public abstract class Subject { public void methodA() { } public void methodB() { } } //RealSubject public class RealSubject extends Subject{ @Override public void methodA() { System.out.println("this is methodA"); } @Override public void methodB() { System.out.println("this is methodB"); } } //Proxy public class Proxy extends Subject{ private Subject subject; public Proxy(Subject subject){ this.subject=subject; } @Override public void methodA() { System.out.println("before this methodA"); subject.methodA(); } @Override public void methodB() { System.out.println("before this methodB"); subject.methodB(); } } //Main public class Main { public static void main(String[] args){ Proxy proxy =new Proxy(new RealSubject()); proxy.methodA(); proxy.methodB(); } }
输出为:
before this methodA
this is methodA
before this methodB
this is methodB
##2.JDK动态代理
###2.1了解 java.lang.reflect.Proxy类
//代理类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。 //静态变量 //代理缓存 private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); // newProxyInstance 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ //生成代理class的地方 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ //利用反射,使用实现的InvocationHandler作为参数调用构造方法来获得代理类的实例 try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } } // getProxyClass 该方法用于获得Proxy的Class对象 public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces) throws IllegalArgumentException { //接口clone final Class<?>[] intfs = interfaces.clone(); //安全管理器 final SecurityManager sm = System.getSecurityManager(); //检查能否获取Class对象 if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //调用 getProxyClass0方法 return getProxyClass0(loader, intfs); } // getProxyClass0 private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) { //首先接口的数目不能超过 65535 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory //JDK对代理进行了缓存,如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory来创建代理 return proxyClassCache.get(loader, interfaces); } //静态内部类 //ProxyClassFactory private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // 所有代理类名字的前缀 private static final String proxyClassNamePrefix = "$Proxy"; // 用于生成代理类名字的计数器 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; // 对于非公共接口,代理类的包名与接口的相同 for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } // 对于公共接口的包名,默认为com.sun.proxy if (proxyPkg == null) { proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; // 真正的生成代理类的字节码的地方 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { // 根据二进制字节码返回相应的Class实例 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) throw new IllegalArgumentException(e.toString()); } } }
###2.2了解java.lang.reflect.InvocationHandler类
//处理器接口,自定义invoke方法,集中处理在动态代理对象上的调用,通常在该方法中实现对委托类的代理访问。 //第一个参数为动态代理对象,第二个参数为委托对象,第三个对象为调用参数。 public Object invoke(Object proxy, Method method, Object[] args)
###2.3代码实现
//HelloWord public interface HelloWord { public void sayHelloWorld(); } //HelloWordImpl public class HelloWordImpl implements HelloWord { public void sayHelloWorld() { System.out.println("HelloWorld!"); } } //HelloWorldHandler public class HelloWorldHandler implements InvocationHandler { // 要代理的原始对象 private Object obj; public HelloWorldHandler(Object obj) { super(); this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; // 调用之前 doBefore(); // 调用原始对象的方法 result = method.invoke(obj, args); // 调用之后 doAfter(); return result; } private void doBefore() { System.out.println("before method invoke"); } private void doAfter() { System.out.println("after method invoke"); } } //Client public class HelloWorldTest { public static void main(String[] args) { HelloWord helloWorld=new HelloWordImpl(); InvocationHandler handler=newHelloWorldHandler(helloWorld); //创建动态代理对象 HelloWord proxy=(HelloWord)Proxy.newProxyInstance( helloWorld.getClass().getClassLoader(), helloWorld.getClass().getInterfaces(), handler); proxy.sayHelloWorld(); } }
输出结果为:before method invoke
HelloWorld!
after method invoke
##3.CGLib动态代理
###3.1介绍:
CGLib是通过生成java字节码从而动态的产生代理对象,因此需要字节码解析处理的依赖asm类库,字节码动态生成的代理对象实际上是继承了真实委托类的。这种实现方式需要导入cglib和asm的类库。
###3.2原理:
通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。
###3.2代码实现:
//Tiger public class Tiger{ public void run() { System.out.println("Tiger is running"); } } //CglibProxy import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { public Object getProxyInstance(Class target) { // 声明增强类实例 Enhancer enhancer = new Enhancer(); // 设置需要创建子类的类 enhancer.setSuperclass(target); enhancer.setCallback(this); // 通过字节码技术动态创建子类实例 return enhancer.create(); } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before"); proxy.invokeSuper(obj, args); System.out.println("after"); return null; } } //Client public class Client { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Tiger tiger = (Tiger)proxy.getProxyInstance(Tiger.class); tiger.run(); } }
输出为:before
Tiger is running
after
##4.JDK动态代理和CgLib动态代理比较
* JDK动态代理对有实现接口的对象做代理 * CgLib动态代理对对没有实现接口的普通类做代理
相关文章推荐
- spring rabbitmq 配置文件简单介绍
- 在SpringMVC中关于转发和重定向的路径问题
- springmvc+freemarker
- 安装了多个jdk在配置环境变量时无效解决办法
- eclipse配置hadoop开发环境并运行WordCount小程序
- java 优雅退出
- velocity模板库的实际使用
- java*正则表达式
- spring配置必须声明元素类型 "context:component-scan"。
- cannot be cast to javassist.util.proxy.Proxy
- Java 线程数据交换控制器Exchange使用实例
- java中的==、equals()、hashCode()源码分析
- Java操作二叉红黑树
- java 泛型详解(普通泛型、 通配符、 泛型接口)
- JDK 1.8.0_92 Arrays.sort()方法不可用?【jdk1.8无法与myeclipse8.6匹配的问题】
- 框架 day68 SpringMVC入门(框架原理,springmvc和mybatis整合,参数绑定)
- Java基础与案例开发详解の常用类的介绍
- Java学习网址
- java序列化
- Enum、EnumMap、EnumSet的用法讲解