MyBatis 簡單代碼講解動態代理原理

先運行mybatis例子

public class SqlSessionFactoryTest {
	public static void main(String[] args) throws IOException {
		String resource = "mybatis/mybatis-config.xml";
		Reader reader = Resources.getResourceAsReader(resource);
		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
		SqlSessionFactory sqlSessionFactory = builder.build(reader);
		System.out.println(sqlSessionFactory);
	}
}

運行結果

DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@1d56ce6a
DEBUG [main] - Created connection 1865127310.
DEBUG [main] - ooo Connection Opened
DEBUG [main] - ==>  Executing: select * from Role where id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==    Columns: id, name, desc
DEBUG [main] - <==        Row: 1, name, test
org.mybatis.example.domain.Role@16b3fc9e

以上代碼對應分析的源碼過程

下面的例子不用在意,可直接跳過
在這裏插入圖片描述

核心代碼演示

jdbc訪問數據庫

public class MySQLDemo {
	static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
	static final String DB_URL = "jdbc:mysql://127.0.0.1/mybatis";

	// 數據庫的用戶名與密碼,需要根據自己的設置
	static final String USER = "root";
	static final String PASS = "root";

	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		try {
			// 註冊 JDBC 驅動
			Class.forName(JDBC_DRIVER);

			// 打開鏈接
			System.out.println("連接數據庫...");
			conn = DriverManager.getConnection(DB_URL, USER, PASS);

			// 執行查詢
			System.out.println(" 實例化Statement對象...");
			stmt = conn.createStatement();
			String sql;
			sql = "select * from Role";
			ResultSet rs = stmt.executeQuery(sql);

			// 展開結果集數據庫
			while (rs.next()) {
				// 通過字段檢索
				int id = rs.getInt("id");
				String name = rs.getString("name");
				String desc = rs.getString("desc");

				// 輸出數據
				System.out.print("ID: " + id);
				System.out.print(", 名稱: " + name);
				System.out.print(", 描述: " + desc);
				System.out.print("\n");
			}
			// 完成後關閉
			rs.close();
			stmt.close();
			conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (stmt != null)
					stmt.close();
			} catch (SQLException se2) {
			}
			try {
				if (conn != null)
					conn.close();
			} catch (SQLException se) {
			}
		}
		System.out.println("Goodbye!");
	}
}

運行結果

連接數據庫...
 實例化Statement對象...
ID: 1, 名稱: name, 描述: test
Goodbye!

核心功能改造

將上述jdbc訪問改造爲工具類

public class SQLUtils {
	static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
	static final String DB_URL = "jdbc:mysql://127.0.0.1/mybatis";

	// 數據庫的用戶名與密碼,需要根據自己的設置
	static final String USER = "root";
	static final String PASS = "root";

	public static void executeSql(String sql) {
		Connection conn = null;
		Statement stmt = null;
		try {
			// 註冊 JDBC 驅動
			Class.forName(JDBC_DRIVER);

			// 打開鏈接
			System.out.println("連接數據庫...");
			conn = DriverManager.getConnection(DB_URL, USER, PASS);

			// 執行查詢
			System.out.println(" 實例化Statement對象...");
			stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery(sql);

			// 展開結果集數據庫
			while (rs.next()) {
				// 通過字段檢索
				int id = rs.getInt("id");
				String name = rs.getString("name");
				String desc = rs.getString("desc");

				// 輸出數據
				System.out.print("ID: " + id);
				System.out.print(", 名稱: " + name);
				System.out.print(", 描述: " + desc);
				System.out.print("\n");
			}
			// 完成後關閉
			rs.close();
			stmt.close();
			conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (stmt != null)
					stmt.close();
			} catch (SQLException se2) {
			}
			try {
				if (conn != null)
					conn.close();
			} catch (SQLException se) {
			}
		}
		System.out.println("Goodbye!");
	}
}

定義接口

public interface RoleDao {
	void query();
}

這裏不定義xml,直接定義json,新建文件:priv.dengjili.mybatis.example.proxy.RoleDao.json

{
	"query":"select * from Role"
}

核心代理類

public class MethodProxy implements InvocationHandler {

	private String filePath;
	
	public MethodProxy(String filePath) {
		this.filePath = filePath;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		String content = FileUtils.readFileToString(new File(filePath), Charset.defaultCharset());
		JSONObject jsonObject = JSONObject.parseObject(content);
		String sql = jsonObject.getString(method.getName());
		SQLUtils.executeSql(sql);
		return null;
	}

  public static <T> T newMethodProxy(Class<T> mapperInterface, String filePath) {
	    ClassLoader classLoader = mapperInterface.getClassLoader();
	    Class[] interfaces = new Class[]{mapperInterface};
	    MethodProxy proxy = new MethodProxy(filePath);
	    return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);
	  }
}

測試類

public class ProxyTest {
	public static void main(String[] args) {
		RoleDao dao = MethodProxy.newMethodProxy(RoleDao.class, "C:/temp-workspace/workspace/mybatis-handwritten/src/main/resources/priv.dengjili.mybatis.example.proxy.RoleDao.json");
		dao.query();
	}
}

運行結果

連接數據庫...
 實例化Statement對象...
ID: 1, 名稱: name, 描述: test
Goodbye!

mybatis主要思想也就是上述思想

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章