java动态代理的实现
来源:互联网 发布:caxa工程师编程实例 编辑:程序博客网 时间:2024/06/05 05:55
本文探讨两种java动态代理技术,JDK和cglib
使用JDK的代理只能对有接口的类做代理,且不能代理接口之外的方法(实现类中扩展的),cglib可以对无接口的类做代理,不受接口的限制
以下对两种代理方式进行剖析,通过模拟Spring的注入依赖(IOC)和面向切面(AOP)
代码都加着注释,运行结果:
当然了,这个错误是可控的,在类型检查的过程中直接把无接口的类过滤掉,不使用代理直接返回对象不就可以了,把getBean方法修改为:
红体字是添加的内容,若是不符合代理条件,直接返回,也就是本业务受理,自己玩去!运行后结果:
必须继承Invocationhandler 实现其invoke方法,在其中书写业务员代码。
多了一个参数而已,其他的结构上基本没区别。
代理有什么用?
Spring的面向切面编程(Aspect)就是利用代理技术实现,获取注入对象的时候获取的其实并不是注入类的对象(target),而是其代理类的对象(proxyTarget)只是通过动态代理实现,对于编码者而言是透明的,在代理方法中可以对目标方法做事务控制、日志记录、异常捕获、错误处理等等工作。代理方式有哪两种?
JDK动态代理和cglib在Spring中如何使用他们,有什么区别?
Spring默认使用JDK的动态代理,如果在spring配置文件中添加<aop:aspectj-autoproxy proxy-target-class="true" />,则使用cglib,false还是使用JDK使用JDK的代理只能对有接口的类做代理,且不能代理接口之外的方法(实现类中扩展的),cglib可以对无接口的类做代理,不受接口的限制
以下对两种代理方式进行剖析,通过模拟Spring的注入依赖(IOC)和面向切面(AOP)
<?xml version="1.0" encoding="UTF-8"?><beans><aspectj-autoproxy proxy-target-class="false" /><bean id="target1" class="com.java.advice151.TargetClass"></bean><bean id="target2" class="com.java.advice151.TargetImpl"></bean></beans
首先看XML配置文件的内容,配置文件模拟Spring配置文件,第一个标签用来设置代理类型,后两个是注入的bean,然后看代码:
public class Advice106 {static Map<String, String> beans = new HashMap<String, String>();private static boolean proxy_target_class = false;public static void main(String[] args) throws Exception,Exception {parseXml2Beans(beans, "beans.xml");TargetInterface pi = getBean("target2");pi.save();}/** * 解析XML文件,以获取文件中注入的类 * * @param beans * @param string */private static void parseXml2Beans(Map<String, String> beans, String string) {SAXReader reader = new SAXReader();try {InputStream xmlPath = Advice106.class.getClassLoader().getResourceAsStream("beans.xml");Document document = reader.read(xmlPath);Element root = document.getRootElement();List<Element> elements = root.elements();for (Element element : elements) {if ("bean".equals(element.getName())) {beans.put(element.attributeValue("id"),element.attributeValue("class"));} else if ("aspectj-autoproxy".equals(element.getName())) {proxy_target_class = Boolean.parseBoolean(element.attributeValue("proxy-target-class"));}}} catch (DocumentException e) {e.printStackTrace();}}/** * 根据解析出来的参数判断代理方式 * * @param id * @return * @throws Exception */@SuppressWarnings("unchecked")private static <T> T getBean(String id)throws Exception {String className = beans.get(id);T target = (T) Class.forName(className).newInstance();if (proxy_target_class) {return cglibProxy(target);} else {return jdkProxy(target);}}/** * JDK动态代理 直接创建代理对象 * * @param target * @return */private static <T> T jdkProxy(T target) {InvocationHandler handler = new JDKHandler<T>(target);return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);}/** * JDK动态代理 先创建代理类,然后创建代理对象 * * @param target * @return */private static <T> T jdkProxy2(T target) {InvocationHandler handler = new JDKHandler<T>(target);Class<T> proxyClass = (Class<T>) Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());T proxyObject = null;try {Constructor<T> con = proxyClass.getConstructor(new Class[] { InvocationHandler.class });proxyObject = con.newInstance(new Object[] { handler });} catch (Exception e) {e.printStackTrace();}return proxyObject;}/** * 使用cglib方式代理 * * @param target * @return */@SuppressWarnings("unchecked")public static <T> T cglibProxy(T target){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(new CglibHandler<T>(target));return (T) enhancer.create();}}/** * 目标接口 * * @author 201507160235 * */interface TargetInterface {public void save();public void add();public void query();}/** * 目标接口实现类 * * @author 201507160235 * */class TargetImpl implements TargetInterface {@Overridepublic void save() {System.out.println("real business save method");}@Overridepublic void add() {System.out.println("real business add method");}@Overridepublic void query() {System.out.println("real business add method");}}/** * 目标类 * * @author 201507160235 * */class TargetClass {public void save() {System.out.println("no interface save method");}public void add() {System.out.println("no interface add method");}public void query() {System.out.println("no interface add method");}}
代码都加着注释,运行结果:
代理句柄中预处理!real business save method代理句柄中最终处理
cglib代理,事务开始!real business save methodcglib代理,事务结束!但是如果proxy-target-class=false的时候,强制获取TargetClass的代理对象,则会报错:
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.java.advice151.TargetClassat com.java.advice151.Advice106.main(Advice106.java:25)
当然了,这个错误是可控的,在类型检查的过程中直接把无接口的类过滤掉,不使用代理直接返回对象不就可以了,把getBean方法修改为:
private static <T> T getBean(String id)throws Exception {String className = beans.get(id);T target = (T) Class.forName(className).newInstance();if (proxy_target_class) {return cglibProxy(target);} else {<span style="color:#ff6666;">if (target.getClass().getInterfaces().length <= 0) {return target;}</span>return jdkProxy(target);}}
红体字是添加的内容,若是不符合代理条件,直接返回,也就是本业务受理,自己玩去!运行后结果:
no interface save method
public class JDKHandler<T> implements InvocationHandler {T obj;public JDKHandler(T obj) {this.obj = obj;}@Overridepublic T invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("代理句柄中预处理!");T result = (T) method.invoke(obj, args);System.out.println("代理句柄中最终处理");return result;}}
必须继承Invocationhandler 实现其invoke方法,在其中书写业务员代码。
cglib的处理拦截器:
public class CglibHandler<T> implements MethodInterceptor {T target;public CglibHandler(T target) {this.target = target;}@Overridepublic T intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {System.out.println("cglib代理,事务开始!");T proxyObj = (T) proxy.invoke(target, args);System.out.println("cglib代理,事务结束!");return proxyObj;}}
多了一个参数而已,其他的结构上基本没区别。
他们之间最大的区别在哪儿呢?是代理的实现部分,JDK传入的是结构数组,而cglib传入的是superClass,回调函数类都是需要传入的,毕竟是你的业务所在。
另外再说下,jdkProxy2和jdkProxy是等价的,这个可以参考官方文档,只是比较麻烦一点而已,最常用的方式是jdkProxy
0 0
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- java动态代理的实现
- java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Java动态代理的实现
- Freemarker中如何遍历List
- The local variable date may not have been initialized解决办法
- Jenkins中集成jmeter-maven插件
- [MSDN] Windows Server 2012 R2 简/繁/英下载
- asp.net calender控件显示一周之内的日期
- java动态代理的实现
- nginx 配置摘要
- 使用Qt开发文本编辑器(一):功能介绍
- POJ 1465 Multiple(用BFS求能组成的n的最小倍数)
- MySQL配置文件my.cnf中各【】块解释
- eclipse 工程导入 android studio
- 短信发送格式
- 一文读懂机器学习,大数据/自然语言处理/算法全有了……
- android.mk的语法