文档章节

JFinal源码解析系列之三

yiguangtia
 yiguangtia
发布于 2015/07/17 10:49
字数 1057
阅读 31
收藏 0

1 数据库插件配置

public void configPlugin(Plugins me) {
C3p0Plugin cp = new C3p0Plugin("jdbc:mysql://localhost/db_name",
"userName", "password");//1.1 配置c3p0插件
me.add(cp);//1.2添加c3p0到plugins中
ActiveRecordPlugin arp = new ActiveRecordPlugin(cp);//1.3 创建ActiveRecordPlugin
me.add(arp);
arp.addMapping("user", User.class);//添加tablesName 到Model的映射
arp.addMapping("article", "article_id", Article.class);
}
}

1.1 c3p0类

public class C3p0Plugin implements IPlugin, IDataSourceProvider {
	
	private String jdbcUrl;
	private String user;
	private String password;
	private String driverClass = "com.mysql.jdbc.Driver";
	private int maxPoolSize = 100;
	private int minPoolSize = 10;
	private int initialPoolSize = 10;
	private int maxIdleTime = 20;
	private int acquireIncrement = 2;
	
	private ComboPooledDataSource dataSource;
	
	public C3p0Plugin setDriverClass(String driverClass) {
		if (StrKit.isBlank(driverClass))
			throw new IllegalArgumentException("driverClass can not be blank.");
		this.driverClass = driverClass;
		return this;
	}
	
	public C3p0Plugin setMaxPoolSize(int maxPoolSize) {
		if (maxPoolSize < 1)
			throw new IllegalArgumentException("maxPoolSize must more than 0.");
		this.maxPoolSize = maxPoolSize;
		return this;
	}
	
	public C3p0Plugin setMinPoolSize(int minPoolSize) {
		if (minPoolSize < 1)
			throw new IllegalArgumentException("minPoolSize must more than 0.");
		this.minPoolSize = minPoolSize;
		return this;
	}
	
	public C3p0Plugin setInitialPoolSize(int initialPoolSize) {
		if (initialPoolSize < 1)
			throw new IllegalArgumentException("initialPoolSize must more than 0.");
		this.initialPoolSize = initialPoolSize;
		return this;
	}
	
	public C3p0Plugin setMaxIdleTime(int maxIdleTime) {
		if (maxIdleTime < 1)
			throw new IllegalArgumentException("maxIdleTime must more than 0.");
		this.maxIdleTime = maxIdleTime;
		return this;
	}
	
	public C3p0Plugin setAcquireIncrement(int acquireIncrement) {
		if (acquireIncrement < 1)
			throw new IllegalArgumentException("acquireIncrement must more than 0.");
		this.acquireIncrement = acquireIncrement;
		return this;
	}
	
	public C3p0Plugin(String jdbcUrl, String user, String password) {//1.1 调用的构造函数
		this.jdbcUrl = jdbcUrl;
		this.user = user;
		this.password = password;
	}
	
	public C3p0Plugin(String jdbcUrl, String user, String password, String driverClass) {
		this.jdbcUrl = jdbcUrl;
		this.user = user;
		this.password = password;
		this.driverClass = driverClass != null ? driverClass : this.driverClass;
	}
	
	public C3p0Plugin(String jdbcUrl, String user, String password, String driverClass, Integer maxPoolSize, Integer minPoolSize, Integer initialPoolSize, Integer maxIdleTime, Integer acquireIncrement) {
		initC3p0Properties(jdbcUrl, user, password, driverClass, maxPoolSize, minPoolSize, initialPoolSize, maxIdleTime, acquireIncrement);
	}
	
	private void initC3p0Properties(String jdbcUrl, String user, String password, String driverClass, Integer maxPoolSize, Integer minPoolSize, Integer initialPoolSize, Integer maxIdleTime, Integer acquireIncrement) {
		this.jdbcUrl = jdbcUrl;
		this.user = user;
		this.password = password;
		this.driverClass = driverClass != null ? driverClass : this.driverClass;
		this.maxPoolSize = maxPoolSize != null ? maxPoolSize : this.maxPoolSize;
		this.minPoolSize = minPoolSize != null ? minPoolSize : this.minPoolSize;
		this.initialPoolSize = initialPoolSize != null ? initialPoolSize : this.initialPoolSize;
		this.maxIdleTime = maxIdleTime != null ? maxIdleTime : this.maxIdleTime;
		this.acquireIncrement = acquireIncrement != null ? acquireIncrement : this.acquireIncrement;
	}
	
