什么是nacos
英文全称dynamic naming and configuration service,na为naming/nameserver即注册中心,co为configuration即注册中心,service是指该注册/配置中心都是以服务为核心。服务在nacos是一等公民
没看源码之前,觉得很离谱,为啥只能限制数据库为mysql,按道理来说,nacos用了jdbctemplate,可以适配很多数据库才是
最近看了nacos的源码,发现其中有很多硬编码,才明白原因
nacos的数据源获取都是通过com.alibaba.nacos.config.server.service.datasource.dynamicdatasource来获取的
在获取数据源时,根据配置判断你到底是使用内置的本地数据库还是外部的数据库(mysql)
public synchronized datasourceservice getdatasource() {
try {
// embedded storage is used by default in stand-alone mode
// in cluster mode, external databases are used by default
// 根据system.getproperty("nacos.standalone")来判断你到底是不是standalone模式
// standalone模式,使用内置数据库
if (propertyutil.isembeddedstorage()) {
if (localdatasourceservice == null) {
localdatasourceservice = new localdatasourceserviceimpl();
localdatasourceservice.init();
}
return localdatasourceservice;
} else {
// 如果不是standalone,直接创建外部的数据源
if (basicdatasourceservice == null) {
basicdatasourceservice = new externaldatasourceserviceimpl();
basicdatasourceservice.init();
}
return basicdatasourceservice;
}
} catch (exception e) {
throw new runtimeexception(e);
}
}
外部数据源com.alibaba.nacos.config.server.service.datasource.externaldatasourceserviceimpl.init()
@override
public void init() {
querytimeout = convertutils.toint(system.getproperty("querytimeout"), 3);
jt = new jdbctemplate();
// set the maximum number of records to prevent memory expansion
jt.setmaxrows(50000);
jt.setquerytimeout(querytimeout);
testmasterjt = new jdbctemplate();
testmasterjt.setquerytimeout(querytimeout);
testmasterwritablejt = new jdbctemplate();
// prevent the login interface from being too long because the main library is not available
testmasterwritablejt.setquerytimeout(1);
// database health check
testjtlist = new arraylist<jdbctemplate>();
ishealthlist = new arraylist<boolean>();
tm = new datasourcetransactionmanager();
tjt = new transactiontemplate(tm);
// transaction timeout needs to be distinguished from ordinary operations.
tjt.settimeout(transaction_query_timeout);
// 判断到底是是不是用外部数据库
// 这个可以在com.alibaba.nacos.config.server.utils.propertyutil#loadsetting中看到
// setuseexternaldb("mysql".equalsignorecase(getstring("spring.datasource.platform", "")));
// 好家伙,直接判断配置的是不是mysql,是mysql那就是外部数据库,进行reload,不是,那就不管了
if (propertyutil.isuseexternaldb()) {
try {
reload();
} catch (ioexception e) {
e.printstacktrace();
throw new runtimeexception(db_load_error_msg);
}
if (this.datasourcelist.size() > db_master_select_threshold) {
configexecutor.scheduleconfigtask(new selectmastertask(), 10, 10, timeunit.seconds);
}
configexecutor.scheduleconfigtask(new checkdbhealthtask(), 10, 10, timeunit.seconds);
}
}
在com.alibaba.nacos.config.server.service.datasource.externaldatasourceserviceimpl#reload中,我们可以看到
@override
public synchronized void reload() throws ioexception {
try {
// 根据配置文件,构建数据源集合
datasourcelist = new externaldatasourceproperties()
.build(envutil.getenvironment(), (datasource) -> {
jdbctemplate jdbctemplate = new jdbctemplate();
jdbctemplate.setquerytimeout(querytimeout);
jdbctemplate.setdatasource(datasource);
testjtlist.add(jdbctemplate);
ishealthlist.add(boolean.true);
});
new selectmastertask().run();
new checkdbhealthtask().run();
} catch (runtimeexception e) {
fatal_log.error(db_load_error_msg, e);
throw new ioexception(e);
}
}
在com.alibaba.nacos.config.server.service.datasource.externaldatasourceproperties#build中
list<hikaridatasource> build(environment environment, callback<hikaridatasource> callback) {
list<hikaridatasource> datasources = new arraylist<>();
// 把胚子信息绑定到当前的externaldatasourceproperties对象,赋值操作
// 因为外面是直接new出来的,需要对属性根据文件进行赋值
binder.get(environment).bind("db", bindable.ofinstance(this));
preconditions.checkargument(objects.nonnull(num), "db.num is null");
preconditions.checkargument(collectionutils.isnotempty(user), "db.user or db.user.[index] is null");
preconditions.checkargument(collectionutils.isnotempty(password), "db.password or db.password.[index] is null");
// 可以配置多个数据库
for (int index = 0; index < num; index++) {
int currentsize = index + 1;
preconditions.checkargument(url.size() >= currentsize, "db.url.%s is null", index);
// 拿到spring.datasource.xxx一堆,这个针对所有的数据源都适用
datasourcepoolproperties poolproperties = datasourcepoolproperties.build(environment);
// 为每一个数据源进行单独的url,user,password进行替换
poolproperties.setdriverclassname(jdbc_driver_name);
poolproperties.setjdbcurl(url.get(index).trim());
poolproperties.setusername(getordefault(user, index, user.get(0)).trim());
poolproperties.setpassword(getordefault(password, index, password.get(0)).trim());
hikaridatasource ds = poolproperties.getdatasource();
ds.setconnectiontestquery(test_query);
datasources.add(ds);
callback.accept(ds);
}
preconditions.checkargument(collectionutils.isnotempty(datasources), "no datasource available");
return datasources;
}
这个整体还行,但是为啥jdbc_driver_name是硬编码呢,代码中清晰看到
private static final string jdbc_driver_name = "com.mysql.cj.jdbc.driver";
到这已经一目了然,代码中硬编码了mysql,driver也没法改,所以根本没法更换数据库驱动,有点骚,而且com.mysql.cj.jdbc.driver是mysql8的驱动,对mysql版本是有要求的
再看其他部分,也可以发现大量的硬编码,例如com.alibaba.nacos.config.server.auth.externaluserpersistserviceimpl
public class externaluserpersistserviceimpl implements userpersistservice {
@autowired
private externalstoragepersistserviceimpl persistservice;
private jdbctemplate jt;
@postconstruct
protected void init() {
jt = persistservice.getjdbctemplate();
}
/**
* execute create user operation.
*
* @param username username string value.
* @param password password string value.
*/
public void createuser(string username, string password) {
string sql = "insert into users (username, password, enabled) values (?, ?, ?)";
try {
jt.update(sql, username, password, true);
} catch (cannotgetjdbcconnectionexception e) {
logutil.fatal_log.error("[db-error] " + e.tostring(), e);
throw e;
}
}
/**
* execute delete user operation.
*
* @param username username string value.
*/
public void deleteuser(string username) {
string sql = "delete from users where username=?";
try {
jt.update(sql, username);
} catch (cannotgetjdbcconnectionexception e) {
logutil.fatal_log.error("[db-error] " + e.tostring(), e);
throw e;
}
}
/**
* execute update user password operation.
*
* @param username username string value.
* @param password password string value.
*/
public void updateuserpassword(string username, string password) {
try {
jt.update("update users set password = ? where username=?", password, username);
} catch (cannotgetjdbcconnectionexception e) {
logutil.fatal_log.error("[db-error] " + e.tostring(), e);
throw e;
}
}
/**
* execute find user by username operation.
*
* @param username username string value.
* @return user model.
*/
public user finduserbyusername(string username) {
string sql = "select username,password from users where username=? ";
try {
return this.jt.queryforobject(sql, new object[] {username}, user_row_mapper);
} catch (cannotgetjdbcconnectionexception e) {
logutil.fatal_log.error("[db-error] " + e.tostring(), e);
throw e;
} catch (emptyresultdataaccessexception e) {
return null;
} catch (exception e) {
logutil.fatal_log.error("[db-other-error]" + e.getmessage(), e);
throw new runtimeexception(e);
}
}
public page<user> getusers(int pageno, int pagesize) {
paginationhelper<user> helper = persistservice.createpaginationhelper();
string sqlcountrows = "select count(*) from users where ";
string sqlfetchrows = "select username,password from users where ";
string where = " 1=1 ";
try {
page<user> pageinfo = helper
.fetchpage(sqlcountrows + where, sqlfetchrows + where, new arraylist<string>().toarray(), pageno,
pagesize, user_row_mapper);
if (pageinfo == null) {
pageinfo = new page<>();
pageinfo.settotalcount(0);
pageinfo.setpageitems(new arraylist<>());
}
return pageinfo;
} catch (cannotgetjdbcconnectionexception e) {
logutil.fatal_log.error("[db-error] " + e.tostring(), e);
throw e;
}
}
@override
public list<string> finduserlikeusername(string username) {
string sql = "select username from users where username like '%' ? '%'";
list<string> users = this.jt.queryforlist(sql, new string[]{username}, string.class);
return users;
}
}
几乎所有的sql都是硬编码….所以要改造成其他数据库工作量还是非常大的
到此这篇关于为什么nacos只支持mysql的文章就介绍到这了,更多相关nacos只支持mysql内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!