net.paoding.rose —— jade模块源码分析
2017-07-26 00:00
344 查看
使用过rose框架的朋友都知道,rose中dao都是interface类型,那它的实例到底是如何生成的呢?
我们以UserDAO来讲一下到底是如何生成的,并且rose是如何执行sql的
一丶生成UserDAO 以下代码为源码中的测试用例
创建一个数据源
至此我们想要的UserDAO的实例就创建好了,jadeFactory对象的create方法
Proxy.newProxyInstance()方法说明
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
二、调用实例中的方法并执行sql
invoke方法
statement的execute方法,判断是否为批处理,然后调用先前statement获得的执行器处理sql
最终调用spring 的 jdbcTemplate执行sql并返回记录
getPreparedStatementCreator()方法的实现
hsldb 链接:http://pan.baidu.com/s/1i5Jyd0p 密码:l733
我们以UserDAO来讲一下到底是如何生成的,并且rose是如何执行sql的
/** * jade约定了bean的id为jade.dataSource.classPackageName。 * jade约定了这个bean的有效范围为classPackageName所有的DAO。 * jade约定了除非有专门的定义,所有的子目录也受bean上的classpackageName所影响。 * 如果配置文件中没有加载到jade.dataSource的bean,则寻找dataSource bean **/ public DataSourceHolder getHolder(StatementMetaData metaData, Map<String, Object> runtimeProperties) { Class<?> daoClass = metaData.getDAOMetaData().getDAOClass(); DataSourceHolder holder = cachedDataSources.get(daoClass); if (holder != null) { return holder; } holder = getDataSourceByDirectory(daoClass, daoClass.getName()); if (holder != null) { cachedDataSources.put(daoClass, holder); return holder; } String catalog = daoClass.getAnnotation(DAO.class).catalog(); if (catalog.length() > 0) { holder = getDataSourceByDirectory(daoClass, catalog + "." + daoClass.getSimpleName()); } if (holder != null) { cachedDataSources.put(daoClass, holder); return holder; } holder = getDataSourceByKey(daoClass, "jade.dataSource"); if (holder != null) { cachedDataSources.put(daoClass, holder); return holder; } holder = getDataSourceByKey(daoClass, "dataSource"); if (holder != null) { cachedDataSources.put(daoClass, holder); return holder; } return null; } private DataSourceHolder getDataSourceByKey(Class<?> daoClass, String key) { if (applicationContext.containsBean(key)) { Object dataSource = applicationContext.getBean(key); if (!(dataSource instanceof DataSource) && !(dataSource instanceof DataSourceFactory)) { throw new IllegalClassException("expects DataSource or DataSourceFactory, but a " + dataSource.getClass().getName()); } if (logger.isDebugEnabled()) { logger.debug("found dataSource: " + key + " for DAO " + daoClass.getName()); } return new DataSourceHolder(dataSource); } return null; }
一丶生成UserDAO 以下代码为源码中的测试用例
UserDAO dao = getUserDAO();
/** * 初始调用位置 */ private UserDAO getUserDAO() { DataSource dataSource = DataSources.createUniqueDataSource(); JadeFactory factory = new JadeFactory(dataSource); UserDAO dao = factory.create(UserDAO.class); dao.createTable(); return dao; }
创建一个数据源
/** * 创建一个新的、唯一的DataSource实例,类似xml中配置 * <bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"> * hsqldb 是一款纯Java编写的数据库 有兴趣的朋友可以一看源码 博客的结尾我会附加源码包 * @return */ public static DataSource createUniqueDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); int random = new Random(Integer.MAX_VALUE).nextInt(); dataSource.setUrl("jdbc:hsqldb:mem:" + System.currentTimeMillis() + "-" + random); dataSource.setDriverClassName("org.hsqldb.jdbc.JDBCDriver"); return dataSource; }
至此我们想要的UserDAO的实例就创建好了,jadeFactory对象的create方法
/** * * */ public <T> T create(Class<?> daoClass) { try { //支持DAO类的基础配置(数据源配置、SQL解析器配置、OR映射配置等等) DAOConfig config = new DAOConfig(dataAccessFactory, rowMapperFactory, interpreterFactory, cacheProvider, statementWrapperProvider); //封装缓存一个DAO接口类本身的一些信息,比如类对象、类常量等等 DAOMetaData daoMetaData = new DAOMetaData(daoClass, config); //DAO代理处理器(一个DAO类对应一个处理器实例) //JadeInvocationHandler 实现了 InvocationHandler,当我们调用UserDAO中的方法时程序会自动调用 //JadeInvocationHandler中的重写方法invoke(Object proxy, Method method, Object[] args) 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); } }
Proxy.newProxyInstance()方法说明
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
二、调用实例中的方法并执行sql
invoke方法
@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对象,并记录应使用哪种类型的执行器, // 将interface类型的UserDAO中执行方法的@SQL注解、@ReturnGeneratedKeys、方法参数 // 是否为批处理等 记录以待查询时使用 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(); //执行sql final Object result = statement.execute(parameters); long cost = System.currentTimeMillis() - begin; // logging if (sqlLogger.isInfoEnabled()) { sqlLogger.info(statemenetMetaData + "\tcost " + cost + "ms." ); } return result; }
statement的execute方法,判断是否为批处理,然后调用先前statement获得的执行器处理sql
public Object execute(Map<String, Object> parameters) { Object result; if (batchUpdate) { // Iterable<?> iterable = (Iterable<?>) parameters.get(":1"); Iterator<?> iterator = (Iterator<?>) iterable.iterator(); List<StatementRuntime> runtimes = new LinkedList<StatementRuntime>(); int index = 0; while (iterator.hasNext()) { Object arg = iterator.next(); HashMap<String, Object> clone = new HashMap<String, Object>(parameters); // 更新执行参数 clone.put(":1", arg); if (metaData.getSQLParamAt(0) != null) { clone.put(metaData.getSQLParamAt(0).value(), arg); } StatementRuntime runtime = new StatementRuntimeImpl(metaData, clone); for (Interpreter interpreter : interpreters) { interpreter.interpret(runtime); } if (index == 0) { log(parameters, runtime); } runtimes.add(runtime); index++; } result = querier.execute(sqlType, runtimes.toArray(new StatementRuntime[0])); result = afterInvocationCallback.execute(runtimes.get(0), result); } else { StatementRuntime runtime = new StatementRuntimeImpl(metaData, parameters); for (Interpreter interpreter : interpreters) { interpreter.interpret(runtime); } log(parameters, runtime); result = querier.execute(sqlType, runtime); result = afterInvocationCallback.execute(runtime, result); } return result; }
最终调用spring 的 jdbcTemplate执行sql并返回记录
@Override public <T> List<T> select(String sql, Object[] args, RowMapper<T> rowMapper) { PreparedStatementCreator csc = getPreparedStatementCreator(sql, args, false); return jdbcTemplate.query(csc, new RowMapperResultSetExtractor<T>(rowMapper)); }
getPreparedStatementCreator()方法的实现
private PreparedStatementCreator getPreparedStatementCreator(// final String sql, final Object[] args, final boolean returnKeys) { PreparedStatementCreator creator = new PreparedStatementCreator() { @Override public PreparedStatement createPreparedStatement(Connection con) throws SQLException { PreparedStatement ps = con.prepareStatement(sql); if (returnKeys) { ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); } else { ps = con.prepareStatement(sql); } if (args != null) { for (int i = 0; i < args.length; i++) { Object arg = args[i]; if (arg instanceof SqlParameterValue) { SqlParameterValue paramValue = (SqlParameterValue) arg; StatementCreatorUtils.setParameterValue(ps, i + 1, paramValue, paramValue.getValue()); } else { StatementCreatorUtils.setParameterValue(ps, i + 1, SqlTypeValue.TYPE_UNKNOWN, arg); } } } return ps; } }; return creator; }
hsldb 链接:http://pan.baidu.com/s/1i5Jyd0p 密码:l733
相关文章推荐
- [java][源码分析]paoding-rose-jade框架源码分析(2)
- [java][源码分析]paoding-rose-jade框架源码分析(1)
- 应用框架的设计与实现——.NET平台(7.事件通知服务.源码分析)
- [Abp 源码分析]二、模块系统
- MySQL源码分析(1):主要模块及数据流
- Asp.net web Api源码分析-HttpParameterBinding
- Asp.net地址转义(分析)加强版--Dottext的地址分析模块的不足之处及相应的解决方案
- [Asp.net 5] Caching-缓存架构与源码分析
- Nginx源码分析 - 实战篇 - 编写一个自定义的模块
- 跟我一起读postgresql源码(二)——Parser(查询分析模块)
- nginx源码分析—模块及其初始化
- asp.net mvc源码分析-路由篇 如何找到 IHttpHandler
- asp.net mvc源码分析-Controllerl篇 如何创建Controller实例
- 3(phonegap源码分析)模块定义与请求(define require)
- asp.net mvc源码分析-Action篇 Action的执行
- asp.net mvc源码分析-ActionResult篇 ViewResult
- U-BOOT介绍以及disk模块源码分析
- 深入学习Django源码基础11 - 简要分析Django中template模块1
- Android4.4设置源码分析(一):设置主界面与各模块之间的联系
- ASP.NET MVC源码分析系列