java-动态代理分析
来源:互联网 发布:linux怎样备份数据库 编辑:程序博客网 时间:2024/05/18 03:40
动态代理的目的:
AOP操作。
动态代理的实现:
在运行时,不能修改原业务类,只能生成一个新类成为代理类,当业务调用原业务类时,实质上去调用代理类,代理执行业务方法,并在方法前后加上切面操作。
那么,要使调用业务类跟调用代理类一样,只有通过多态实现。
java实现多态只有两种:
1.实现接口:jdk动态代理的做法
2.继承:CGLib的做法(动态字节码生成新类)
假设场景:我们需要给某部分类增加日志切面
原某个业务类:UserService
业务实现类:UserServiceImpl
aop逻辑类:LogInterceptor
jdk动态代理实现代码:
public class AppTest { public static Logger logger = LoggerFactory.getLogger(AppTest.class); public static void main(String args[]) throws Exception { long startTime = System.currentTimeMillis(); for (int i = 0; i < 100; i ++) { UserService us = new UserServiceImpl(); InvocationHandler ih = new LogInterceptor(us); Class<?> cls = us.getClass(); UserService userServiceProxy = (UserService) Proxy.newProxyInstance( cls.getClassLoader(), // 实现类的类加载器 cls.getInterfaces(), // 业务类接口 ih); // aop操作类(方法拦截类) userServiceProxy.printUser(); } long endTime = System.currentTimeMillis(); System.out.println("执行了:" + (endTime - startTime) + "毫秒"); }}/** * 业务接口类 */interface UserService { void printUser();}/** * 业务方法实现类 */class UserServiceImpl implements UserService { @Override public void printUser() { System.out.println("打印用户信息成功"); }}/** * 切面操作回调 */class LogInterceptor implements InvocationHandler { private Object obj; // 传入业务方法的实现类对象 public LogInterceptor (Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("切面操作开始前"); System.out.println("日志记录操作"); // 实际调用业务类方法 method.invoke(obj, args); System.out.println("切面操作结束"); return null; }}
可以看到,关键点还是代理类的生成
Proxy.newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } /* * Look up or generate the designated proxy class. */ Class cl = getProxyClass(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { /* * Proxy源码开始有这样的定义: * private final static Class[] constructorParams = { InvocationHandler.class }; * cons即是形参为InvocationHandler类型的构造方法 */ Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }
代码中Class cl = getProxyClass创建了代理类$proxy0,这里是关键。
getProxyClass在jdk1.8之前的实现:
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { // 如果目标类实现的接口数大于65535个则抛出异常 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // 声明代理对象所代表的Class对象(有点拗口) Class proxyClass = null; String[] interfaceNames = new String[interfaces.length]; Set interfaceSet = new HashSet(); // for detecting duplicates // 遍历目标类所实现的接口 for (int i = 0; i < interfaces.length; i++) { // 拿到目标类实现的接口的名称 String interfaceName = interfaces[i].getName(); Class interfaceClass = null; try { // 加载目标类实现的接口到内存中 interfaceClass = Class.forName(interfaceName, false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != interfaces[i]) { throw new IllegalArgumentException( interfaces[i] + " is not visible from class loader"); } // 中间省略了一些无关紧要的代码 ....... // 把目标类实现的接口代表的Class对象放到Set中 interfaceSet.add(interfaceClass); interfaceNames[i] = interfaceName; } // 把目标类实现的接口名称作为缓存(Map)中的key Object key = Arrays.asList(interfaceNames); Map cache; synchronized (loaderToCache) { // 从缓存中获取cache cache = (Map) loaderToCache.get(loader); if (cache == null) { // 如果获取不到,则新建地个HashMap实例 cache = new HashMap(); // 把HashMap实例和当前加载器放到缓存中 loaderToCache.put(loader, cache); } } synchronized (cache) { do { // 根据接口的名称从缓存中获取对象 Object value = cache.get(key); if (value instanceof Reference) { proxyClass = (Class) ((Reference) value).get(); } if (proxyClass != null) { // 如果代理对象的Class实例已经存在,则直接返回 return proxyClass; } else if (value == pendingGenerationMarker) { try { cache.wait(); } catch (InterruptedException e) { } continue; } else { cache.put(key, pendingGenerationMarker); break; } } while (true); } try { // 中间省略了一些代码 ....... // 这里就是动态生成代理对象的最关键的地方 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { // 根据代理类的字节码生成代理类的实例 proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } // add to set of all generated proxy classes, for isProxyClass proxyClasses.put(proxyClass, null); } // 中间省略了一些代码 ....... return proxyClass; }
ProxyGenerator类的静态方法generateProxyClass是真正生成代理类class字节码的地方:
public static byte[] generateProxyClass(final String name, Class[] interfaces) { ProxyGenerator gen = new ProxyGenerator(name, interfaces); // 这里动态生成代理类的字节码,由于比较复杂就不进去看了 final byte[] classFile = gen.generateClassFile(); // 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上 if (saveGeneratedFiles) { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { try { FileOutputStream file = new FileOutputStream(dotToSlash(name) + ".class"); file.write(classFile); file.close(); return null; } catch (IOException e) { throw new InternalError( "I/O exception saving generated file: " + e); } } }); } // 返回代理类的字节码 return classFile; }
网上有同学贴出了$proxy0的代码:
获取$proxy0代码的思路是:先用ProxyGenerator中的generateProxyClass生成字节码文件,然后用反编译工具查看生成的.class文件就可以了
public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static Method m0; private static Method m3; private static Method m2; static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("***.RealSubject").getMethod("request", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch (ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } //static public $Proxy0(InvocationHandler invocationhandler) { super(invocationhandler); } @Override public final boolean equals(Object obj) { try { return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final int hashCode() { try { return ((Integer) super.h.invoke(this, m0, null)).intValue(); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final void request() { try { super.h.invoke(this, m3, null); return; } catch (Error e) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @Override public final String toString() { try { return (String) super.h.invoke(this, m2, null); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }
这波操作很6,这个request()方法就是他代理的方法,对应到我们这里就是那个printUser()方法了,关于其中的基类:proxy
class Proxy{ InvocationHandler h=null; protected Proxy(InvocationHandler h) { this.h = h; } ... }
入参是一个InvocationHandler,就是那个LogInterceptor了。
CGLib实现代码:
public class AppTest { public static Logger logger = LoggerFactory.getLogger(AppTest.class); public static void main(String args[]) throws Exception { long startTime = System.currentTimeMillis(); for (int i = 0; i < 1; i ++) { CGLibProxy cgLibProxy = new CGLibProxy(); UserService userService = (UserService) cgLibProxy.getProxy(UserServiceImpl.class); userService.printUser(); //这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口 System.out.println("userService的Class类是:"+userService.getClass().toString()); System.out.print("userService中的属性有:"); Field[] field=userService.getClass().getDeclaredFields(); for(Field f:field){ System.out.print(f.getName()+", "); } System.out.print("\n"+"userService中的方法有:"); Method[] method=userService.getClass().getDeclaredMethods(); for(Method m:method){ System.out.print(m.getName()+", "); } System.out.println("\n"+"userService的父类是:"+userService.getClass().getSuperclass()); System.out.print("\n"+"userService实现的接口是:"); Class<?>[] interfaces=userService.getClass().getInterfaces(); for(Class<?> ii :interfaces){ System.out.print(ii.getName()+", "); } } long endTime = System.currentTimeMillis(); System.out.println("执行了:" + (endTime - startTime) + "毫秒"); }}/** * 代理类 */class CGLibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy (Class clazz) { // 设置需要创建子类的类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); // 通过字节码技术动态创建子类实例 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("切面操作开始前"); System.out.println("日志记录操作"); // 实际调用业务类方法 Object result = methodProxy.invokeSuper(o, objects); System.out.println("切面操作结束"); return result; }}/** * 业务接口类 */interface UserService { void printUser();}/** * 业务方法实现类 */class UserServiceImpl implements UserService { @Override public void printUser() { System.out.println("打印用户信息成功"); }}
代码结果中看到,生成的代理类继承自UserServiceImpl。
参考链接:
http://blog.csdn.net/xyw591238/article/details/51995515
http://songbo-mail-126-com.iteye.com/blog/968792
http://rejoy.iteye.com/blog/1627405
阅读全文
1 0
- Java动态代理分析
- Java动态代理分析
- java-动态代理分析
- Java动态代理机制分析
- Java 动态代理机制分析
- java动态代理机制分析
- Java 动态代理机制分析
- java动态代理机制分析
- Java 动态代理源码分析
- Java 动态代理源码分析
- Java动态代理过程分析
- Java 动态代理机制分析及扩展
- Java 动态代理机制分析及扩展
- Java 动态代理机制分析及扩展
- Java 动态代理机制分析及扩展
- Java 动态代理机制分析及扩展
- Java 动态代理机制分析及扩展
- Java 动态代理机制分析及扩展
- 《MongoDB 入门篇》笔记
- 深度学习_简介及相关概念
- 电商项目开发流程
- 浏览器从发送HTTP请求到返回HTML的过程
- httpwebrequest下载文件失败的解决方案
- java-动态代理分析
- android 使用TextInputLayout创建一个登陆界面
- string和stringstream类
- Java基础部分第十八节
- 【Swift】下载图片
- 计算机网络-10
- CentOS修改hosts文件
- Java算法之选择排序
- Sublime Text 2支持GB2312和GBK,解决中文显示乱码问题