一 代理模式簡介
代理(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); }