[java][源码分析]paoding-rose-jade框架源码分析(2)

在分析动态代理回调的invoke 方法之前,我们先看下factory.create(UserDAO.class) 里面做了什么。

1.JadeFactory工厂分析

JadeFactory类的代码如下:

public class JadeFactory {

    private RowMapperFactory rowMapperFactory = new DefaultRowMapperFactory();

    private DefaultInterpreterFactory interpreterFactory = new DefaultInterpreterFactory();

    private DataAccessFactoryAdapter dataAccessFactory;

    private CacheProvider cacheProvider;

    // 可选的
    private StatementWrapperProvider statementWrapperProvider;

    public JadeFactory() {
    }

    public JadeFactory(DataSource defaultDataSource) {
        setDataSourceFactory(new SimpleDataSourceFactory(defaultDataSource));
    }

    public JadeFactory(DataSourceFactory dataSourceFactory) {
        setDataSourceFactory(dataSourceFactory);
    }

    public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
        this.dataAccessFactory = new DataAccessFactoryAdapter(dataSourceFactory);
    }

    public void setCacheProvider(CacheProvider cacheProvider) {
        this.cacheProvider = cacheProvider;
    }

    public DataSourceFactory getDataSourceFactory() {
        if (this.dataAccessFactory == null) {
            return null;
        }
        return this.dataAccessFactory.getDataSourceFactory();
    }

    public void setRowMapperFactory(RowMapperFactory rowMapperFactory) {
        this.rowMapperFactory = rowMapperFactory;
    }

    public StatementWrapperProvider getStatementWrapperProvider() {
        return statementWrapperProvider;
    }

    public void setStatementWrapperProvider(StatementWrapperProvider statementWrapperProvider) {
        this.statementWrapperProvider = statementWrapperProvider;
    }

    public void addInterpreter(Interpreter... interpreters) {
        for (Interpreter interpreter : interpreters) {
            interpreterFactory.addInterpreter(interpreter);
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T create(Class<?> daoClass) {
        try {
            DAOConfig config = new DAOConfig(dataAccessFactory, rowMapperFactory,
                interpreterFactory, cacheProvider, statementWrapperProvider);
            DAOMetaData daoMetaData = new DAOMetaData(daoClass, config);
            JadeInvocationHandler handler = new JadeInvocationHandler(daoMetaData);
            ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
            return (T) Proxy.newProxyInstance(classLoader, new Class[] { daoClass }, handler);
        } catch (RuntimeException e) {
            throw new IllegalStateException("failed to create bean for " + daoClass.getName(), e);
        }
    }
}

我们需要关注的是create() 方法:

    public <T> T create(Class<?> daoClass) {
        try {
            DAOConfig config = new DAOConfig(dataAccessFactory, rowMapperFactory,
                interpreterFactory, cacheProvider, statementWrapperProvider);
            DAOMetaData daoMetaData = new DAOMetaData(daoClass, config);
            JadeInvocationHandler handler = new JadeInvocationHandler(daoMetaData);
            ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
            return (T) Proxy.newProxyInstance(classLoader, new Class[] { daoClass }, handler);
        } catch (RuntimeException e) {
            throw new IllegalStateException("failed to create bean for " + daoClass.getName(), e);
        }
    }

create() 方法中:
1.新建了一个DAOConfig对象。DAOConfig的功能非常简单,它仅仅用于封装dataAccessFactory, rowMapperFactory,interpreterFactory, cacheProvider, statementWrapperProvider这4个对象,并提供对应的get方法,以供调用。

public class DAOConfig {
    private final DataAccessFactory dataAccessFactory;
    private final RowMapperFactory rowMapperFactory;
    private final InterpreterFactory interpreterFactory;
    private final CacheProvider cacheProvider;
    private final StatementWrapperProvider statementWrapperProvider;
    public DAOConfig(DataAccessFactory dataAccessFactory, //
                     RowMapperFactory rowMapperFactory, //
                     InterpreterFactory interpreterFactory, CacheProvider cacheProvider,
                     StatementWrapperProvider statementWrapperProvider) {
        this.dataAccessFactory = dataAccessFactory;
        this.rowMapperFactory = rowMapperFactory;
        this.interpreterFactory = interpreterFactory;
        this.cacheProvider = cacheProvider;
        this.statementWrapperProvider = statementWrapperProvider;
    }
    public DataAccessFactory getDataAccessFactory() {
        return dataAccessFactory;//标准数据访问器配置
    }
    public InterpreterFactory getInterpreterFactory() {
        return interpreterFactory;//SQL解析器配置
    }
    public RowMapperFactory getRowMapperFactory() {
        return rowMapperFactory;//OR映射配置
    }
    public CacheProvider getCacheProvider() {
        return cacheProvider;
    }
    public StatementWrapperProvider getStatementWrapperProvider() {
        return statementWrapperProvider;
    }
}

2.新建一个JadeInvocationHandler对象,这个handler对象就比较重要了,它是我们上次断点跟进去的invoke() 方法所在的对象。它实现了InvocationHandler接口,这是典型的java动态代理创建过程。


一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args)

