mysql時間函式總結
阿新 • • 發佈:2020-12-12
技術標籤:設計模式
定義
給某一個物件提供代理,由代理物件控制對原物件的引用,可以在代理物件中進行特殊的處理。遵循設計模式開閉原則。
目的
有時直接對原物件進行改造成本比較大或者是第三方提供的介面,無法在原物件進行修改,這時需要自己進行實現介面。可以通過代理模式,通過對原物件的引用,只需要在呼叫原方法之前進行特殊邏輯處理。
分類
靜態代理、JDK動態代理、CGLib動態代理
程式碼實現
1.靜態代理:
實現同一個介面,代理物件通過對目標物件的引用對外提供功能。
public interface BuyHouse { /** * 買房 */ void buyHouse(); } //預設的實現,即目標物件 public class DefaultBuyHouse implements BuyHouse { @Override public void buyHouse() { System.out.println("-----DefaultBuyHouse 實現-----"); } } //代理物件 public class ProxyBuyHouse implements BuyHouse { /** * 持有目標物件 */ private DefaultBuyHouse defaultBuyHouse; public ProxyBuyHouse(DefaultBuyHouse defaultBuyHouse) { this.defaultBuyHouse = defaultBuyHouse; } //重寫目標方法,呼叫目標物件方法,並做特殊處理 @Override public void buyHouse() { System.out.println("=====代理之前做的事情======"); defaultBuyHouse.buyHouse(); System.out.println("=====代理之後做的事情======"); } }
優點:遵循開閉原則,可以對原物件進行擴充套件。
缺點:需要人工建立代理類,工作量大,如果介面發生改變,代理類也要發生變化。
2.JDK動態代理
通過JDK提供的代理功能實現動態代理,只需要重寫動態處理器,通過
Proxy.newProxyInstance(ClassLoader loader,//指定當前目標物件使用的類載入器
Class<?>[] interfaces,//指定目標物件實現的介面陣列,因為可以實現多個介面
InvocationHandler h)//動態處理器,執行目標物件的方法時,會觸發處理器的方法
在執行時生成代理類,當呼叫代理類時,執行動態處理器中的方法。
//重寫動態處理器 public class DynamicBuyHouseProxyHandler implements InvocationHandler { //目標物件 private Object target; public DynamicBuyHouseProxyHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("====dynamicproxy買房前====="); Object result = method.invoke(target,args); System.out.println("====dynamicproxy買房後====="); return result; } }
優點:相對於靜態代理,減少開發,同時減少對業務介面的依賴,降低耦合度。
缺點:被代理的類必須實現interface,否則不能被JDK代理。因為JDK生成的代理類繼承了Proxy類,java是單繼承,因此只能對interface進行動態代理。
3.CGLib動態代理
對於沒有實現介面的類,需要通過CGLib實現動態代理。CGLib採用底層的位元組碼技術,通過位元組碼技術為一個類建立子類,並在子類中採用方法攔截技術攔截所有方法的呼叫,順勢織入橫切邏輯。因為是繼承,所以不能對final的類進行代理。
//建立CGLib代理類 public class CglibDynamicProxy implements MethodInterceptor { /** * 目標物件 */ private Object target; public CglibDynamicProxy(Object target) { this.target = target; } public Object getProxyInstance(){ //工具類 Enhancer enhancer = new Enhancer(); //設定父類 enhancer.setSuperclass(target.getClass()); //設定回撥函式 enhancer.setCallback(this); //建立代理物件 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("=====cglib動態代理前===="); Object result = method.invoke(target,objects); System.out.println("=====cglib動態代理後===="); return result; } }
優點:可以對類進行代理,不用必須實現某一介面
缺點:CGLib建立代理物件時間比JDK代理多,同時由於CGLib是建立子類的方式,所以無法對final類進行代理。
public class ProxyTest {
public static void main(String[] args) {
DefaultBuyHouse defaultBuyHouse = new DefaultBuyHouse();
//靜態代理
ProxyBuyHouse proxyBuyHouse = new ProxyBuyHouse(defaultBuyHouse);
proxyBuyHouse.buyHouse();
//JDK動態代理
BuyHouse jdkDynamicProxy = (BuyHouse) Proxy.newProxyInstance(
//目標物件使用的類載入器
BuyHouse.class.getClassLoader(),
//目標類實現的所有介面
new Class[]{BuyHouse.class},
//目標類的動態處理器,在執行目標方法時觸發
new DynamicBuyHouseProxyHandler(defaultBuyHouse));
jdkDynamicProxy.buyHouse();
//CGLib動態代理
CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(defaultBuyHouse);
BuyHouse proxy = (BuyHouse)cglibDynamicProxy.getProxyInstance();
proxy.buyHouse();
}
}
原始碼中用到
Mybatis中SqlSession、DefaultSqlSession、SqlSessionTemplate之間,SqlSessionTemplate是一個典型的靜態代理和動態代理相結合的使用方式。
//實現同一個介面SqlSession
public class SqlSessionTemplate implements SqlSession, DisposableBean {
private final SqlSessionFactory sqlSessionFactory;
private final ExecutorType executorType;
//持有目標類SqlSession
private final SqlSession sqlSessionProxy;
private final PersistenceExceptionTranslator exceptionTranslator;
//構造方法
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
//賦值目標類是動態生成的的代理類
this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class }, new SqlSessionInterceptor());
}
}
//動態處理器
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
//在動態處理器中呼叫目標類的方法
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
。。。
} finally {
。。。
}
}
}