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