<三> MyBatis代理模式

概述

????我們首先要理解,代理模式是干什么的?我們知道,代理模式是用于松耦合的,其實代理模式是通過將主要業(yè)務(wù)與次要業(yè)務(wù)分開處理實現(xiàn)松耦合的。而代理模式的本質(zhì)是在監(jiān)控行為特征。

代理模式

????代理模式主要分兩種,靜態(tài)代理模式和動態(tài)代理模式,下面我們通過實現(xiàn)來看看兩者的具體區(qū)別到底是什么。

靜態(tài)代理模式

主要角色:

??接口(主題):定義需要被監(jiān)控的方法
??被代理類:接口的具體實現(xiàn)類
??代理類:代理被代理類的類

主要角色:

????1. 代理類和被代理類實現(xiàn)同一個主題接口。
????2. 代理類具備一個屬性,為被代理類對象。

實現(xiàn)的目的:

????核心業(yè)務(wù)邏輯由被代理類去實現(xiàn),非核心需求多變的邏輯,交給代理類實現(xiàn)。

代碼實現(xiàn)案例:

接口(主題)
public interface Proxy {
     public abstract void todo();
}
被代理類
public class Reality implements Proxy {
    @Override
    public void todo() {
        System.out.println("我是核心功能......");
    }
}
代理類
public class ProxyReality implements Proxy {
    // 被代理對象
    private Proxy reality;

    //傳入一個被代理對象
    public ProxyRole(Proxy proxy) {
        reality = proxy;
    }
    @Override
    public void todo() {
        //1. 代理類的前期準(zhǔn)備
        doBefore();
        //2. 執(zhí)行核心功能
        reality.todo();
        //3. 代理類的收尾工作
        doAfter();
    }
    private void doBefore() {
        System.out.println("我做非核心功能......");
    }
    private void doAfter() {
        System.out.println("我是多變的需求......");
    }
}
案例測試
public static void main(String[] args) {
    //1. 創(chuàng)建被代理對象
    Proxy reality = new RealityRole();
    //2. 創(chuàng)建代理對象,傳入被代理對象
    ProxyRole proxyRole = new ProxyRole(reality);
    //3. 代理對象執(zhí)行
    proxyRole.todo();
}
總結(jié):
  1. 代理類和被代理類實現(xiàn)一樣的接口。
  2. 代理類具有一個屬性對象,值為被代理類。
  3. 執(zhí)行時,調(diào)用代理類,再由代理類調(diào)用被代理類。

動態(tài)代理模式

主要角色:

??接口(主題):定義需要被監(jiān)控的方法
??被代理類:接口的具體實現(xiàn)類
??通知類:包含次要業(yè)務(wù)的具體實現(xiàn)和次要與主要的綁定
??監(jiān)控對象(代理對象):被監(jiān)控實例對象,需要被監(jiān)控的監(jiān)控行為,具體通知類實例對象

實現(xiàn)的思路:

????1. 采用通知類的方式,通知類具備一個屬性,為被代理類對象。
????2. 使用JDK的給通知類分配一個監(jiān)控對象。
????3. 通知類統(tǒng)一實現(xiàn)InvocationHandler接口。

實現(xiàn)的目的:

????核心業(yè)務(wù)邏輯由被代理類去實現(xiàn),非核心需求多變的邏輯,交給通知類實現(xiàn),不需要一個具體的代理類,而是由JDK動態(tài)生成代理對象。

JDK方式代碼實現(xiàn)案例:

接口(主題)
public interface Proxy {
     public abstract void todo();
}
被代理類
public class Reality implements Proxy {
    @Override
    public void todo() {
        System.out.println("我是核心功能......");
    }
}
通知類
public class ProxyReality implements InvocationHandler {
    // 被代理對象
    private Proxy reality;

