1. 程式人生 > 其它 >mysql時間函式總結

mysql時間函式總結

技術標籤:設計模式

定義

給某一個物件提供代理,由代理物件控制對原物件的引用,可以在代理物件中進行特殊的處理。遵循設計模式開閉原則。

圖片名稱

目的

有時直接對原物件進行改造成本比較大或者是第三方提供的介面,無法在原物件進行修改,這時需要自己進行實現介面。可以通過代理模式,通過對原物件的引用,只需要在呼叫原方法之前進行特殊邏輯處理。

分類

靜態代理、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 {
      。。。
    }
  }
}