一 代理模式簡介
代理(Proxy)是一種設計模式 提供了對目標物件另外的訪問方式
代理物件代理目標物件 達到增強目標物件功能的目的

二 靜態代理
需要定義介面或者父類 代理物件與目標物件一起實作相同介面或者繼承相同父類
優點: 在不修改目標物件的功能前提下 對目標功能擴展
缺點: 因為代理物件需要與目標物件一起實作相同介面或者繼承相同父類 所以會有很多代理類 導致類太多 同時 如果介面增加方法 代理物件與目標物件都要維護
1. 介面
/** * 介面 * Created by Hy on 2020/7/10. */ public interface IUserService { void insertUser(); String deleteUser(int id); }
2. 目標物件
/** * 目標物件 * Created by Hy on 2020/7/10. */ public class UserService implements IUserService { @Override public void insertUser() { System.out.println("insert ok"); } @Override public String deleteUser(int id) { System.out.println("delete... ... ..."); return "id = " + id + " delete ok"; } }
3. 代理物件
/** * 代理物件 * Created by Hy on 2020/7/13. */ public class UserServiceProxy implements IUserService { private IUserService target; //目標物件 public UserServiceProxy(IUserService target) { this.target = target; } @Override public void insertUser() { System.out.println("增強方法體 1/2"); target.insertUser(); System.out.println("增強方法體 2/2"); } @Override public String deleteUser(int id) { id++; //增強引數 String s = target.deleteUser(id); s = s + "!!!"; //增強回傳值 return s; } }
4. 測驗
@Test public void test01() { // 創建目標物件 UserService target = new UserService(); // 創建代理物件 UserServiceProxy proxy = new UserServiceProxy(target); // 使用代理物件呼叫方法 proxy.insertUser(); String s = proxy.deleteUser(1); System.out.println(s); }
三 動態代理(介面代理)
需要定義介面讓目標物件實作 使用java.lang.reflect.Proxy動態的在記憶體中構建代理物件
優點: 在不修改目標物件的功能前提下 對目標功能擴展 代理物件不需要實作介面
缺點: 目標物件一定要實作介面 否則不能用動態代理
1. 介面
/** * 介面 * Created by Hy on 2020/7/10. */ public interface IUserService { void insertUser(); String deleteUser(int id); }
2. 目標物件
/** * 目標物件 * Created by Hy on 2020/7/10. */ public class UserService implements IUserService { @Override public void insertUser() { System.out.println("insert ok"); } @Override public String deleteUser(int id) { System.out.println("delete... ... ..."); return "id = " + id + " delete ok"; } }
3. 代理工廠
/** * 代理工廠 * Created by Hy on 2020/7/13. */ public class ProxyFactory { private Object target; //目標物件 public ProxyFactory(Object target) { this.target = target; } public Object createProxyInstance() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { /** * 代理物件呼叫的所有方法都會觸發該方法執行 * @param proxy 代理物件 * @param method 被代理的方法 * @param args 被代理的方法傳參 * @return 被代理的方法回傳值 * @throws Throwable 例外 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("deleteUser".equals(method.getName())) { // 增強指定方法 int id = (int) args[0]; id++; //增強引數 System.out.println("增強方法體 1/2"); String invoke = (String) method.invoke(target, id); invoke = invoke + "!!!"; //增強回傳值 System.out.println("增強方法體 2/2"); return invoke; } else { // 其它方法默認實作 Object invoke = method.invoke(target, args); return invoke; } } }); } }
4. 測驗
@Test public void test01() { // 創建目標物件 UserService target = new UserService(); System.out.println(target.getClass()); // 創建代理物件 IUserService proxy = (IUserService) new ProxyFactory(target).createProxyInstance(); System.out.println(proxy.getClass()); // 使用代理物件呼叫方法 proxy.insertUser(); String s = proxy.deleteUser(1); System.out.println(s); }
四 CGLIB代理(子類代理)
通過在記憶體中構建一個子類物件從而實作對目標物件功能的擴展 CGLIB是一個強大的高性能的代碼生成包 底層使用一個小而快的位元組碼處理框架ASM來轉換位元組碼并生成新的類
優點: 在不修改目標物件的功能前提下 對目標功能擴展 代理物件與目標物件都不需要實作介面
缺點: 需要引入CGLIB的JAR檔案
1. 目標物件
/** * 目標物件 * Created by Hy on 2020/7/10. */ public class UserService { public void insertUser() { System.out.println("insert ok"); } public String deleteUser(int id) { System.out.println("delete... ... ..."); return "id = " + id + " delete ok"; } }
2. 代理工廠
/** * 代理工廠 * Created by Hy on 2020/7/13. */ public class ProxyFactory { private Object target; //目標物件 public ProxyFactory(Object target) { this.target = target; } public Object createProxyInstance() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(new MethodInterceptor() { /** * 代理物件呼叫的所有方法都會觸發該方法執行 * @param proxy 代理物件 * @param method 被代理的方法 * @param args 被代理的方法傳參 * @param methodProxy 代理的方法 * @return 被代理的方法回傳值 * @throws Throwable 例外 */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { if ("deleteUser".equals(method.getName())) { // 增強指定方法 int id = (int) args[0]; id++; //增強引數 System.out.println("增強方法體 1/2"); String invoke = (String) method.invoke(target, id); invoke = invoke + "!!!"; //增強回傳值 System.out.println("增強方法體 2/2"); return invoke; } else { // 其它方法默認實作 Object invoke = methodProxy.invokeSuper(proxy, args); //等同 method.invoke(target, args); return invoke; } } }); return enhancer.create(); } }
3. 測驗
@Test public void test01() { // 創建目標物件 UserService target = new UserService(); System.out.println(target.getClass()); // 創建代理物件 UserService proxy = (UserService) new ProxyFactory(target).createProxyInstance(); System.out.println(proxy.getClass()); // 使用代理物件呼叫方法 proxy.insertUser(); String s = proxy.deleteUser(1); System.out.println(s); }
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/143902.html
標籤:Java
上一篇:JDK路徑設定無效問題解決
下一篇:Java常用類-Object類