    //傳入一個被代理對象
    public ProxyRole(Proxy proxy) {
        reality = proxy;
    }
    /**
     * 在被監(jiān)控的方法要被執(zhí)行時,執(zhí)行該方法
     * @param proxy 代理對象,例如小明.eat()
     * @param method 類似eat方法的封裝對象
     * @param args  入?yún)⒌臄?shù)組
     */
    public Object invoke(Object proxy, Method method, Object[] args) {
        //0.接受主要業(yè)務(wù)返回的對象
        Object resultObj;
          //1. 代理類的前期準(zhǔn)備
        doBefore();
         //2. 執(zhí)行核心功能
         resultObj = method.invoke(proxy,args);
        //3. 代理類的收尾工作
        doAfter();
        return resultObj;
    }
    private void doBefore() {
        System.out.println("我做非核心功能......");
    }
    private void doAfter() {
        System.out.println("我是多變的需求......");
    }
}
代理工廠類
public class ProxyFactory {
    /**
     * JDK動態(tài)代理模式下,代理對象的數(shù)據(jù)類型應(yīng)由監(jiān)控行為來描述
     * @param obj 監(jiān)控的類
     * @return
     */
    public static Proxy builder(Class obj) throws IllegalAccessException, InstantiationException {
        //1.實例化被監(jiān)控對象
        Proxy $proxy= (Proxy) obj.newInstance();
        //2.實例化通知對象,將被監(jiān)控對象傳入
        InvocationHandler adviser = new ProxyReality($proxy);
        //2、向JVM申請一個負(fù)責(zé)監(jiān)控被監(jiān)控對象的代理對象
        Proxy proxy = (Proxy) Proxy.newProxyInstance($proxy.getClass().getClassLoader(),
                        $proxy.getClass().getInterfaces(),adviser);
        return proxy;
    }
}
案例測試
public static void main(String[] args) {
    //1. 創(chuàng)建被代理對象
    Proxy reality = ProxyFactory.builder(Reality.class);
    //2. 直接調(diào)用代理對象方法執(zhí)行
    reality.todo();
}


MyBatis的動態(tài)代理模式

一、JDBC開發(fā)步驟

