代理模式coding-动态代理
生活随笔
收集整理的這篇文章主要介紹了
代理模式coding-动态代理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我們看一下里邊都做了什么,這里先打一個斷點,F6,我們在這個方法的最下邊先打一個斷點,防止出現問題的時候直接跳過去了, @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);}/** Look up or generate the designated proxy class.*/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);}}public static <T> T requireNonNull(T obj) {if (obj == null)throw new NullPointerException();return obj;}final SecurityManager sm = System.getSecurityManager();也就是里面傳的this,這里面對傳入的接口進行安全的檢查,這里就是動態代理的核心方法,動態代理的核心思路,生成一個新類,CGLib是生成一個子類,通過這個名字能夠看出來獲取一個代理的Proxy0,就是動態的,我們進入這個方法來看一下Class<?> cl = getProxyClass0(loader, intfs);/*** 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) {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 ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces);} 首先對接口的數量進行了一個判斷, if (interfaces.length > 65535) 如果一個接口的數量操作65535個,就會報錯,提示非法的參數異常,當然這個種情況非常少見,這個類也是在是太厲害了,可以寫6萬5千個接口,接著往下看,return proxyClassCache.get(loader, interfaces);這里面可以看出來,在代理類生成的Class,里面是有一個Cache的,也就是說代理類的緩存,那如果緩存里有這個代理類,就直接返回,如果沒有我們看一下,get里面又做了什么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);}}}}這里使用了CocurrentMap,然后對他進行一系列的判斷,接著往下走,注意看這里邊,這里有一個Factory,就是工廠模式的工廠,如果Cat里面沒有這個代理類的話,就走到while (true)這一行,這里面是while true循環,只有在return value;這里進行返回,那如果if里面沒有進行返回的話,就開始返回這個工廠factory = new Factory(key, parameter, subKey, valuesMap);然后把工廠賦值給supplier,然后在上邊對工廠進行循環if (supplier != null) {// supplier might be a Factory or a CacheValue<V> instanceV value = supplier.get();if (value != null) {return value;}
} 這樣就獲取了這個代理類,接著回到Proxy里面,我們把里面的斷點先去掉,F6單步,在try這一片區域呢,我們可以看到,就是根據生成的Class,通過反射獲取對應的構造參數,然后根據這個構造參數呢,生成對應的實例,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});} 也是通過對應的構造器生成對應的實例,F6單步走, Class<?> cl = getProxyClass0(loader, intfs); 我們開始講了有一個getProxyClass0,他們是對應的,所以生成的這個類,就是剛剛那個方法創建的代理類,我們也可以展開來看一下,他代理的什么類,target,那接下類我們就要調用代理類的saveOrder方法,public interface InvocationHandler {/*** Processes a method invocation on a proxy instance and returns* the result. This method will be invoked on an invocation handler* when a method is invoked on a proxy instance that it is* associated with.** @param proxy the proxy instance that the method was invoked on** @param method the {@code Method} instance corresponding to* the interface method invoked on the proxy instance. The declaring* class of the {@code Method} object will be the interface that* the method was declared in, which may be a superinterface of the* proxy interface that the proxy class inherits the method through.** @param args an array of objects containing the values of the* arguments passed in the method invocation on the proxy instance,* or {@code null} if interface method takes no arguments.* Arguments of primitive types are wrapped in instances of the* appropriate primitive wrapper class, such as* {@code java.lang.Integer} or {@code java.lang.Boolean}.** @return the value to return from the method invocation on the* proxy instance. If the declared return type of the interface* method is a primitive type, then the value returned by* this method must be an instance of the corresponding primitive* wrapper class; otherwise, it must be a type assignable to the* declared return type. If the value returned by this method is* {@code null} and the interface method's return type is* primitive, then a {@code NullPointerException} will be* thrown by the method invocation on the proxy instance. If the* value returned by this method is otherwise not compatible with* the interface method's declared return type as described above,* a {@code ClassCastException} will be thrown by the method* invocation on the proxy instance.** @throws Throwable the exception to throw from the method* invocation on the proxy instance. The exception's type must be* assignable either to any of the exception types declared in the* {@code throws} clause of the interface method or to the* unchecked exception types {@code java.lang.RuntimeException}* or {@code java.lang.Error}. If a checked exception is* thrown by this method that is not assignable to any of the* exception types declared in the {@code throws} clause of* the interface method, then an* {@link UndeclaredThrowableException} containing the* exception that was thrown by this method will be thrown by the* method invocation on the proxy instance.** @see UndeclaredThrowableException*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
} invoke方法的最上邊,關于Proxy對象的一個描述,可以看到這個注釋說的還是比較清楚的,代理的對象,@param proxy the proxy instance that the method was invoked on也就是說這個方法是屬于proxy instance的,那我們接著回來動態代理是比較核心的,Spring AOP也是建立在JDK的動態代理之上的,當然呢還有CGLib,Spring的AOP也是依賴于JDK的動態代理的,所以動態代理還是非常重要的,那現在我們通過JDK的動態代理,對AOP進行了一個簡單的實現,在目標對象的方法執行之前,和執行之后呢,都進行了增強,那Spring的AOP也使用到了Proxy這個類,同時他也會使用InvocationHandler這個類,他也是在這個基礎之上,當然這里說的是對接口的代理,CGLib是單獨的,那么回到測試類里面,代理模式可以說是AOP非常重要的一個基礎,也是重點來講了一下,例如說單例模式,代理模式,這種對于我們以后提高非常重要的知識點呢,會重點來講,希望對靜態代理和動態代理呢,這兩塊有深刻的認識,同時可以對他們進行一個對比理解
package com.learn.design.pattern.structural.proxy.dynamicproxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;import com.learn.design.pattern.structural.proxy.Order;
import com.learn.design.pattern.structural.proxy.db.DataSourceContextHolder;/*** 在這里創建一個類* OrderServiceDynamicProxy* 讓他來實現InvocationHandler* 然后寫一下他的實現方法* * * * @author Leon.Sun**/
public class OrderServiceDynamicProxy implements InvocationHandler {/*** 目標對象* 那這個目標對象如何放進來呢* * */private Object target;/*** 我們通過構造器* * target是目標類* 目標類就是OrderService的實現* 那里面的DAO沒有注入成功* 這個忽略就可以了* 因為我們是顯示而寫的* 只有saveOrder的時候才會生成* 這個忽略就行* target目標類已經在這里了* 于是給目標代理類target類進行賦值* * * * @param target*/public OrderServiceDynamicProxy(Object target) {this.target = target;}/*** 然后我們再寫一個綁定的方法* 這里面就要獲取proxy的代理對象* 這么一個靜態方法* 怎么寫呢* * 他通過Proxy* newProxyInstance* 來返回代理類* 所以這里面分號是不行的* 我們還要調用一下他的bind方法* 然后對他進行強轉* 他就是一個IOrderService類型* 然后調用它的Order.saveOrder方法* * bind打上斷點* 這個時候就調用了bind這個方法* 首先把目標對象的Class拿到* * * * @return*/public Object bind(){/*** 首先獲取一個class* 這個class是目標類的class* 也就是target的getClass* 然后return一個對象* 這個對象通過Proxy.newProxyInstance* 靜態方法* 來進行生成* target里面獲得ClassLoader* 從這里面獲得接口的一個復數* 返回值是class類型* 還有自己* 這樣綁定之后* 就通過Proxy的newProxyInstance* 把這個Object就返回回去了* 那在這個類里面叫OrderService* 那如果使用動態代理的話* 這里面可以補充一些判斷邏輯* 如果使用靜態代理* 例如Order在分庫的時候* 我們要寫一個Order的靜態代理* 如果這個時候要是有其他的類* 要做分庫的時候* 還要對那個類寫一個靜態代理* 而動態代理不僅僅是針對Order這么一個實體* 比如說針對這個用戶的抽獎信息* 我們也可以通過userId進行分庫* 都可以通過這一個動態代理進行復用* 而不用每一個類都寫一套靜態代理* 那這個就是動態代理和靜態代理很大的一個區別* 那因為動態代理是動態生成的* 靜態代理要顯示的來描述* 來coding* 那接下來我們接著寫* * * */Class cls = target.getClass();/*** 然后看一下這行* 這行是動態代理的核心* 把這個class的ClassLoader* 聲明的接口* 注意這里面是復數* 還有他本身自己傳進來* 那我們就進來看一下* */return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);}
// InvocationHandler h;/*** 這個方法三個參數* 第一個參數在我們平時寫動態代理invoke方法的時候* 幾乎用不上他* 那第二個參數是method* 也就是說要被增強的方法對象* 第三個是具體的method的參數* 那我們再說以proxy* proxy在這個方法實現里邊* 很少使用這個對象* 那為什么還要傳過來呢* 一會我們debug的時候* 也會來說一下proxy這個對象* 我們先寫* 一會debug的時候* 來講解一下* 首先我們聲明一個對象* * 那在invoke的時候* 我們也說了* beforeMethod* 還有afterMethod* * 接著我們回到invoke方法中* invoke很簡單* 我們首先把argument參數拿出來* 那因為我們這里面比較簡單* 對于說這個方法就一個參數* 后續邏輯復雜的時候* 我們可以自己完善這個邏輯* * invoke也打上斷點* 現在進入到invoke方法里面了* invoke有三個參數* proxy也就是這個代理類* method就是要增強的哪個方法呢* saveOrder* OrderService這個類的saveorder這個方法* 那后邊的arguments呢* 自然是參數* 參數是Order* saveOrder的時候傳入的參數呢* 正是Order* 那剛剛我前面有說* proxy在invoke的實現里面呢* 很少用到他* 但是他要傳過來* 后面的method* 和arguments* 正來自對應的proxy* 很簡單* 這個proxy代理類* 他呢是動態生成的* 那有興趣的可以把這個動態生成的類* 進行持久化* 然后通過反編譯* 看一下這個$符的class文件* 反編譯的過來的代碼* 里面有獲取method* 因為這個method是proxy的method* 他通過Class.forName* 也就是method這個反射包下的method* 只有在proxy的這個實例* 在我們現在實現的這個接口* InvocationHandler* 加載之后才能產生對應的method* 所以這個生成的proxy* 傳給invoke方法* 我們看一下InvocationHandler接口里面的聲明* * 現在就要調用method的invoke方法* * */@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*** 首先我們創建一個對象* argObject等于什么呢* 等于argument的第0個元素* * */Object argObject = args[0];/*** 然后調用beforeMethod* 把Order傳進去* 也就是把這個參數傳進去* 因為我們在調用saveOrder方法的時候* 傳的參數正是Order類型* * 進入beforeMethod* * */beforeMethod(argObject);/*** 那這個時候我們聲明一個Object* 就是要被增強的方法的返回值* 因為增強不同的方法* 返回值不一定一樣* 但是他們的父類都是Object* 所以用Object來接他* method.invoke* invoke什么呢* 目標對象target* 把參數傳進去* * 代理哪個類呢* target* 參數傳進來* F6單步* 這個時候可以看到* 進入了真正的目標類的saveOrder方法里邊* * */Object object = method.invoke(target,args);/*** 我們再調用一下afterMethod* * */afterMethod();/*** 最后把方法的返回值返回回去* 那這個動態代理就寫完了* 非常簡單* 我們現在寫一個Test來run一下* * */return object;}/*** 我們先寫一個beforeMethod* 用動態代理來實現* 這里我們就把調用方法的參數* 傳進來* 傳進來干嘛呢* 進行取模運算* * 我們就要把數據庫確定了* 我們現在寫一下* * 通過obj的一個類型* instanceof這么一個判斷* 然后進行相同的取模邏輯* 確定目標DB* * 到這里邊單步走* * * @param obj*/private void beforeMethod(Object obj){/*** 首先初始化一個userId等于0* 那我們就要在beforeMethod里面* 對userId進行取模* 然后確定分配到哪個db上* 當然分配到哪個db上* 我們可以把里面的實現* 寫到invoke里邊* * 動態代理* * */int userId = 0;System.out.println("動態代理 before code");/*** 如果obj是Order類型* 剛剛說了* 那我們也可以在這里進行判斷* 抽獎信息這個類* 我們只有Order這個類* * 然后進行類型判斷* * */if(obj instanceof Order){/*** 如果是這個類型就對他進行強轉* obj強轉成Order* * */Order order = (Order)obj;/*** 然后把userId賦值* 通過order的getUserId* 接下來就和靜態代理是一樣的* 我們把這里面的拿過來* copy到這里面* * 對userId進行賦值* * */userId = order.getUserId();}/*** 取模*/int dbRouter = userId % 2;/*** 這里面是動態代理db* * * */System.out.println("動態代理分配到【db"+dbRouter+"】處理數據");//todo 設置dataSource;DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));}private void afterMethod(){/*** 這里面是動態代理after code* * */System.out.println("動態代理 after code");}
}
package com.learn.design.pattern.structural.proxy.staticproxy;import com.learn.design.pattern.structural.proxy.IOrderService;
import com.learn.design.pattern.structural.proxy.Order;
import com.learn.design.pattern.structural.proxy.OrderServiceImpl;
import com.learn.design.pattern.structural.proxy.db.DataSourceContextHolder;/*** 這個類是靜態代理類* OrderService的靜態代理* 這里面也很簡單* 我們首先在這個靜態代理類里邊* * * @author Leon.Sun**/
public class OrderServiceStaticProxy {/*** 來注入目標對象* 那這里面的IOrderService* 是目標對象* 我們要對saveOrder方法* 進行增強* 那我們來到orderService里邊* * */private IOrderService iOrderService;/*** 當然使用不同的方法名也是OK的* 這里面并沒有嚴格的限制* 寫一個before和after* 那后面我們講源碼解析的時候* 也會領著大家來看一下* 那就是Spring里面的beforeAdvice* 在AOP包下的* 還有afterAdvice* 只不過我們通過靜態代理* 非常簡單的一個實現* 所以我們聲明兩個方法* 一個beforeMethod* 還有一個* afterMethod* 直接輸出* 輸出什么呢* * * @param order* @return*/public int saveOrder(Order order){/*** 首先調用beforeMethod* * */beforeMethod(order);/*** 先把這個Service new出來* 這里面和DAO層一樣* 如果使用Spring容器的話就不需要顯示的來new了* 那現在我們獲取userId* * service的實現* 如果使用Spring容器的話* 這里面不需要顯示的來new他* * */iOrderService = new OrderServiceImpl();/*** 調用saveOrder方法* 然后把Order傳進來* Spring的分庫實現* 首先我們創建一個包* 這個包叫db* 這里面我們創建一個類* DynamicDataSource* 動態的數據源* * */int result = iOrderService.saveOrder(order);/*** 這個after我們要拿到對應的saveOrder之后* 也就是我們增強的是saveOrder* 怎么辦呢* 在這里面再優化一下* 然后調用afterMethod* 這里面的界限怎么劃分呢* 很簡單* saveOrder是為了增強OrderService的saveOrder* 所以我們要把saveOrder這一行* 單獨領出來* 那執行完saveOrder之后* 這個才是比較符合代理模式* 那像剛才這種實現方案* afterMetho和beforeMethod* 都在saveOrder前面* 都是一個beforeMethod* 所以這里埋了一個伏筆* 就是要對這一段要印象深刻* 那現在這種實現* 通過before就把目標數據庫* 已經確定了* 那這塊大家肯定都理解了* * * */afterMethod();return result;}/*** 執行saveOrder之前要執行的* * 那首先在saveOrder之前* 我們調用一下beforeMethod* 對saveOrder進行一個增強* * beforeMethod里面并沒有寫實現* 而是把分庫的實現寫到saveOrder里邊* 所以這個時候靜態代理* 我們就要改進一下了* 如何改進呢* 很簡單* 例如beforeMethod把order傳進來* 我們要把方法的界限劃清楚* 執行代理模式的時候* 很容易劃分不清楚* 埋了一個伏筆* 那這個初始化還是放到這里邊* 我們把下邊拿走* 拿到beforeMethod這里邊* 然后調用的時候傳進來* 但是我們又想一下* * * * @param order*/private void beforeMethod(Order order){/*** order獲取userId* * * */int userId = order.getUserId();/*** 獲得DB的路由編號* 用userId對2進行取模* 這樣只會得到0或者1* * 在這里取完模之后呢* 我們就要寫一段代碼* 設置dataSource* 怎么設置呢* * 然后對2取模* 2對2取余余數是0* 所以dbRouter是0* * */int dbRouter = userId % 2;/*** 然后我們輸出一下* 靜態代理增強了OrderService的實現* 把DB切到DB Router這個上* db0或者db1* * 輸出這一行* * */System.out.println("靜態代理分配到【db"+dbRouter+"】處理數據");//todo 設置dataSource;/*** 我們直接調用DataSourceContextHolder* 我們自己寫的* 然后setDBType* 把什么傳進來呢* 把dbRouter* 只不過我們現在這里沒有和Spring容器集成* String類型的* String.valueOf* 那這個靜態代理類就寫完了* 根據userId的不同* 插入到不同的DB當中* 一個是db0* 一個是db1* 那我們現在來到靜態代理這個包下* 寫一個Test* * 然后把DataSourceContextHolder里面的DBType* 設置為0* 當然這里講代理模式的時候* 這一行執不執行都沒關系* 只不過這里面只是為了擴展* 所以分庫的一些知識點* 調一下他的getDBType* 可以看到這里面是0* 那這里面是有問題的* 這里面要存的是db0* 也就是說在寫分庫的時候* 這里很容易忽略* 里面的dbType和我們配置文件里面的是一樣* 這里不要出bug* 而我在這里面就做了一個反面教材* * * */DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));System.out.println("靜態代理 before code");}/*** 這個是執行saveOrder之后要執行的代碼* * */private void afterMethod(){System.out.println("靜態代理 after code");}
}
package com.learn.design.pattern.structural.proxy.dynamicproxy;import com.learn.design.pattern.structural.proxy.IOrderService;
import com.learn.design.pattern.structural.proxy.Order;
import com.learn.design.pattern.structural.proxy.OrderServiceImpl;/*** 我們看到結果和預期是一樣的* 動態代理before code* 然后動態代理分配到db0上處理數據* service層調用DAO層* 添加Order* DAO層添加Order成功* 動態代理after code* 這里和預期完全一致* 分配到db1上處理數據* 和預期是一樣的* 那接下來我們debug來跑一下* 同時進行講解* 那我們直接在這里面打上兩個斷點* 然后debug來跑一下* 首先進入這個動態代理類的構造器* 我們進來* * * * @author Leon.Sun**/
public class Test {/*** 寫一個主函數* 如何測試呢* * 這里和靜態的測試類差不多* 我們先拿過來* * * @param args*/public static void main(String[] args) {/*** 聲明一個Order* new一個Order出來* * */Order order = new Order();/*** 注意1對2取模的時候* 余數是1* 2對2取余的時候* 余數是0* 所以我們在run的時候* 這里面應該是db0數據庫* 我們run一下* 結果已經出來了* 和我們預期是一樣的* 那我們現在debug來運行一下* 我們一起來體會一下* 流程是怎么走的* 直接debug* * */order.setUserId(2);/*** 現在我們設置userId* 為1* * */
// order.setUserId(1);/*** 然后獲取靜態代理類* 我們就直接new一個好了* 那在實際的項目當中* 我們可以在這個代理類上增加注解* 比如說Component* 來表示這個類是一個組件* 這樣的話我們直接使用就可以了* 那這里面我們采用new的方式* 是為了講解方便* * 我們進到這個靜態代理類里邊* * 我們使用OrderService這么一個接口* 我們現在是動態代理* 我們直接代理這個接口就OK了* 所以用接口來接收他* orderServiceDynamicProxy這個不是靜態代理* 而是動態代理* 看一下后邊* 后邊要怎么寫呢* 我們首先要new一個動態代理這個類* 然后傳入一個參數* 我們要增強哪個類呢* 當然是要增強service的實現* 也就是OrderServiceImpl* 這么一個類* 但是呢并沒有結束* 注意我們在動態代理里面寫的* 返回值bind這個方法* * 可以看到現在這個代理類* 我們來看一下這個類型* 他呢是一個$Proxy0* 是這么一個類型* 但是它是用IOrderService進行引用聲明的* * */IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();/*** 然后我們調用它的saveOrder方法* order傳進來* 我們直接run一下* 我們看一下結果* 首先靜態執行了beforeMethod* 然后把它分配到db1上處理數據* 然后執行了afterCode* 也就是afterMethod里面的內容* 然后service層調用了DAO層* 添加Order* DAO層添加order成功* 那我們現在把它改成2* * */orderServiceDynamicProxy.saveOrder(order);}
}
package com.learn.design.pattern.structural.proxy;/*** @author Leon.Sun**/
public interface IOrderService {/*** 這里面有一個方法* saveOrder* 里面傳一個實體Order* 保存這個訂單* 再寫一個DAO層的接口* * 我們要增強這個方法* 所以我們使用同樣的方法名* * * * @param order* @return*/int saveOrder(Order order);
}
package com.learn.design.pattern.structural.proxy;/*** 他來實現IOrderService* 實現IOrderService里的方法* 當然我們現在這個分層比較簡單* Service下邊是DAO* 那在Service之上是Controller* 那也有業務邏輯復雜的情況下呢* 加一個Manager層* Manager位于DAO層之上* * * @author Leon.Sun**/
public class OrderServiceImpl implements IOrderService {/*** 把DAO層注入進來* 只不過我們這里并沒有集成Spring* 所以像@Autowired和@Resource我們并不用加* 然后我們會通過人工注入的方式* 把OrderDao注入進來* 那我們寫一個Service的實現* */private IOrderDao iOrderDao;@Overridepublic int saveOrder(Order order) {//Spring會自己注入,我們課程中就直接new了/*** 我們課程中就直接new了* 直接new出來* DAO層的implement* 當然如果這一行使用Spring容器管理的話* 我們就不用顯示的來寫了* 或者在應用層使用set方法注入進來* 或者通過構造器注入也是OK的* 我們為了簡單* 直接在這里new了* 但是我們實際在也業務的時候* 是不應該這么寫的* 因為這樣DAO層會new很多對象* 那對于DAO層來說* 保持一個單例是OK的* * 這里面創建了一個DAO層* * */iOrderDao = new OrderDaoImpl();/*** 然后我們輸出* service層調用DAO添加Order* * */System.out.println("Service層調用Dao層添加Order");/*** DAO層調用insert方法* 把Order傳進來* 那這個Service實現就寫完了* 那我們再看一下包* 這個包的類是非常的common的* 實體* DAO層* service層* 只不過我們講設計模式都放在這個包下了* 下面我們就不分包了* 那現在我們要進行分庫了* 怎么分庫呢* 我們看一下Order* * 調用DAO的insert方法* * */return iOrderDao.insert(order);}
}
?
總結
以上是生活随笔為你收集整理的代理模式coding-动态代理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代理模式coding-静态代理
- 下一篇: 代理模式源码解析(jdk+spring+