1. 程式人生 > 其它 >Spring中的代理模式(jdk為主)

Spring中的代理模式(jdk為主)

代理的分類:靜態代理 動態代理(jdk動態代理/cglib動態代理)

    1. 靜態代理:

    描述:有多個業務類,就有多少個代理類,代理類,在編譯之前就已經存在了,和業務類同時存在。

    靜態代理:

       1、需要知道核心類(被代理類)是哪一個類,並且有什麼方法。 

       2、非核心的程式碼需要重複寫多次,顯得程式碼的結構臃腫,形成程式碼冗餘。

       3、非核心類(代理類)需要實現核心類(被代理類)實現的介面,也就是他們需要實現共同的介面,但是以核心類實現的介面(被代理類)為準。

    l目地是將業務程式碼與日誌程式碼完全分離,實現鬆散耦合.

    l代理物件與被代理物件必須實現同一介面,在代理物件中實現與日誌記錄的相關服務

    ,並在需要的時候呼叫被代理物件,而被代理物件只保留業務程式碼.

     

    靜態代理的弊端:

    一個代理介面只能服務於一種型別的物件.對於稍大點的專案根本無法勝任.

    靜態代理的實現:

    1、先確定核心類(被代理的類)。

    其中的方法:

    @Resource
    private UserDao userDao;

    public void inserts(User user) throws SQLException {
        userDao.insert(user);
        SpringCha springCha = new SpringCha();
        springCha.setHabit("先吃再睡");
        springCha.setHobby("吃喝睡

    ");
        userDao.insert(springCha);
    }

     

    2、在去編寫非核心類。

    事務處理:

    @Resource
    private TManager tManager;
    @Resource
    private UserServiceImpl1 userServiceImpl1;
    public void inserts(User user) throws SQLException {
        try {
            tManager.closeCommit();
            userServiceImpl1.inserts(user);
            tManager.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            tManager.rollBack();
        }

    }

     

    3、在使用非核心類。

     

  1. 動態代理(jdk):

    1. 利用靜態代理中的核心類(這個核心類是靜態和動態所需的)
    2. 在建立一個類(xxxProxy)來實現InvocationHandler介面
    3. 在實現InvocationHandler後,進行編寫裡面的方法

    //使用註解把實現動態代理的類注入spring容器中
    @Component
    public class Dynamic implements InvocationHandler {
        @Resource(name = "userServiceImpl1")
        private Object object;

        /**
         * 用來在測試類中進行測試時獲取例項,以及介面
         * UserService o = (UserService)Proxy.newProxyInstance(
         *                 dynamic.getObject().getClass().getClassLoader(),
         *                 dynamic.getObject().getClass().getInterfaces(),
         *                 dynamic);
         * @return
         */

     

    /**

         * 當用戶呼叫物件中的每個方法時都通過下面的方法執行,方法必須在介面

         * proxy 被代理後的物件

         * method 將要被執行的方法資訊(反射)

         * args 執行方法時需要的引數

         */


        public Object getObject() {
            return object;
        }

        /**
         * 事務處理,來處理後續資料庫操作可能出現的錯誤
         */
        @Resource
        private TManager tManager;

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object invoke=null;
            try {
    //            關閉自動提交事務
                tManager.closeCommit();
    //            返回我們需要動態代理的實現類
                invoke= method.invoke(object, args);
    //            手動提交事務
                tManager.commit();
            } catch (SQLException e) {
                e.printStackTrace();
    //            事務回滾
                tManager.rollBack();
            }
            
            return invoke;
        }
    }

     

    1. 在使用(在測試中使用)

    /**
     * 動態代理
     */
    @Resource
    private Dynamic dynamic;

    @Test
    public void testInsert2() throws SQLException {

    // 在使用動態代理,在返回實現類但是需要使用它的介面

    /**

    * 通過ProxynewProxyInstance方法來建立我們的代理物件,我們來看看其三個引數

          * 第一個引數 dynamic.getObject().getClass().getClassLoader(),我們這裡使用handler這個類的ClassLoader物件來載入我們的代理物件

          * 第二個引數dynamic.getObject().getClass().getInterfaces(),是為代理物件提供的介面是真實物件所實行的介面,表示我要代理的是該真實物件,這樣我就能呼叫這組介面中的方法了

          * 第三個引數dynamic,將這個代理物件關聯到了上方的 InvocationHandler 這個物件上

          */


        UserService o = (UserService)Proxy.newProxyInstance(
                dynamic.getObject().getClass().getClassLoader(),
                dynamic.getObject().getClass().getInterfaces(),
                dynamic);

        User user = new User();
        user.setName("");
        user.setPassword("201619");
        o.inserts(user);
    }

     

    並且在使用實現動態代理有一個問題:被代理的類必須實現介面,未實現介面則沒辦法完成動態代理。而且在動態代理類中也是隻能去處理一個被代理類。