update: fescar的DataSource拦截改成Ioc事件监听器来做, 实现对任意数据源的全局事务支持,不仅限于NutDao

需要配合最新的nutz版本,否则DataSource替换会失败

不良后果: 由于DataSourceProxy并没有继承DruidDataSource,所以depose event对应的close方法不存在
但nutzboot服务器一般不存在关闭流程,所以这个影响应该是可以接受的
This commit is contained in:
Wendal Chen 2019-03-28 20:27:28 +08:00
parent 343d164aad
commit 65f26c4b45
2 changed files with 94 additions and 68 deletions

View File

@ -1,26 +1,16 @@
package org.nutz.boot.starter.fescar;
import java.sql.Connection;
import java.sql.Statement;
import javax.sql.DataSource;
import org.nutz.boot.AppContext;
import org.nutz.boot.annotation.PropDoc;
import org.nutz.boot.starter.ServerFace;
import org.nutz.dao.impl.NutDao;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fescar.common.util.StringUtils;
import com.alibaba.fescar.config.ConfigurationFactory;
import com.alibaba.fescar.rm.RMClient;
import com.alibaba.fescar.rm.datasource.DataSourceManager;
import com.alibaba.fescar.rm.datasource.DataSourceProxy;
import com.alibaba.fescar.tm.TMClient;
@IocBean
@ -30,13 +20,13 @@ public class FescarStarter implements ServerFace {
protected static final String PRE = "fescar.";
@PropDoc(value="fescar应用id", need=true)
@PropDoc(value = "fescar应用id", need = true)
public static String PROP_APPID = PRE + "applicationId";
@PropDoc(value="fescar事务组", need=true)
@PropDoc(value = "fescar事务组", need = true)
public static String PROP_TXGROUP = PRE + "txServiceGroup";
@PropDoc(value="自动创建undo表", defaultValue="true")
@PropDoc(value = "自动创建undo表", defaultValue = "true")
public static String PROP_CREATE_UNDO = PRE + "create_undo_table";
@Inject
@ -45,14 +35,12 @@ public class FescarStarter implements ServerFace {
@Inject
protected AppContext appContext;
private final boolean disableGlobalTransaction = ConfigurationFactory.getInstance().getBoolean("service.disableGlobalTransaction", false);
private String applicationId;
private String txServiceGroup;
@Override
public void start() throws Exception {
if (disableGlobalTransaction) {
if (FescarHelper.disableGlobalTransaction) {
if (log.isInfoEnabled()) {
log.info("Global transaction is disabled.");
}
@ -67,40 +55,6 @@ public class FescarStarter implements ServerFace {
log.infof("fescar applicationId=%s txServiceGroup=%s", applicationId, txServiceGroup);
initClient();
DataSource ds = appContext.getIoc().get(DataSource.class);
if (!(ds instanceof DruidDataSource)) {
log.error("only DruidDataSource is support by fescar!!!");
throw new RuntimeException("only DruidDataSource is support by fescar!!!");
}
if (conf.getBoolean(PROP_CREATE_UNDO, true)) {
try (Connection conn = ds.getConnection()) {
Statement st = conn.createStatement();
st.execute("CREATE TABLE IF NOT EXISTS " + "`undo_log` (\r\n" +
" `id` bigint(20) NOT NULL AUTO_INCREMENT,\r\n" +
" `branch_id` bigint(20) NOT NULL,\r\n" +
" `xid` varchar(100) NOT NULL,\r\n" +
" `rollback_info` longblob NOT NULL,\r\n" +
" `log_status` int(11) NOT NULL,\r\n" +
" `log_created` datetime NOT NULL,\r\n" +
" `log_modified` datetime NOT NULL,\r\n" +
" `ext` varchar(100) DEFAULT NULL,\r\n" +
" PRIMARY KEY (`id`),\r\n" +
" UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)\r\n" +
") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8");
st.close();
}
}
DataSourceProxy proxy = new DataSourceProxy((DruidDataSource) ds, "DEFAULT");
DataSourceManager.get().registerResource(proxy);
if (appContext.getIoc().has("dao")) {
log.info("looking for NutDao instance and replace DataSource");
NutDao dao = appContext.getIoc().get(NutDao.class, "dao");
dao.setDataSource(proxy);
}
else {
log.info("NutDao instance not found, skip it");
}
}
protected void initClient() {
@ -108,17 +62,14 @@ public class FescarStarter implements ServerFace {
log.info("Initializing Global Transaction Clients ... ");
}
if (StringUtils.isNullOrEmpty(applicationId) || StringUtils.isNullOrEmpty(txServiceGroup)) {
throw new IllegalArgumentException(
"applicationId: " + applicationId + ", txServiceGroup: " + txServiceGroup);
throw new IllegalArgumentException("applicationId: " + applicationId + ", txServiceGroup: " + txServiceGroup);
}
//init TM
// init TM
TMClient.init(applicationId, txServiceGroup);
if (log.isInfoEnabled()) {
log.info(
"Transaction Manager Client is initialized. applicationId[" + applicationId + "] txServiceGroup["
+ txServiceGroup + "]");
log.info("Transaction Manager Client is initialized. applicationId[" + applicationId + "] txServiceGroup[" + txServiceGroup + "]");
}
//init RM
// init RM
RMClient.init(applicationId, txServiceGroup);
if (log.isInfoEnabled()) {
log.info("Resource Manager is initialized. applicationId[" + applicationId + "] txServiceGroup[" + txServiceGroup + "]");

View File

@ -0,0 +1,75 @@
package org.nutz.boot.starter.fescar.datasource;
import java.sql.Connection;
import java.sql.Statement;
import org.nutz.boot.starter.fescar.FescarHelper;
import org.nutz.boot.starter.fescar.FescarStarter;
import org.nutz.ioc.IocEventListener;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fescar.rm.datasource.DataSourceManager;
import com.alibaba.fescar.rm.datasource.DataSourceProxy;
@IocBean
public class FescarDataSourceHandler implements IocEventListener {
private static final Log log = Logs.get();
@Inject
protected PropertiesProxy conf;
public Object afterBorn(Object obj, String beanName) {
return obj;
}
public Object afterCreate(Object obj, String beanName) {
if (obj == null)
return null;
if (obj instanceof DruidDataSource) {
if (FescarHelper.disableGlobalTransaction) {
if (log.isInfoEnabled()) {
log.info("Global transaction is disabled.");
}
return obj;
}
log.info("proxy DruidDataSource : " + obj.hashCode());
DruidDataSource ds = (DruidDataSource)obj;
DataSourceProxy proxy = new DataSourceProxy(ds, "DEFAULT");
DataSourceManager.get().registerResource(proxy);
if (conf.getBoolean(FescarStarter.PROP_CREATE_UNDO, true)) {
try (Connection conn = ds.getConnection()) {
Statement st = conn.createStatement();
st.execute("CREATE TABLE IF NOT EXISTS " + "`undo_log` (\r\n" +
" `id` bigint(20) NOT NULL AUTO_INCREMENT,\r\n" +
" `branch_id` bigint(20) NOT NULL,\r\n" +
" `xid` varchar(100) NOT NULL,\r\n" +
" `rollback_info` longblob NOT NULL,\r\n" +
" `log_status` int(11) NOT NULL,\r\n" +
" `log_created` datetime NOT NULL,\r\n" +
" `log_modified` datetime NOT NULL,\r\n" +
" `ext` varchar(100) DEFAULT NULL,\r\n" +
" PRIMARY KEY (`id`),\r\n" +
" UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)\r\n" +
") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8");
st.close();
}
catch (Throwable e) {
log.warn("fail to create fescar's undo_log table", e);
}
}
return proxy;
}
return obj;
}
public int getOrder() {
return 0;
}
}