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(); }}思考改進的代碼解決了什么問題?解決了之前代碼的缺點一的問題
新聞熱點
疑難解答