	public C3p0Plugin(File propertyfile) {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(propertyfile);
			Properties ps = new Properties();
			ps.load(fis);
			
			initC3p0Properties(ps.getProperty("jdbcUrl"), ps.getProperty("user"), ps.getProperty("password"), ps.getProperty("driverClass"),
					toInt(ps.getProperty("maxPoolSize")), toInt(ps.getProperty("minPoolSize")), toInt(ps.getProperty("initialPoolSize")),
					toInt(ps.getProperty("maxIdleTime")),toInt(ps.getProperty("acquireIncrement")));
		} catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			if (fis != null)
				try {fis.close();} catch (IOException e) {e.printStackTrace();}
		}
	}
	
	public C3p0Plugin(Properties properties) {
		Properties ps = properties;
		initC3p0Properties(ps.getProperty("jdbcUrl"), ps.getProperty("user"), ps.getProperty("password"), ps.getProperty("driverClass"),
				toInt(ps.getProperty("maxPoolSize")), toInt(ps.getProperty("minPoolSize")), toInt(ps.getProperty("initialPoolSize")),
				toInt(ps.getProperty("maxIdleTime")),toInt(ps.getProperty("acquireIncrement")));
	}
	//c3p0初始化,初始化datasource
	public boolean start() {
		dataSource = new ComboPooledDataSource();
		dataSource.setJdbcUrl(jdbcUrl);
		dataSource.setUser(user);
		dataSource.setPassword(password);
		try {dataSource.setDriverClass(driverClass);}
		catch (PropertyVetoException e) {dataSource = null; System.err.println("C3p0Plugin start error"); throw new RuntimeException(e);} 
		dataSource.setMaxPoolSize(maxPoolSize);
		dataSource.setMinPoolSize(minPoolSize);
		dataSource.setInitialPoolSize(initialPoolSize);
		dataSource.setMaxIdleTime(maxIdleTime);
		dataSource.setAcquireIncrement(acquireIncrement);
		
		return true;
	}
	
	private Integer toInt(String str) {
		return Integer.parseInt(str);
	}
	
	public DataSource getDataSource() {
		return dataSource;
	}
	
	public boolean stop() {
		if (dataSource != null)
			dataSource.close();
		return true;
	}
}

可以看到c3p0实现了Iplugin 和IDatasoureProvider。

1.3 AtiveRecordPlugin 类中构造方法的具体实现

//其中c3p0为IDataSourceProvider的子类
public ActiveRecordPlugin(IDataSourceProvider dataSourceProvider) {
		this(DbKit.MAIN_CONFIG_NAME, dataSourceProvider);
	}

1.4 arp.addMapping()的具体实现

public ActiveRecordPlugin addMapping(String tableName, Class<? extends Model<?>> modelClass) {
		tableList.add(new Table(tableName, modelClass));// 添加class类与name的映射
		return this;
	}

其中table 类保存了元数据包含列名和类型。

JFinal初始化时调用了plugins.start();

其中ActiveRecordPlugin的start方法实现如下:

public boolean start() {
		if (isStarted)//isStarted是启动标识防止重复启动
			return true;
		
		if (dataSourceProvider != null)
			dataSource = dataSourceProvider.getDataSource();//获取dataSource
		if (dataSource == null)
			throw new RuntimeException("ActiveRecord start error: ActiveRecordPlugin need DataSource or DataSourceProvider");
		//生成Config设置或者使用已有的设置
		if (config == null)
			config = new Config(configName, dataSource, dialect, showSql, devMode, transactionLevel, containerFactory, cache);
		DbKit.addConfig(config);
		//建立config与数据库的关联 核心与关键
		TableBuilder.build(tableList, config);
		Db.init();
		isStarted = true;
		return true;
	}

build方法实现如下:

static void build(List<Table> tableList, Config config) {
		Table temp = null;
		Connection conn = null;
		try {
			conn = config.dataSource.getConnection();//获取数据库连接
			TableMapping tableMapping = TableMapping.me();//获取TableMapping 单例
			//tableList中的数据为arp.add("User",User.class);
			for (Table table : tableList) {
				temp = table;
				doBuild(table, conn, config);//建立每一个表与Model的对应关系
				tableMapping.putTable(table);//将构建成功的每一个table添加到TableMapping中
				DbKit.addModelToConfigMapping(table.getModelClass(), config);
			}
		} catch (Exception e) {
			if (temp != null)
				System.err.println("Can not create Table object, maybe the table " + temp.getName() + " is not exists.");
			throw new ActiveRecordException(e);
		}
		finally {
			config.close(conn);
		}
	}

doBuild()的实现方法如下:

private static void doBuild(Table table, Connection conn, Config config) throws SQLException {
		table.setColumnTypeMap(config.containerFactory.getAttrsMap());
		if (table.getPrimaryKey() == null)//table的主键是否为空
			table.setPrimaryKey(config.dialect.getDefaultPrimaryKey());//将id设置为table的主键
		
		String sql = config.dialect.forTableBuilderDoBuild(table.getName());//"select * from "+tablename+" where 1=2"
		Statement stm = conn.createStatement();
		ResultSet rs = stm.executeQuery(sql);
		ResultSetMetaData rsmd = rs.getMetaData();//获取metadata
		
		for (int i=1; i<=rsmd.getColumnCount(); i++) {
			String colName = rsmd.getColumnName(i);//获取列名
			String colClassName = rsmd.getColumnClassName(i);//获取the fully-qualified name 
			
			Class<?> clazz = strToType.get(colClassName);
			if (clazz != null) {//判断是否为class类
				table.setColumnType(colName, clazz);
			}
			else {
				int type = rsmd.getColumnType(i);//获取字段类型
				if (type == Types.BLOB) {//blob
					table.setColumnType(colName, byte[].class);
				}
				else if (type == Types.CLOB || type == Types.NCLOB) {//Clob||NCLOB类型
					table.setColumnType(colName, String.class);
				}
				else {
					table.setColumnType(colName, String.class);
				}
				// core.TypeConverter
				// throw new RuntimeException("You've got new type to mapping. Please add code in " + TableBuilder.class.getName() + ". The ColumnClassName can't be mapped: " + colClassName);
			}
		}
		
		rs.close();
		stm.close();
	}

巧妙地利用“select * from tablename where 1=2"的语句获取table的相关信息,实现数据库到model的精巧映射。

© 著作权归作者所有

yiguangtia
粉丝 5
博文 39
码字总数 29778
作品 0
深圳
私信 提问
建议以依赖的方式,而非copy的方式使用jfinal代码

Springblade 的技术组合是 spring+springmvc+beetl+beetlsql+shiro,刚看了一下源码,其中大量直接 copy 的 jfinal 源码,例如 render 模块、json 模块相当于整模块原封不动地 copy 使用。项...

JFinal
2016/09/05
1K
15
JFinal Weixin 1.9 发布,微信极速 SDK

JFinal Weixin 1.9 正式发布!离上一次 JFinal weixin 1.8 发布,已经过去 10 个月。在过去的 10 个月时间里 JFinal Weixin 紧随微信公众平台的演化,不断增加了新的 API,同时也在不断完善原...

JFinal
2017/05/22
10.4K
54
JFinal 1.5 发布,JAVA极速WEB+ORM框架

JFinal 爱好者一直都在问 JFinal 何时再次升级?JFinal 1.5 何时发布?以往升级都保持在每月近两次的频率,为何本次五个月过去了新版本还不出?由于作者暂时阔别码坛已有半年时间,一直无暇顾...

JFinal
2013/10/08
7.3K
101
微信公众号极速 SDK - JFinal Weixin

JFinal Weixin 是基于 JFinal 的微信公众号极速 SDK,只需参考 Demo 代码即可进行极速开发。自 JFinal Weixin 1.2 版本开始已添加对多公众号支持 0、Maven 坐标 1、WeixinConfig public cla...

JFinal
2014/10/21
81.7K
54
JFinal Extensions 1.2 发布,JFinal 扩展

Jfinal-ext是对java极速web框架 jfinal 的一个扩充,主要利用jfinal的plugin机制集成各种第三方框架,像spring一样,简化开发者的学习应用成本,使用时请将jfinal.jar先引入工程。 new feat...

绝望的八皮
2012/12/17
1K
24

没有更多内容

加载失败,请刷新页面

加载更多

Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
5
0
CSS盒子模型

CSS盒子模型 组成: content --> padding --> border --> margin 像现实生活中的快递: 物品 --> 填充物 --> 包装盒 --> 盒子与盒子之间的间距 content :width、height组成的 内容区域 padd......

studywin
今天
7
0
修复Win10下开始菜单、设置等系统软件无法打开的问题

因为各种各样的原因导致系统文件丢失、损坏、被修改,而造成win10的开始菜单、设置等系统软件无法打开的情况,可以尝试如下方法解决 此方法只在部分情况下有效,但值得一试 用Windows键+R打开...

locbytes
昨天
8
0
jquery 添加和删除节点

本文转载于:专业的前端网站➺jquery 添加和删除节点 // 增加一个三和一节点function addPanel() { // var newPanel = $('.my-panel').clone(true) var newPanel = $(".triple-panel-con......

前端老手
昨天
8
0
一、Django基础

一、web框架分类和wsgiref模块使用介绍 web框架的本质 socket服务端 与 浏览器的通信 socket服务端功能划分: 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 根据用户访问...

ZeroBit
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部