概述
????我們首先要理解凛辣,代理模式是干什么的绝编?我們知道孕豹,代理模式是用于松耦合的框弛,其實(shí)代理模式是通過將主要業(yè)務(wù)與次要業(yè)務(wù)分開處理實(shí)現(xiàn)松耦合的辛辨。而代理模式的本質(zhì)是在監(jiān)控行為特征。
代理模式
????代理模式主要分兩種瑟枫,靜態(tài)代理模式和動(dòng)態(tài)代理模式斗搞,下面我們通過實(shí)現(xiàn)來看看兩者的具體區(qū)別到底是什么。
靜態(tài)代理模式
主要角色:
??接口(主題):定義需要被監(jiān)控的方法
??被代理類:接口的具體實(shí)現(xiàn)類
??代理類:代理被代理類的類
主要角色:
????1. 代理類和被代理類實(shí)現(xiàn)同一個(gè)主題接口慷妙。
????2. 代理類具備一個(gè)屬性僻焚,為被代理類對象。
實(shí)現(xiàn)的目的:
????核心業(yè)務(wù)邏輯由被代理類去實(shí)現(xiàn)景殷,非核心需求多變的邏輯溅呢,交給代理類實(shí)現(xiàn)澡屡。
代碼實(shí)現(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;
//傳入一個(gè)被代理對象
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é):
- 代理類和被代理類實(shí)現(xiàn)一樣的接口咐旧。
- 代理類具有一個(gè)屬性對象驶鹉,值為被代理類。
- 執(zhí)行時(shí)铣墨,調(diào)用代理類室埋,再由代理類調(diào)用被代理類。
動(dòng)態(tài)代理模式
主要角色:
??接口(主題):定義需要被監(jiān)控的方法
??被代理類:接口的具體實(shí)現(xiàn)類
??通知類:包含次要業(yè)務(wù)的具體實(shí)現(xiàn)和次要與主要的綁定
??監(jiān)控對象(代理對象):被監(jiān)控實(shí)例對象伊约,需要被監(jiān)控的監(jiān)控行為姚淆,具體通知類實(shí)例對象
實(shí)現(xiàn)的思路:
????1. 采用通知類的方式,通知類具備一個(gè)屬性屡律,為被代理類對象腌逢。
????2. 使用JDK的給通知類分配一個(gè)監(jiān)控對象。
????3. 通知類統(tǒng)一實(shí)現(xiàn)InvocationHandler接口超埋。
實(shí)現(xiàn)的目的:
????核心業(yè)務(wù)邏輯由被代理類去實(shí)現(xiàn)搏讶,非核心需求多變的邏輯,交給通知類實(shí)現(xiàn)霍殴,不需要一個(gè)具體的代理類媒惕,而是由JDK動(dòng)態(tài)生成代理對象。
JDK方式代碼實(shí)現(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;
//傳入一個(gè)被代理對象
public ProxyRole(Proxy proxy) {
reality = proxy;
}
/**
* 在被監(jiān)控的方法要被執(zhí)行時(shí)来庭,執(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動(dòng)態(tài)代理模式下,代理對象的數(shù)據(jù)類型應(yīng)由監(jiān)控行為來描述
* @param obj 監(jiān)控的類
* @return
*/
public static Proxy builder(Class obj) throws IllegalAccessException, InstantiationException {
//1.實(shí)例化被監(jiān)控對象
Proxy $proxy= (Proxy) obj.newInstance();
//2.實(shí)例化通知對象月弛,將被監(jiān)控對象傳入
InvocationHandler adviser = new ProxyReality($proxy);
//2肴盏、向JVM申請一個(gè)負(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的動(dòng)態(tài)代理模式
一、JDBC開發(fā)步驟
public void test(){
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1. 加載驅(qū)動(dòng)
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í)行尊搬,并帶回運(yùn)行結(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動(dòng)態(tài)代理模式封裝JDBC
1佛寿、JDBC的主要業(yè)務(wù)和次要業(yè)務(wù)
主要業(yè)務(wù):輸送SQL命令到數(shù)據(jù)庫中執(zhí)行,并帶回運(yùn)行結(jié)果
次要業(yè)務(wù):加載驅(qū)動(dòng)但壮、建立鏈接通道冀泻、建立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蜡饵、具體實(shí)現(xiàn)類被監(jiān)控對象
主要業(yè)務(wù):具體實(shí)現(xiàn)SQL命令執(zhí)行
/**
* 被監(jiān)控對象實(shí)現(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ù)處理器具體實(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í)行處理器具體實(shí)現(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ù)格式化處理器具體實(shí)現(xiàn)
*/
public class SimpleResultSetHandler implements ResultSetHandler{
public Object query(ResultSet resultSet) throws SQLException {
//格式化為具體對象(反射賦值)
resultSet.close();
resultSet = null;
return null;
}
}
4弹渔、通知類:實(shí)現(xiàn)InvocationHandler,在構(gòu)造方法定義具體入?yún)qlSession溯祸,實(shí)現(xiàn)具體次要業(yè)務(wù)肢专。
/**
* 通知類(實(shí)現(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. 傳值給會(huì)話對象
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舞肆、實(shí)現(xiàn)代理工廠SqlSessionFactory
/**
* 代理工廠
*/
public class SqlSessionFactory {
/**
* JDK動(dòng)態(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申請一個(gè)負(fù)責(zé)監(jiān)控被監(jiān)控對象的代理對象
SqlSession proxy = (SqlSession) Proxy.newProxyInstance(session.getClass().getClassLoader(),
session.getClass().getInterfaces(),adviser);
return proxy;
}
}