public void test(){
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //1. 加載驅(qū)動
            Class.forName("com.mysql.jdbc.Driver");
            //2. 建立鏈接通道
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "root");
           //3. 建立PreparedStament
            ps = con.prepareStatement("SELECT * FROM ...");
           //4. 輸送SQL命令到數(shù)據(jù)庫中執(zhí)行,并帶回運行結(jié)果
            rs = ps.executeQuery();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            // 5. 銷毀鏈接通道、PreparedStament和結(jié)果集對象
            try {
                if (rs != null) {
                    rs.close();
                    rs = null;
                }
                if (ps != null) {
                    ps.close();
                    ps = null;
                }
                if (con != null) {
                    con.close();
                    con = null;
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

二、MyBatis動態(tài)代理模式封裝JDBC

1、JDBC的主要業(yè)務(wù)和次要業(yè)務(wù)

主要業(yè)務(wù):輸送SQL命令到數(shù)據(jù)庫中執(zhí)行,并帶回運行結(jié)果
次要業(yè)務(wù):加載驅(qū)動、建立鏈接通道、建立PreparedStament和銷毀鏈接通道和PreparedStament

2、聲明接口SqlSession(定義具體的方法行為)
/**
 * 定義被監(jiān)控者接口
 */
public interface SqlSession {
    public int insert(String template,Object obj) throws SQLException;
    public int update(String template,Object obj) throws SQLException;
    public void delete(String template,Object obj) throws SQLException;
    public Object queryInfo(String template,Object obj) throws SQLException;
}
3、具體實現(xiàn)類被監(jiān)控對象

主要業(yè)務(wù):具體實現(xiàn)SQL命令執(zhí)行

/**
 * 被監(jiān)控對象實現(xiàn)
 */
public class SimpleSqlSession implements SqlSession {
    ParamentHandler parament;//入?yún)⑻幚砥?    StatementHandler statement;//執(zhí)行命令處理器
    ResultSetHandler resultSet;//結(jié)果集處理器
    PreparedStatement ps;

    /**
     * 初始化處理器
     */
    public SimpleSqlSession(){
        this.resultSet = new SimpleResultSetHandler();
        this.statement = new SimpleStatementHandler();
        this.parament = new SimpleParmentHandler();
    }
    public int insert(String template,Object obj) throws SQLException {
        String sql = parament.insert(template,obj);
        return statement.update(ps,sql);
    }
    public int update(String template,Object obj) throws SQLException {
        String sql = parament.insert(template,obj);
        return statement.update(ps,sql);
    }
    public void delete(String template,Object obj) throws SQLException {
        String sql = parament.insert(template,obj);
        statement.update(ps,sql);
    }
    public Object queryInfo(String template,Object obj) throws SQLException {
        String sql = parament.insert(template,obj);
        ResultSet object = statement.query(ps,sql);
        return resultSet.query(object);
    }
}
/**
 * 參數(shù)處理器接口
 */
public interface ParamentHandler{
    public String insert(String template,Object paremt);
    public String delete(String template,Object paremt);
    public String update(String template,Object paremt);
    public String query(String template,Object paremt);
}
/**
 * 參數(shù)處理器具體實現(xiàn)
 */
public class SimpleParmentHandler implements ParamentHandler {
    /**
     * 新增的參數(shù)處理
     */
    public String insert(String template, Object paremt) {
        String sql = null;
        //拼接入?yún)⒑蚐QL模板
        return sql;
    }
    /**
     * 刪除的參數(shù)處理
     */
    public String delete(String template, Object paremt) {
        String sql = null;
        //拼接入?yún)⒑蚐QL模板
        return sql;
    }
    /**
     * 更新的參數(shù)處理
     */
    public String update(String template, Object paremt) {
        String sql = null;
        //拼接入?yún)⒑蚐QL模板
        return sql;
    }
    /**
     * 查詢的參數(shù)處理
     */
    public String query(String template, Object paremt) {
        String sql = null;
        //拼接入?yún)⒑蚐QL模板
        return sql;
    }
}
/**
 * 命令執(zhí)行處理器接口
 */
public interface  StatementHandler{
    public int update(PreparedStatement ps,String sql) throws SQLException;
    public ResultSet query(PreparedStatement ps, String sql) throws SQLException;
}
/**
 * 命令執(zhí)行處理器具體實現(xiàn)
 */
public class SimpleStatementHandler implements StatementHandler{
    /**
     * 執(zhí)行更新指令
     */
    public int update(PreparedStatement ps,String sql) throws SQLException {
        return ps.executeUpdate(sql);
    }
    /**
     * 執(zhí)行查詢指令
     */
    public ResultSet query(PreparedStatement ps, String sql) throws SQLException {
        return ps.executeQuery(sql);
    }
}
/**
 * 返回參數(shù)格式化處理器接口
 */
public interface ResultSetHandler {
    public Object query(ResultSet resultSet) throws SQLException;
}
/**
 * 返回參數(shù)格式化處理器具體實現(xiàn)
 */
public class SimpleResultSetHandler implements ResultSetHandler{

    public Object query(ResultSet resultSet) throws SQLException {
        //格式化為具體對象(反射賦值)
        resultSet.close();
        resultSet = null;
        return null;
    }
}
4、通知類:實現(xiàn)InvocationHandler,在構(gòu)造方法定義具體入?yún)qlSession,實現(xiàn)具體次要業(yè)務(wù)。
/**
 * 通知類(實現(xiàn)次要業(yè)務(wù))
 */
public class Plugin implements InvocationHandler {

    SqlSession session;
    Connection con = null;
    PreparedStatement ps = null;

    public Plugin(SqlSession session){
        this.session = session;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1. 傳值給會話對象
        setPreparedStatement();
        //2. 前置處理
        frontLoad();
        //3. 執(zhí)行主要業(yè)務(wù)
        Object result = method.invoke(session,args);
        //4. 后置處理
        closeLoad();
        return result;
    }
    /**
     * 反射賦值
     */
    private void setPreparedStatement() throws NoSuchFieldException, IllegalAccessException {
        Field field = session.getClass().getDeclaredField("ps");
        field.setAccessible(true);
        field.set(session,ps);
    }
    /**
     * 前置處理
     * @throws Exception
     */
    private void frontLoad() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "root");
        ps = con.prepareStatement("");
    }
    /**
     * 后置處理
     * @throws SQLException
     */
    private void closeLoad() throws SQLException {
        if (ps != null) {
            ps.close();
            ps = null;
        }
        if (con != null) {
            con.close();
            con = null;
        }
    }
}
5、實現(xiàn)代理工廠SqlSessionFactory
/**
 * 代理工廠
 */
public class SqlSessionFactory {
    /**
     * JDK動態(tài)代理模式下,代理對象的數(shù)據(jù)類型應(yīng)由監(jiān)控行為來描述
     * @param obj 監(jiān)控的類
     * @return
     */
    public static SqlSession builder(Class obj) throws IllegalAccessException, InstantiationException {
        //1.創(chuàng)建被監(jiān)控對象
        SqlSession session = (SqlSession) obj.newInstance();
        //2.創(chuàng)建通知對象
        InvocationHandler adviser = new Plugin(session);
        //2、向JVM申請一個負(fù)責(zé)監(jiān)控被監(jiān)控對象的代理對象
        SqlSession proxy = (SqlSession) Proxy.newProxyInstance(session.getClass().getClassLoader(),
                session.getClass().getInterfaces(),adviser);
        return proxy;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容