3.接下的代码就是java动态代理创建过程。
这里有一篇文章讲得非常详细http://www.cnblogs.com/flyoung2008/archive/2013/08/11/3251148.html

2.invoke方法分析

先贴出代码:

/**
 * DAO代理处理器(一个DAO类对应一个处理器实例)
 * 
 * @author 王志亮 [qieqie.wang@gmail.com]
 * 
 */
public class JadeInvocationHandler implements InvocationHandler {

    private static final Log logger = LogFactory.getLog(JadeInvocationHandler.class);
    private static final Log sqlLogger = LogFactory.getLog("jade_sql.log");

    private final ConcurrentHashMap<Method, Statement> statements = new ConcurrentHashMap<Method, Statement>();

    private final DAOMetaData daoMetaData;

    /**
     * 
     * @param daoMetaData
     */
    public JadeInvocationHandler(DAOMetaData daoMetaData) {
        this.daoMetaData = daoMetaData;
    }

    /**
     * 
     * @return
     */
    public DAOMetaData getDAOMetaData() {
        return daoMetaData;
    }

    private static final String[] INDEX_NAMES = new String[] { ":1", ":2", ":3", ":4", ":5", ":6",
            ":7", ":8", ":9", ":10", ":11", ":12", ":13", ":14", ":15", ":16", ":17", ":18", ":19",
            ":20", ":21", ":22", ":23", ":24", ":25", ":26", ":27", ":28", ":29", ":30", };

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        final boolean debugEnabled = logger.isDebugEnabled();
        if (debugEnabled) {
            logger.debug("invoking " + daoMetaData.getDAOClass().getName() + "#" + method.getName());
        }

        // 调用object的方法
        if (method.getDeclaringClass() == Object.class) {
            return invokeObjectMethod(proxy, method, args);
        }
        // 获取当前DAO方法对应的Statement对象
        Statement statement = getStatement(method);
        //
        // 将参数放入  Map
        Map<String, Object> parameters;
        StatementMetaData statemenetMetaData = statement.getMetaData();
        if (args == null || args.length == 0) {
            parameters = new HashMap<String, Object>(4);
        } else {
            parameters = new HashMap<String, Object>(args.length * 2 + 4);
            for (int i = 0; i < args.length; i++) {
                parameters.put(INDEX_NAMES[i], args[i]);
                SQLParam sqlParam = statemenetMetaData.getSQLParamAt(i);
                if (sqlParam != null) {
                    parameters.put(sqlParam.value(), args[i]);
                }
            }
        }
        // logging
        if (debugEnabled) {
            logger.info("invoking " + statemenetMetaData);
        }

