首页 > 学院 > 开发设计 > 正文

JDK动态代理

2019-11-11 07:10:42
字体:
来源:转载
供稿:网友
1、背景   SPRing AOP使用动态代理技术在运行期织入增强的代码,Spring AOP 的底层使用了两种代理模式一种是JDK的动态代理,另一种是基于CGLIB的动态代理。之所以需要两种代理机制,很大程度上是因为JDK本身只提供接口的代理,而不支持类的代理。  2、JDKProxy的代码package com.itheima.spring.jdkproxy;public interface PersonDao { public void savePerson();}package com.itheima.spring.jdkproxy;public class PersonDaoImpl implements PersonDao{ @Override public void savePerson() { System.out.println("save person"); }}package com.itheima.spring.jdkproxy;public class Transaction { public void beginTransaction(){ System.out.println("begin transcation"); } public void commit() { System.out.println("commit"); }}package com.itheima.spring.jdkproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * 拦截器: * 1、目标类导入进来 * 2、事务导入进来 * 3、invoke完成 * ①开启事务 * ②调用目标对象的方法 * ③事务提交 * @author xx * */public class MyInterceptor implements InvocationHandler{ private Object target; //目标类 private Transaction transaction;//事务,在这里代表一种功能,但如果要插入多个功能,就不能这么写了,看下一个案例,可以把他们加入在一个拦截器链表里 public MyInterceptor(Object target, Transaction transaction) { super(); this.target = target; this.transaction = transaction; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if("savePerson".equals(methodName) || "updatePerson".equals(methodName) || "deletePerson".equals(methodName)){ this.transaction.beginTransaction();//开启 事务 method.invoke(target);//调用目标方法 this.transaction.commit();//事务的提交 }else{ method.invoke(target); } return null; } }package com.itheima.spring.jdkproxy;import java.lang.reflect.Proxy;import org.junit.Test;/** * 1、拦截器的invoke方法是在是什么时候执行的? * 当在客户端,代理对象调用方法的时候,进入到了拦截器的invoke方法 * 2、代理对象的方法体的内容是什么? * 拦截器的invoke方法的内容就是代理对象的方法的内容 * 3、拦截器中的invoke方法的参数method是谁在什么时候传递过来的? * 代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke * 方法中的参数method就是代理对象调用的方法 * @author xx */public class JDKProxyTest { /** * 1、创建一个目标类 * 2、创建一个事务 * 3、创建一个拦截器 * 4、动态生成一个代理对象 */ @Test public void test() { Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); MyInterceptor interceptor = new MyInterceptor(target,transaction); /* *1、目标类的加载器 *2、目标类的所有的接口 *3、拦截器 */ PersonDao personDao = (PersonDao) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); personDao.savePerson(); }}思考动态代理是怎么生成的?
 jdk的动态代理不用写代理方法,它是由java虚拟机实现的,因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的PersonDao接口,在实现PersonDao接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法。
jdk动态代理比静态代理先进(不同)在哪?有什么优势?
①解决代码重用的问题
②解耦,代码灵活性高,调用目标代码时,会在方法“运行时”动态的加入
以上的JdkProxy代码有什么缺点?
①拦截器中除了能调用目标对象的目标方法以外,功能是比较单一,这个例子只能处理事务(见下面代码)
②拦截器中invoke方法的if语句(切入点)是不靠谱的,因为一旦方法多了要写很多(可用正则表达式)
3、另一种改进的JDK动态代理模式package com.itheima.spring.jdkproxy;
/** * 给日志、事务等做了一个抽象,而这个抽象就是Interceptor * @author xx * */public interface Interceptor { /* * 除了目标对象的目标方法之外,其他任何的功能,比如事务、日志等都写在interceptor里面 */ public void interceptor();}package com.itheima.spring.jdkproxy;/** * Spring的实现比这复杂,用的责任链模式 * @author xx * */public class Transaction implements Interceptor{ @Override public void interceptor() { System.out.println("transaction"); }}package com.itheima.spring.jdkproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.util.List;/** * 拦截器: * 1、目标类导入进来 * 2、事务导入进来 * 3、invoke完成 * ①开启事务 * ②调用目标对象的方法 * ③事务提交 * @author xx * */public class MyInterceptor implements InvocationHandler{ private Object target; //目标类 List<Interceptor> interceptors; public MyInterceptor(Object target, List<Interceptor> interceptors) { super(); this.target = target; this.interceptors = interceptors; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if("savePerson".equals(methodName) || "updatePerson".equals(methodName) || "deletePerson".equals(methodName)){ for(Interceptor interceptor: interceptors){ interceptor.interceptor(); } } method.invoke(target); return null; }} package com.itheima.spring.jdkproxy;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.List;import org.junit.Test;/** * 1、拦截器的invoke方法是在是什么时候执行的? * 当在客户端,代理对象调用方法的时候,进入到了拦截器的invoke方法 * 2、代理对象的方法体的内容是什么? * 拦截器的invoke方法的内容就是代理对象的方法的内容 * 3、拦截器中的invoke方法的参数method是谁在什么时候传递过来的? * 代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke * 方法中的参数method就是代理对象调用的方法 * @author xx */public class JDKProxyTest { /** * 1、创建一个目标类 * 2、创建一个事务 * 3、创建一个拦截器 * 4、动态生成一个代理对象 */ @Test public void test() { Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); List<Interceptor> interceptors = new ArrayList<Interceptor>(); interceptors.add(transaction); MyInterceptor interceptor = new MyInterceptor(target,interceptors); /* *1、目标类的加载器 *2、目标类的所有的接口 *3、拦截器 */ PersonDao personDao = (PersonDao) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); personDao.savePerson(); }}思考改进的代码解决了什么问题?
解决了之前代码的缺点一的问题

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表