【设计模式】代理模式 ( 动态代理 )
生活随笔
收集整理的這篇文章主要介紹了
【设计模式】代理模式 ( 动态代理 )
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 一、動態代理使用流程
- 二、動態代理代碼示例
- 1、訂單類
- 2、Service 接口
- 3、Service 實現類
- 4、Service 靜態代理類
- 5、Dao 接口
- 6、Dao 實現類
- 7、Service 動態代理類
- 8、測試類
- 三、動態代理源碼分析
一、動態代理使用流程
動態的代理類使用流程 :
1. 內部持有 目標對象2. 創建動態代理類 , 調用 Proxy.newProxyInstance 創建動態代理類系統會自動創建一個類 , 該類實現了目標對象的所有接口的所有方法最后返回一個該動態代理類的實例對象3. 調用動態代理類實例對象的某個接口方法 , 會自動回調 動態代理類的 invoke 函數注意 : 被代理的方法必須是 目標對象 的接口中的方法二、動態代理代碼示例
業務場景 : 保存訂單信息 , 在 Service 層處理訂單保存 , 在 Dao 層將訂單存儲到數據庫 ; 使用動態代理類加強 Service 層的功能 ;
1、訂單類
package proxy;/*** 訂單類* 存儲訂單時 , 通過 Service 層通接收 Order 對象進行處理*/ public class Order {/*** 訂單信息*/private Object orderInfo;/*** 用戶 ID*/private Integer userId;public Order(Object orderInfo, Integer userId) {this.orderInfo = orderInfo;this.userId = userId;}public Object getOrderInfo() {return orderInfo;}public void setOrderInfo(Object orderInfo) {this.orderInfo = orderInfo;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;} }
2、Service 接口
package proxy;/*** 服務接口*/ public interface IOrderService {/*** 保存訂單* @param order 數據庫生效行數* @return*/int saveOrder(Order order); }
3、Service 實現類
package proxy;public class OrderServiceImpl implements IOrderService {private IOrderDao iOrderDao;public OrderServiceImpl(IOrderDao iOrderDao) {this.iOrderDao = iOrderDao;}@Overridepublic int saveOrder(Order order) {System.out.println("Service 層插入 Order 訂單信息成功");return this.iOrderDao.insert(order);} }
4、Service 靜態代理類
package proxy;/*** 訂單服務靜態代理類*/ public class OrderServiceStaticProxy {private IOrderService iOrderService;public OrderServiceStaticProxy(IOrderService iOrderService) {this.iOrderService = iOrderService;}public int saveOrder(Order order){beforeMethod();int result = iOrderService.saveOrder(order);afterMethod();return result;}/*** 在被代理對象方法之前執行的內容*/private void beforeMethod() {System.out.println("靜態代理 OrderServiceStaticProxy 執行 saveOrder 之前");}/*** 在被代理對象方法之后執行的內容*/private void afterMethod() {System.out.println("靜態代理 OrderServiceStaticProxy 執行 saveOrder 之后");} }
5、Dao 接口
package proxy;/*** 數據庫接口*/ public interface IOrderDao {/*** 向數據庫中插入訂單信息* @param order* @return*/int insert(Order order); }
6、Dao 實現類
package proxy;public class OrderDaoImpl implements IOrderDao {@Overridepublic int insert(Order order) {System.out.println("Dao 層插入 Order 訂單信息成功");return 1;} }
7、Service 動態代理類
package proxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;/*** 訂單服務動態代理類** 動態的代理類使用流程 :* 1. 內部持有 目標對象* 2. 創建動態代理類 , 調用 Proxy.newProxyInstance 創建動態代理類* 系統會自動創建一個類 , 該類實現了目標對象的所有接口的所有方法* 最后返回一個該動態代理類的實例對象* 3. 調用動態代理類實例對象的某個接口方法 , 會自動回調 動態代理類的 invoke 函數* 注意 : 被代理的方法必須是 目標對象 的接口中的方法*/ public class OrderServiceDynamicProxy implements InvocationHandler {private Object target;public OrderServiceDynamicProxy(IOrderService iOrderService) {this.target = iOrderService;}/*** 綁定方法* 將目標對象與動態代理類進行綁定*/public Object bind() {// 拿到目標對象的類Class clazz = target.getClass();// 動態代理類時系統執行的時候自動生成的類 , 該類自動實現了指定的接口// 動態代理類會獲取目標對象的所有接口 , 并實現所有的接口中的所有的方法// 該動態代理類 代理的是 target 的接口的方法 , 即 IOrderService 接口的方法// 凡是調用創建的動態代理實例對象中的 IOrderService 接口方法 , 都會觸發該類的 invoke 方法return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);}/*** 調用代理類的 IOrderService 接口方法 , 就會自動回調該方法* 注意 : 所有的 IOrderService 接口方法 , 都會回調該方法* 在回調時 , 需要判定一下 , 是哪個方法回調的 , 過濾掉不需要加強的方法** @param proxy 該參數幾乎用不到* @param method 要被增強的方法對象* @param args 要被增強的方法對象的參數* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {beforeMethod();// 調用目標對象的 method 方法Object object = method.invoke(target, args);afterMethod();return object;}/*** 在被代理對象方法之前執行的內容*/private void beforeMethod() {System.out.println("動態代理 OrderServiceStaticProxy 執行 saveOrder 之前");}/*** 在被代理對象方法之后執行的內容*/private void afterMethod() {System.out.println("動態代理 OrderServiceStaticProxy 執行 saveOrder 之后");}}
8、測試類
package proxy;public class Main {public static void main(String[] args) {Order order = new Order("書籍訂單", 1);IOrderDao dao = new OrderDaoImpl();IOrderService service = new OrderServiceImpl(dao);// 不使用代理的情況service.saveOrder(order);System.out.println();// 使用靜態代理的情況OrderServiceStaticProxy proxy = new OrderServiceStaticProxy(service);proxy.saveOrder(order);System.out.println();// 使用動態代理的情況IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(service).bind();orderServiceDynamicProxy.saveOrder(order);} }
執行結果 :
Service 層插入 Order 訂單信息成功 Dao 層插入 Order 訂單信息成功靜態代理 OrderServiceStaticProxy 執行 saveOrder 之前 Service 層插入 Order 訂單信息成功 Dao 層插入 Order 訂單信息成功 靜態代理 OrderServiceStaticProxy 執行 saveOrder 之后動態代理 OrderServiceStaticProxy 執行 saveOrder 之前 Service 層插入 Order 訂單信息成功 Dao 層插入 Order 訂單信息成功 動態代理 OrderServiceStaticProxy 執行 saveOrder 之后三、動態代理源碼分析
動態代理的核心步驟是 Proxy.newProxyInstance 調用 ;
傳入 333 個參數分別是 : ① 目標對象類加載器 , ② 目標對象實現的接口 , ③ 動態代理類本身 ( InvocationHandler 實現類 ) ;
public class Proxy implements java.io.Serializable {/*** Returns an instance of a proxy class for the specified interfaces* that dispatches method invocations to the specified invocation* handler.** <p>{@code Proxy.newProxyInstance} throws* {@code IllegalArgumentException} for the same reasons that* {@code Proxy.getProxyClass} does.** @param loader the class loader to define the proxy class* @param interfaces the list of interfaces for the proxy class* to implement* @param h the invocation handler to dispatch method invocations to* @return a proxy instance with the specified invocation handler of a* proxy class that is defined by the specified class loader* and that implements the specified interfaces* @throws IllegalArgumentException if any of the restrictions on the* parameters that may be passed to {@code getProxyClass}* are violated* @throws SecurityException if a security manager, <em>s</em>, is present* and any of the following conditions is met:* <ul>* <li> the given {@code loader} is {@code null} and* the caller's class loader is not {@code null} and the* invocation of {@link SecurityManager#checkPermission* s.checkPermission} with* {@code RuntimePermission("getClassLoader")} permission* denies access;</li>* <li> for each proxy interface, {@code intf},* the caller's class loader is not the same as or an* ancestor of the class loader for {@code intf} and* invocation of {@link SecurityManager#checkPackageAccess* s.checkPackageAccess()} denies access to {@code intf};</li>* <li> any of the given proxy interfaces is non-public and the* caller class is not in the same {@linkplain Package runtime package}* as the non-public interface and the invocation of* {@link SecurityManager#checkPermission s.checkPermission} with* {@code ReflectPermission("newProxyInPackage.{package name}")}* permission denies access.</li>* </ul>* @throws NullPointerException if the {@code interfaces} array* argument or any of its elements are {@code null}, or* if the invocation handler, {@code h}, is* {@code null}*/@CallerSensitivepublic static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{// 進行空校驗 Objects.requireNonNull(h);// 對傳入的接口進行安全檢查 final Class<?>[] intfs = interfaces.clone();final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}// 動態代理的思路是生成一個新類/** 動態生成一個代理類*/Class<?> cl = getProxyClass0(loader, intfs);/** Invoke its constructor with the designated invocation handler.*/try {if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}// 通過反射獲取代理類的構造函數 , 并根據構造函數生成實例對象 final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}// 返回動態代理類生成的實例對象return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}}/*** Generate a proxy class. Must call the checkProxyAccess method* to perform permission checks before calling this.*/private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {// 判定接口數量 , 接口不能超過 65535 個 throw new IllegalArgumentException("interface limit exceeded");}// If the proxy class defined by the given loader implementing// the given interfaces exists, this will simply return the cached copy;// otherwise, it will create the proxy class via the ProxyClassFactory// 代理類生成的 Class 都緩存在此 , 如果緩存中有這個代理類 , 直接獲取 // 如果緩存中 , 沒有這個代理類 , 創建這個代理類 return proxyClassCache.get(loader, interfaces);}/*** Look-up the value through the cache. This always evaluates the* {@code subKeyFactory} function and optionally evaluates* {@code valueFactory} function if there is no entry in the cache for given* pair of (key, subKey) or the entry has already been cleared.** @param key possibly null key* @param parameter parameter used together with key to create sub-key and* value (should not be null)* @return the cached value (never null)* @throws NullPointerException if {@code parameter} passed in or* {@code sub-key} calculated by* {@code subKeyFactory} or {@code value}* calculated by {@code valueFactory} is null.*/public V get(K key, P parameter) {Objects.requireNonNull(parameter);expungeStaleEntries();Object cacheKey = CacheKey.valueOf(key, refQueue);// lazily install the 2nd level valuesMap for the particular cacheKeyConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);if (valuesMap == null) {ConcurrentMap<Object, Supplier<V>> oldValuesMap= map.putIfAbsent(cacheKey,valuesMap = new ConcurrentHashMap<>());if (oldValuesMap != null) {valuesMap = oldValuesMap;}}// create subKey and retrieve the possible Supplier<V> stored by that// subKey from valuesMapObject subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));Supplier<V> supplier = valuesMap.get(subKey);Factory factory = null;while (true) {// 如果找到對應的類 , 直接返回 if (supplier != null) {// supplier might be a Factory or a CacheValue<V> instanceV value = supplier.get();if (value != null) {return value;}}// 如果緩存中沒有這個類 , 開始創建這個類// else no supplier in cache// or a supplier that returned null (could be a cleared CacheValue// or a Factory that wasn't successful in installing the CacheValue)// lazily construct a Factoryif (factory == null) {factory = new Factory(key, parameter, subKey, valuesMap);}if (supplier == null) {supplier = valuesMap.putIfAbsent(subKey, factory);if (supplier == null) {// successfully installed Factorysupplier = factory;}// else retry with winning supplier} else {if (valuesMap.replace(subKey, supplier, factory)) {// successfully replaced// cleared CacheEntry / unsuccessful Factory// with our Factorysupplier = factory;} else {// retry with current suppliersupplier = valuesMap.get(subKey);}}}} }
總結
以上是生活随笔為你收集整理的【设计模式】代理模式 ( 动态代理 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【设计模式】代理模式 ( 静态代理 )
- 下一篇: 【设计模式】组合模式 ( 简介 | 适用