java动态代理

今天在读mybatis-spring的源码时,看到下面一段代码(红色部分),其中 this.sqlSessionProxy 是SqlSession接口类型 ,通过动态代理的方式产生了实例对象

  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
            PersistenceExceptionTranslator exceptionTranslator) {

        Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
        Assert.notNull(executorType, "Property 'executorType' is required");

        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
                SqlSessionFactory.class.getClassLoader(),
                new Class[] { SqlSession.class },
                new SqlSessionInterceptor());
    通过跟踪代码发现其产生的代理实例对象是 org.apache.ibatis.session.defaults.DefaultSqlSession,查看了一下,SqlSession是一个接口,其实现类有好几个,当时很奇怪为什么动态代理这段代码产生的实例类型会是DefaultSqlSession呢,

经过分析发现,是由Proxy这个动态代码类的
 public static Object newProxyInstance(ClassLoader loader,
       Class<?>[] interfaces,
       InvocationHandler h)     方法中最后一个参数InvocationHandler决定的,创建动态代理对象时必须要传入
InvocationHandler类型的参数,动态代理对象产生后,对后续调用时,其时调的是InvocationHandler接口实例的
 public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable;方法,通过该方法的传参,可以得到当前要调用的方法参数method,和方法的传参args,下面看一下
 mybatis-spring的代码是如何实现这个InvocationHandler接口的
  private class SqlSessionInterceptor implements InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            final SqlSession sqlSession = SqlSessionUtils.getSqlSession(
                    SqlSessionTemplate.this.sqlSessionFactory,
                    SqlSessionTemplate.this.executorType,
                    SqlSessionTemplate.this.exceptionTranslator);
            try {
                Object result = method.invoke(sqlSession, args);
                if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                    sqlSession.commit();
                }
                return result;
            } catch (Throwable t) {
                Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
                if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                    unwrapped = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
                }
                throw unwrapped;
            } finally {
                SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            }
        }
    }

posted @   杭州胡欣  阅读(777)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示