六、springMVC資料轉換&格式化&校驗&錯誤訊息顯示和國際化
動態代理可以為任何類做代理且是在執行時生成,通過呼叫JDK提供的一個代理工廠Proxy.newProxyInstance來生成代理,這個代理工廠需要配置三個引數:
1.生成的代理類的二進位制位元組碼的載入器以生成代理類的Class例項去例項化代理類以最終被返回呼叫
2.被代理的介面
3.代理邏輯,此代理邏輯以InvocationHandler的形式通過已生成的代理類Class例項反射呼叫此代理類的構造器注入到代理例項 它有對目標類的引用,它有裝配代理邏輯的通用介面invoke,這個invoke最關鍵知道代理目標Method,代理類中的方法只需呼叫這個invoke就好了,ProxyGenerator負責Method分配到各個代理類中的方法。
代理類位元組碼生成邏輯:
根據傳進來的介面能做一下事情:
1.class 代理類 extends Proxy implements 要代理的介面 { //繼承Proxy能構造器注入InvocationHandler
2.public 代理類(InvocationHandler h) {
super(h);
3.private static Method 要代理的介面中的方法的Method物件;
4.static {
要代理的介面中的方法的Method物件=Class.forName("要代理的介面的名字")
.getMethod("要代理的介面中的方法的名字",new Class[]{Class.forName}
5.public final 返回型別 要代理的介面中的方法(引數) {
return (返回型別)this.h.invoke(this,要代理的介面中的方法的Method物件,引數);
介面類
package com.life.proxy; public interface IUserDao { public void save(); }
目標物件
package com.life.proxy; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("儲存資料"); } }
代理工廠
package com.life.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { private Object target;// 維護一個目標物件 public ProxyFactory(Object target) { this.target = target; } // 為目標物件生成代理物件 public Object getProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("開啟事務"); // 執行目標物件方法 Object returnValue = method.invoke(target, args); System.out.println("提交事務"); return null; } }); } }
測試類
package com.life.proxy; import org.junit.Test; public class TestProxy { @Test public void testDynamicProxy (){ IUserDao target = new UserDao(); System.out.println(target.getClass()); //輸出目標物件資訊 IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //輸出代理物件資訊 proxy.save(); //執行代理方法 } }