        // executing
        long begin = System.currentTimeMillis();
        final Object result = statement.execute(parameters);
        long cost = System.currentTimeMillis() - begin;

        // logging
        if (sqlLogger.isInfoEnabled()) {
            sqlLogger.info(statemenetMetaData + "\tcost " + cost + "ms." );
        }
        return result;
    }

    private Statement getStatement(Method method) {
        Statement statement = statements.get(method);
        if (statement == null) {
            synchronized (method) {
                statement = statements.get(method);
                if (statement == null) {
                    // config
                    DAOConfig config = daoMetaData.getConfig();
                    DataAccessFactory dataAccessFactory = config.getDataAccessFactory();
                    RowMapperFactory rowMapperFactory = config.getRowMapperFactory();
                    InterpreterFactory interpreterFactory = config.getInterpreterFactory();
                    CacheProvider cacheProvider = config.getCacheProvider();
                    StatementWrapperProvider wrapperProvider = config.getStatementWrapperProvider();

                    // create
                    StatementMetaData smd = new StatementMetaData(daoMetaData, method);
                    SQLType sqlType = smd.getSQLType();
                    Querier querier;
                    if (sqlType == SQLType.READ) {
                        RowMapper<?> rowMapper = rowMapperFactory.getRowMapper(smd);
                        querier = new SelectQuerier(dataAccessFactory, smd, rowMapper);
                    } else {
                        querier = new UpdateQuerier(dataAccessFactory, smd);
                    }
                    Interpreter[] interpreters = interpreterFactory.getInterpreters(smd);
                    statement = new JdbcStatement(smd, sqlType, interpreters, querier);
                    if (cacheProvider != null) {
                        statement = new CachedStatement(cacheProvider, statement);
                    }
                    if (wrapperProvider != null) {
                        statement = wrapperProvider.wrap(statement);
                    }
                    statements.put(method, statement);
                }
            }
        }
        return statement;
    }

    private Object invokeObjectMethod(Object proxy, Method method, Object[] args) 
            throws CloneNotSupportedException {
        String methodName = method.getName();
        if (methodName.equals("toString")) {
            return JadeInvocationHandler.this.toString();
        }
        if (methodName.equals("hashCode")) {
            return daoMetaData.getDAOClass().hashCode() * 13 + this.hashCode();
        }
        if (methodName.equals("equals")) {
            return args[0] == proxy;
        }
        if (methodName.equals("clone")) {
            throw new CloneNotSupportedException("clone is not supported for jade dao.");
        }
        throw new UnsupportedOperationException(daoMetaData.getDAOClass().getName() + "#"
                + method.getName());
    }

    @Override
    public String toString() {
        DAO dao = daoMetaData.getDAOClass().getAnnotation(DAO.class);
        String toString = daoMetaData.getDAOClass().getName()//
                + "[catalog=" + dao.catalog() + "]";
        return toString;
    }

}

1.
这里写图片描述
这段代码用于记录日志对我们分析没什么作用,忽略

2.
这里写图片描述
这个method对象UserDao对象的createTable()方法的反射对象(它的原理是java的反射机制),method.getDeclaringClass() 获得的是UserDao的类对象,它显然和Object的类对象不等。
debug信息如图:
这里写图片描述

3.
这里写图片描述
可以推测这个getStatement(mehtod) 方法是我们这次分析的重头戏,可以说核心工作就是在这里完成的。因为这里是invoke中唯一 一个处理非Object类对象的method的方法,可以猜想@SQL("create table user (id int, name varchar(200));") 注解就是在这个方法内被处理后生成Statement对象的。这个方法内的分析我们留在下次进行。

4.
这里写图片描述
因为void createTable(); 的方法声明中没有参数,所以args为null,所以这段代码只是创建一个HashMap对象parameters。

5.最后final Object result = statement.execute(parameters); 执行SQL语句并返回结果。
这样代理对象的回调方法就执行完毕了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值