色婷婷狠狠18禁久久YY,CHINESE性内射高清国产,国产女人18毛片水真多1,国产AV在线观看

基于接口的動態代理是如何實現的

錢浩然2年前28瀏覽0評論

基于接口的動態代理是如何實現的?

什么叫動態代理

可以在運行期動態創建某個接口的實例;創建的這個代理實例可以幫我們完成很多事情,常見的比如:RPC框架中通過代理類幫助我們發送請求到遠程服務器端,Mybatis中通過代理類幫助我們映射到xml中的statement,Spring中通過代理類實現事務的控制,日志的打印等等;

如何實現

1.基于 JDK 實現動態代理,通過jdk提供的工具方法

Proxy.newProxyInstance

動態構建全新的代理類;

2.基于CGlib 動態代理模式基于繼承被代理類生成代理子類,不用實現接口;

3.基于 Aspectj 實現動態代理,在程序編譯的時候 插入動態代理的字節碼,不會生成全新的Class;

源碼分析

下面以Mybatis為例子,分析一下XXXMapper是如何通過接口調用xml中的statement的,下面看一個常見的實例:

public class BlogMain {

public static void main(String[] args) throws IOException {

String resource = "mybatis-config-sourceCode.xml";

InputStream inputStream = Resources.getResourceAsStream(resource);

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession session = sqlSessionFactory.openSession();

try {

BlogMapper mapper = session.getMapper(BlogMapper.class);

// 常規方法

System.out.println(mapper.selectBlog(101));

} finally {

session.close();

}

}

}

BlogMapper是一個接口類,我們通過

session.getMapper

的時候獲取的就是一個動態代理類,由此代理類去映射到xml中的statement;

如上代碼中使用openSession創建的一個DefaultSqlSession類,此類中包含了執行了sql的增刪改查等操作,另外還包含了getMapper方法:

此處的Configuration是關鍵,也是Mybatis的一個核心類,可以先簡單理解為就是我們的配置文件mybatis-config.xml的一個映射類;繼續往下走:

這里引出了MapperRegistry,所有的Mapper都在此類中注冊,通過key-value的形式存放,key對應xx.xx.xxMapper,而value存放的是Mapper的代理類,具體如類MapperRegistry代碼所示:

可以看到每次getMapper的時候其實都是去knownMappers獲取一個MapperProxyFactory類,至于是何時往knownMappers中添加數據的,是在解析mybatis-config.xml配置文件的時候,解析到mappers標簽的時候,如下所示:

繼續解析里面的BlogMapper.xml,會把BlogMapper.xml中的namespace作為key,如下所示:

namespace是必填的,此值作為MapperRegistry中的knownMappers的key,而value就是此Mapper類的一個代理工廠類MapperProxyFactory,每次調用getMapper的時候都會newInstance一個實例,代碼如下:

可以發現通過jdk自帶的代理類Proxy.newProxyInstance(...)創建了一個代理類,設置MapperProxy作為InvocationHandler,在實例化MapperProxy時同時傳入了一個methodCache對象,此對象是一個Map,存放的就是每個Mapper里面的方法,這里定義為MapperMethod;至此我們了解了getMapper的大致流程,下面繼續看執行方法;

當我們執行上面的mapper.selectBlog(101)時會自動觸發MapperProxy的invoke方法,此方法會幫我們映射到xml中的statement,然后執行里面配置的sql。

java動態代理,基于接口的動態代理是如何實現的