java动态代理
2016-06-08 18:26
281 查看
java动态代理
动态代理是java的一个重要功能,也是Spring AOP等的实现基础。代理是什么?它的作用是什么?
代理是在已有类的基础上加了一个中间层,可以在方法调用的前后进行一些附加操作,如请求过滤、参数变化、日志记录等。这样就可以在不修改已有类的情况下,增加或改变一些功能。代理有几种?
包括静态代理和动态代理。
静态代理
package com.invocationHandler; public interface Subject { public void myFunc(String arg); }
package com.invocationHandler; public class RealSubject implements Subject { @Override public void myFunc(String arg) { System.out.println("RealSubject arg: " + arg); } }
package com.invocationHandler; /** * 静态代理 */ public class SubjectProxy implements Subject { private RealSubject realSubject = new RealSubject(); @Override public void myFunc(String arg) { realSubject.myFunc(arg); } }
package com.invocationHandler; public class TestProxy { public static void main(String[] args){ SubjectProxy subjectProxy = new SubjectProxy(); subjectProxy.myFunc("静态代理"); } }
为什么要用代理?直接创建RealSubject的对象并调用它的方法不好吗?
可以增强现有接口的功能,或进行请求过滤等。
有时候不想或不能直接访问某个接口,可以通过代理来中转。
静态代理的特点是?
在运行前class文件就已经编译好了。
如果被代理的类新增了方法,静态代理类也要新增相应的方法。这样系统就会变得越来越臃肿,也不利于扩展。
动态代理
jdk动态代理package com.invocationHandler; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理 */ public class ProxyHandler implements InvocationHandler { private Object target; public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("动态代理:ProxyHandler before~~"); result = method.invoke(target, args); System.out.println("动态代理:ProxyHandler after~~"); return result; } }
package com.invocationHandler; public class TestProxy { public static void main(String[] args){ ProxyHandler proxyHandler = new ProxyHandler(); Subject subject = (Subject) proxyHandler.bind(new RealSubject()); System.out.println(subject.getClass().getName()); subject.myFunc("动态代理"); } }
输出内容:
com.sun.proxy.$Proxy0 动态代理:ProxyHandler before~~ RealSubject arg: 动态代理 动态代理:ProxyHandler after~~
bind()中调用的Proxy.newProxyInstance(),代码如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, interfaces); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { return newInstance(cons, ih); } }); } else { return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
newProxyInstance()生成的对象的类型是$Proxy0,它既不是Subject,也不是ProxyHandler。但是生成对象可以转换为Subject subject,是因为它实现了Subject的各个接口。
* 动态代理是如何实现的?包括哪几步? *
1.创建调用处理器,用来处理Proxy所有方法调用
ProxyHandler proxyHandler = new ProxyHandler();
2.根据RealSubject的类加载器和所有接口列表,获取动态代理类类对象
根据要实现的接口信息,在代码中动态创建该Proxy类的字节码
Class
动态代理的特点和用处?
特点:动态代理是在运行时才生成class文件,相比于静态代理,执行效率会有所降低。
利用java jdk实现的动态代理只能针对接口实现代理,见target.getClass().getInterfaces() ,而不能针对类实现,这是它的一个缺憾。cglib(code generation library)补充了jdk仅能支持接口实现类的不足。
动态代理Proxy的代码量是固定的,不会因为业务的庞大而变庞大可以减少冗余代码量。
解耦,通过参数就可以判断真实的类,不需要事先实例化,可以更灵活地添加功能,在不改变源码的情况下,增强一些方法。
用处:
spring AOP
远程调用,java标准库的RMI、hessian等.从某处看到的,我也没看懂o(╯□╰)o
JDK 和 CGLIB 实现的动态代理
JDK动态代理只能适用于实现了接口的类,而CGLIB可以针对类实现;
JDK的实现是,代理类和目标类实现了相同的接口,目标对象作为代理对象的一个属性;CGLIB是,代理类是目标类的一个子类,覆盖了目标类的所有方法,所以目标类和方法不能声明为final的。CGLIB利用开源字节码处理框架ASM动态修改子类的代码来实现。具体怎么弄的我也不清楚(⊙o⊙)哦~~
如果目标类实现了接口,spring默认会使用JDK动态代理实现AOP;目标类实现了接口的情况下,可以强制用CGLIB实现AOP;若目标类没有实现接口,必须使用CGLIB,spring动态代理会自动在JDK动态代理和CGLIB之前转换。具体咋转换的呢?
待深入内容
JDK动态代理的代理类字节码具体是如何一步步生成的?
spring AOP如何根据配置生成代理类的?
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树