Commit bac5a040 by 李秋伟

Merge branch 'feature_datasouce' into 'master'

Feature datasouce

See merge request mall/arch/matrix!29
parents 9f276ac4 45118628
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
package com.secoo.mall.common.core.classloader;
import com.secoo.mall.common.core.exception.SystemInternalException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class MatrixUrlClassLoader extends URLClassLoader {
private volatile static MatrixUrlClassLoader instance;
private static ClassLoader classLoader = MatrixUrlClassLoader.class.getClassLoader();
private static final Method ADD_URL;
//并行加载classLoader
static {
ClassLoader.registerAsParallelCapable();
}
//初始化添加资源
static {
try {
ADD_URL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
ADD_URL.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
throw new SystemInternalException();
}
}
public MatrixUrlClassLoader(URL[] urls) {
super(urls);
}
public static MatrixUrlClassLoader getInstance() {
if (instance == null) {
synchronized (MatrixUrlClassLoader.class) {
if (instance == null)
instance = new MatrixUrlClassLoader(new URL[]{});
}
}
return instance;
}
public void loadByUrl(String urlStr) {
try {
URL url = new URL(urlStr);
ADD_URL.invoke(classLoader, url);
} catch (Exception e) {
e.printStackTrace();
throw new SystemInternalException();
}
}
public <T> T loadClassByFullName(String fullClassName, Class<T> clazz) {
return loadClassByFullName(fullClassName, clazz, null, null);
}
public <T> T loadClassByFullName(String fullClassName, Class<T> clazz, Class[] args, Object[] params) {
try {
Class<?> tClass = classLoader.loadClass(fullClassName);
Class<? extends T> factClass = tClass.asSubclass(clazz); //生成实际类
//有参构造函数调用
if (args != null && args.length > 0) {
Constructor<? extends T> constructor = factClass.getDeclaredConstructor(args);
return constructor.newInstance(params);
}
//默认构造函数调用
return factClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new SystemInternalException();
}
}
}
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
package com.secoo.mall.common.util.net;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class IpUtil {
private static String[] headers = new String[]{"Cdn-Src-Ip", "X-Real-IP", "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
private static String localIP = "127.0.0.1";
/**
* 获取请求客户端IP地址,支持代理服务器
*
* @param request {@link HttpServletRequest} 对象
* @return IP地址
*/
public static String getRemoteAddr(HttpServletRequest request) {
// 1、获取客户端IP地址,支持代理服务器
String remoteAddr = null;
for (String header : headers) {
remoteAddr = request.getHeader(header);
if (StringUtils.hasText(remoteAddr) && !remoteAddr.equals("unknown")) {
break;
}
}
// 2、没有取得特定标记的值
if (!StringUtils.hasText(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
}
// 3、判断是否localhost访问
if (remoteAddr.equals("localhost")) {
remoteAddr = localIP;
}
return remoteAddr;
}
/**
* 获得请求的客户端信息【ip,port,name】
*
* @param request {@link HttpServletRequest} 对象
* @return 客户端信息[ip, port, name]
*/
public static String[] getRemoteInfo(HttpServletRequest request) {
if (request == null) {
return new String[]{"", "", ""};
}
return new String[]{getRemoteAddr(request), request.getRemotePort() + "", request.getRemoteHost()};
}
public static String getHostIp() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
}
return "127.0.0.1";
}
public static String getHostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
}
return "未知";
}
}
package com.secoo.mall.common.util.sys;
import com.secoo.mall.common.constant.CommonConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.SystemUtils;
@Slf4j
public class SystemUtil extends SystemUtils {
/**
* -Dapp.id=demo
*/
private static final String APP_ID_KEY = "app.id";
/**
* -Denv=pro
*/
private static final String ENV_KEY = "env";
/**
* 系统唯一标识
*/
public static final String APP_ID = getSystemProperty(APP_ID_KEY,"");
/**
* 环境变量
*/
public static final String ENV = getSystemProperty(ENV_KEY,"pro");
private static String getSystemProperty(final String property,String defaultValue) {
try {
return System.getProperty(property,defaultValue);
} catch (final SecurityException e) {
log.error("Caught a SecurityException reading the system property '" + property
+ "'; the SystemUtils property value will default to null.", e);
return null;
}
}
}
package com.secoo.mall.common.util.web; package com.secoo.mall.common.util.web;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
...@@ -12,8 +11,6 @@ import javax.servlet.http.HttpSession; ...@@ -12,8 +11,6 @@ import javax.servlet.http.HttpSession;
public class WebUtil extends WebUtils { public class WebUtil extends WebUtils {
private static String sessionUser = "sessionUser"; private static String sessionUser = "sessionUser";
private static String[] headers = new String[]{"Cdn-Src-Ip", "X-Real-IP", "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
private static String localIP = "127.0.0.1";
public static String getParameter(String name) { public static String getParameter(String name) {
return getRequest().getParameter(name); return getRequest().getParameter(name);
...@@ -57,46 +54,5 @@ public class WebUtil extends WebUtils { ...@@ -57,46 +54,5 @@ public class WebUtil extends WebUtils {
} }
/**
* 获取请求客户端IP地址,支持代理服务器
*
* @param request {@link HttpServletRequest} 对象
* @return IP地址
*/
public static String getRemoteAddr(HttpServletRequest request) {
// 1、获取客户端IP地址,支持代理服务器
String remoteAddr = null;
for (String header : headers) {
remoteAddr = request.getHeader(header);
if (StringUtils.hasText(remoteAddr) && !remoteAddr.equals("unknown")) {
break;
}
}
// 2、没有取得特定标记的值
if (!StringUtils.hasText(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
}
// 3、判断是否localhost访问
if (remoteAddr.equals("localhost")) {
remoteAddr = localIP;
}
return remoteAddr;
}
/**
* 获得请求的客户端信息【ip,port,name】
*
* @param request {@link HttpServletRequest} 对象
* @return 客户端信息[ip, port, name]
*/
public static String[] getRemoteInfo(HttpServletRequest request) {
if (request == null) {
return new String[]{"", "", ""};
}
return new String[]{getRemoteAddr(request), request.getRemotePort() + "", request.getRemoteHost()};
}
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>matrix-datasource</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.1.9.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>matrix-datasource-core</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>app-security-algo</artifactId>
</dependency>
<!--所依赖的数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.secoo.mall.datasource.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 选择使用的数据源
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SelectDataSource {
String value();
}
package com.secoo.mall.datasource.aop;
import com.secoo.mall.datasource.annotation.SelectDataSource;
import com.secoo.mall.datasource.holder.DataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Order(Byte.MIN_VALUE)
@Component
public class DataSourceAop {
@Pointcut("@annotation(com.secoo.mall.datasource.annotation.SelectDataSource) || @within(com.secoo.mall.datasource.annotation.SelectDataSource)")
public void dataSoucePointcut() {
}
@Around("com.secoo.mall.datasource.aop.DataSourceAop.dataSoucePointcut()")
public Object lookupKeyAround(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
SelectDataSource dsName = AnnotationUtils.getAnnotation(method, SelectDataSource.class);
if (dsName == null) {
Class clazz = signature.getDeclaringType();
dsName = AnnotationUtils.findAnnotation(clazz, SelectDataSource.class);
}
try {
DataSourceContextHolder.setDs(dsName.value());
return pjp.proceed();
} finally {
DataSourceContextHolder.clear();
}
}
}
package com.secoo.mall.datasource.bean;
import org.springframework.jdbc.datasource.AbstractDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public abstract class AbsDynamicDataSource extends AbstractDataSource {
private String dsName;
public AbsDynamicDataSource(String dsName) {
this.dsName = dsName;
}
public String getDsName() {
return dsName;
}
@Override
public Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return getDataSource().getConnection(username, password);
}
protected abstract DataSource getDataSource();
}
package com.secoo.mall.datasource.bean;
import com.secoo.mall.datasource.config.MatrixDataSourceConfig;
import com.secoo.mall.datasource.constant.DataSourceTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.MethodUtils;
import javax.sql.DataSource;
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
@Slf4j
public class MatrixDataSource implements DataSource, Closeable {
private DataSource dataSource;
public MatrixDataSource() {
}
public MatrixDataSource(DataSourceTypeEnum dataSourceTypeEnum, MatrixDataSourceConfig config) {
dataSource = dataSourceTypeEnum.getDataSourceFactory().createDataSouce(config);
}
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return dataSource.getConnection(username, password);
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return dataSource.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return dataSource.isWrapperFor(iface);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return dataSource.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
dataSource.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
dataSource.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
return dataSource.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return dataSource.getParentLogger();
}
@Override
public void close() throws IOException {
try {
MethodUtils.invokeExactMethod(dataSource, "close");
} catch (Exception e) {
log.error("datasource close error ", e);
}
}
}
package com.secoo.mall.datasource.bean;
import com.secoo.mall.common.core.exception.BusinessException;
import com.secoo.mall.common.util.string.StringUtil;
import com.secoo.mall.datasource.errorcode.DataSourceError;
import com.secoo.mall.datasource.holder.DataSourceContextHolder;
import com.secoo.mall.datasource.provider.DataSourceProvider;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j
@Data
public class MatrixDynamicDataSource extends AbsDynamicDataSource implements InitializingBean, DisposableBean {
private Map<String, DataSource> dataSourceMap = new HashMap<>();
private static Lock lock = new ReentrantLock();
@Resource
private DataSourceProvider provider;
public MatrixDynamicDataSource(String dsName) {
super(dsName);
}
@Override
/**
* 获取数据源有两种途径:
* 1.由构造参数直接指定
* 2.使用了selectDataSource注解
*/
protected DataSource getDataSource() {
String dsName = StringUtil.isEmpty(getDsName()) ? DataSourceContextHolder.getDs() : getDsName();
if (log.isDebugEnabled()) {
log.debug("cur ds is {}", dsName);
}
return getTargetDataSource(dsName);
}
/**
* 获取目的数据原
*
* @param dsName
* @return
*/
private DataSource getTargetDataSource(String dsName) {
//如果数据源名字为空默认取一个,此种情况可以允许不使用@SelectDataSource指定数据源
if (dataSourceMap.containsKey(dsName)) {
return dataSourceMap.get(dsName);
}
throw new BusinessException(DataSourceError.DATA_SOURCE_NOT_EXIST, dsName);
}
/**
* bean销毁
*
* @throws Exception
*/
@Override
public void destroy() throws Exception {
log.info("datasource start closing ....");
for (Map.Entry<String, DataSource> item : dataSourceMap.entrySet()) {
DataSource dataSource = item.getValue();
Class<? extends DataSource> clazz = dataSource.getClass();
try {
Method closeMethod = clazz.getDeclaredMethod("close");
closeMethod.invoke(dataSource);
} catch (NoSuchMethodException e) {
log.warn("datasource close the datasource named [{}] failed,", item.getKey());
}
}
log.info("datasource all closed success");
}
/**
* 数据加载
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
Map<String, DataSource> dataSourceMap = this.provider.loadDataSources();
for (Map.Entry<String, DataSource> dataSourceEntry : dataSourceMap.entrySet()) {
addDataSource(dataSourceEntry.getKey(), dataSourceEntry.getValue());
}
}
public void addDataSource(String dsName, DataSource dataSource) {
lock.lock();
log.info("load dataSources lock {}", dsName);
if (!dataSourceMap.containsKey(dsName)) {
dataSourceMap.put(dsName, dataSource);
}
log.info("load dataSources unlock {}", dsName);
lock.unlock();
}
/**
* todo:动态更新数据源
*
* @param dsName
*/
public void removeDataSource(String dsName) {
lock.lock();
log.info("remove dataSources lock {}", dsName);
if (dataSourceMap.containsKey(dsName)) {
dataSourceMap.remove(dsName);
}
log.info("remove dataSources unlock {}", dsName);
lock.unlock();
}
}
package com.secoo.mall.datasource.config;
import java.util.concurrent.TimeUnit;
public interface DataSourceConfig {
String POOL_NAME_PRIFIX = "matrix-dataSource-";
int DEFAULT_MIN_IDLE = 5;
int DEFAULT_POOL_SIZE = 50;
long CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(30L);
long VALIDATION_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
long IDLE_TIMEOUT = TimeUnit.MINUTES.toMillis(10L);
long MAX_LIFETIME = TimeUnit.MINUTES.toMillis(30L);
/**
* Get the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @return the connection timeout in milliseconds
*/
long getConnectionTimeout();
/**
* Set the maximum number of milliseconds that a client will wait for a connection from the pool. If this
* time is exceeded without a connection becoming available, a SQLException will be thrown from
* {@link javax.sql.DataSource#getConnection()}.
*
* @param connectionTimeoutMs the connection timeout in milliseconds
*/
void setConnectionTimeout(long connectionTimeoutMs);
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @return the idle timeout in milliseconds
*/
long getIdleTimeout();
/**
* This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit
* idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30
* seconds, and average variation of +15 seconds. A connection will never be retired as idle before this timeout.
* A value of 0 means that idle connections are never removed from the pool.
*
* @param idleTimeoutMs the idle timeout in milliseconds
*/
void setIdleTimeout(long idleTimeoutMs);
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @return the maximum connection lifetime in milliseconds
*/
long getMaxLifetime();
/**
* This property controls the maximum lifetime of a connection in the pool. When a connection reaches this
* timeout, even if recently used, it will be retired from the pool. An in-use connection will never be
* retired, only when it is idle will it be removed.
*
* @param maxLifetimeMs the maximum connection lifetime in milliseconds
*/
void setMaxLifetime(long maxLifetimeMs);
/**
* The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool,
* including both idle and in-use connections. If the idle connections dip below this value, HikariCP will
* make a best effort to restore them quickly and efficiently.
*
* @return the minimum number of connections in the pool
*/
int getMinimumIdle();
/**
* The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool,
* including both idle and in-use connections. If the idle connections dip below this value, HikariCP will
* make a best effort to restore them quickly and efficiently.
*
* @param minIdle the minimum number of idle connections in the pool to maintain
*/
void setMinimumIdle(int minIdle);
/**
* The property controls the maximum number of connections that HikariCP will keep in the pool,
* including both idle and in-use connections.
*
* @return the maximum number of connections in the pool
*/
int getMaximumPoolSize();
/**
* The property controls the maximum size that the pool is allowed to reach, including both idle and in-use
* connections. Basically this value will determine the maximum number of actual connections to the database
* backend.
* <p>
* When the pool reaches this size, and no idle connections are available, calls to getConnection() will
* block for up to connectionTimeout milliseconds before timing out.
*
* @param maxPoolSize the maximum number of connections in the pool
*/
void setMaximumPoolSize(int maxPoolSize);
/**
* Set the password used for authentication. Changing this at runtime will apply to new connections only.
* Altering this at runtime only works for DataSource-based connections, not Driver-class or JDBC URL-based
* connections.
*
* @param password the database password
*/
void setPassword(String password);
/**
* Set the username used for authentication. Changing this at runtime will apply to new connections only.
* Altering this at runtime only works for DataSource-based connections, not Driver-class or JDBC URL-based
* connections.
*
* @param username the database username
*/
void setUsername(String username);
/**
* The name of the data source.
*
* @return the name of the connection pool
*/
String getName();
}
package com.secoo.mall.datasource.config;
import lombok.Data;
@Data
public class MatrixDataSourceConfig implements DataSourceConfig {
private String name;
private String username;
private String password;
/**
* Connection url
*/
private String url;
private int minimumIdle = DEFAULT_MIN_IDLE;
private int maxPoolSize = DEFAULT_POOL_SIZE;
/**
* Unit:Millis
*/
private long connectionTimeout = CONNECTION_TIMEOUT;
private long idleTimeout = IDLE_TIMEOUT;
private long maxLifetime = MAX_LIFETIME;
public void setName(String name) {
this.name = POOL_NAME_PRIFIX + name;
}
@Override
public long getConnectionTimeout() {
return connectionTimeout;
}
@Override
public void setConnectionTimeout(long connectionTimeoutMs) {
this.connectionTimeout = connectionTimeoutMs;
}
@Override
public long getIdleTimeout() {
return idleTimeout;
}
@Override
public void setIdleTimeout(long idleTimeoutMs) {
this.idleTimeout = idleTimeoutMs;
}
@Override
public long getMaxLifetime() {
return maxLifetime;
}
@Override
public void setMaxLifetime(long maxLifetimeMs) {
this.maxLifetime = maxLifetimeMs;
}
@Override
public int getMinimumIdle() {
return this.minimumIdle;
}
@Override
public void setMinimumIdle(int minIdle) {
this.minimumIdle = minIdle;
}
@Override
public int getMaximumPoolSize() {
return maxPoolSize;
}
@Override
public void setMaximumPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
}
package com.secoo.mall.datasource.constant;
import java.util.concurrent.TimeUnit;
public interface DataSourceConstant {
/**
* 解密服务
*/
String APP_SECURITY_SERVER_HOST = "http://localhost:9080";
/**
* 解密文件
*/
String SECURITY_FILE_JAR_PATH = APP_SECURITY_SERVER_HOST + "/file/getSecurityFile.jar";
/**
* 获取私钥
*/
String APP_SALT_KEY_PATH = APP_SECURITY_SERVER_HOST + "/config/getPrivateKeyByAppId?appId=%s";
/**
* 阿波罗数据库的配置命名空间
*/
String DB_NAMESPACE = "db.config";
/**
* 属性配置分割符
*/
String PROPETY_SPLIT_CHAR = "\\.";
/**
* 加密标识
*/
String ENCRY_FLAG = "###";
/**
* http访问超时时间。10S
*/
Long HTTP_CONNETION_TIME_COUT = TimeUnit.SECONDS.toMillis(10L);
}
package com.secoo.mall.datasource.constant;
import com.secoo.mall.datasource.factory.DataSourceFactory;
import com.secoo.mall.datasource.factory.DruidDataSourceFactory;
import com.secoo.mall.datasource.factory.HikariDataSourceFactory;
public enum DataSourceTypeEnum {
DRUID("druid", new DruidDataSourceFactory()), HIKARI("hikari", new HikariDataSourceFactory());
private String name;
private DataSourceFactory dataSourceFactory;
DataSourceTypeEnum(String name, DataSourceFactory dataSourceFactory) {
this.name = name;
this.dataSourceFactory = dataSourceFactory;
}
public String getName() {
return name;
}
public DataSourceFactory getDataSourceFactory() {
return dataSourceFactory;
}
public static DataSourceTypeEnum getByName(String name) {
for (DataSourceTypeEnum typeEnum : DataSourceTypeEnum.values()) {
if (typeEnum.getName().equals(name)) {
return typeEnum;
}
}
return null;
}
}
package com.secoo.mall.datasource.errorcode;
import com.secoo.mall.common.core.errorcode.ErrorCode;
public interface DataSourceError {
ErrorCode APOLLO_CONFIG_NOT_EXIST = new ErrorCode(1, "appollo config not exits");
ErrorCode PRIVATE_KEY_NOT_EXIST = new ErrorCode(2, "http get privatekey fail");
ErrorCode APP_ID_NOT_EXIST = new ErrorCode(3, "please config -Dappp.id");
ErrorCode DATA_SOURCE_NOT_EXIST = new ErrorCode(4, "could not find a datasource named %s");
}
package com.secoo.mall.datasource.factory;
import com.secoo.mall.datasource.config.MatrixDataSourceConfig;
import javax.sql.DataSource;
public abstract class AbsDataSourceFactory<T> implements DataSourceFactory<T> {
@Override
public <T extends DataSource> T createDataSouce(MatrixDataSourceConfig config) {
return convertAndCreate(config);
}
protected abstract <T extends DataSource> T convertAndCreate(MatrixDataSourceConfig config);
}
package com.secoo.mall.datasource.factory;
import com.secoo.mall.datasource.config.MatrixDataSourceConfig;
import javax.sql.DataSource;
public interface DataSourceFactory<T> {
<T extends DataSource> T createDataSouce(MatrixDataSourceConfig config);
}
package com.secoo.mall.datasource.factory;
import com.alibaba.druid.pool.DruidDataSource;
import com.secoo.mall.datasource.config.MatrixDataSourceConfig;
import java.util.Properties;
public class DruidDataSourceFactory extends AbsDataSourceFactory<DruidDataSource> {
private final String duridPreFix = "druid.";
@Override
protected DruidDataSource convertAndCreate(MatrixDataSourceConfig config) {
Properties properties = new Properties();
properties.setProperty(duridPreFix + "name", config.getName());
properties.setProperty(duridPreFix + "url", config.getUrl());
properties.setProperty(duridPreFix + "username", config.getUsername());
properties.setProperty(duridPreFix + "password", config.getPassword());
//连接相关信息
properties.setProperty(duridPreFix + "minIdle", String.valueOf(config.getMinimumIdle()));
properties.setProperty(duridPreFix + "maxActive", String.valueOf(config.getMaximumPoolSize()));
properties.setProperty(duridPreFix + "phyTimeoutMillis", String.valueOf(config.getConnectionTimeout()));
properties.setProperty(duridPreFix + "timeBetweenEvictionRunsMillis", String.valueOf(config.getIdleTimeout()));
properties.setProperty(duridPreFix + "maxEvictableIdleTimeMillis", String.valueOf(config.getMaxLifetime()));
DruidDataSource dataSource = new DruidDataSource();
dataSource.configFromPropety(properties);
return dataSource;
}
}
package com.secoo.mall.datasource.factory;
import com.secoo.mall.app.security.encryptor.Encryptor;
import com.secoo.mall.common.constant.CharConstant;
import com.secoo.mall.common.core.classloader.MatrixUrlClassLoader;
import com.secoo.mall.common.core.exception.BusinessException;
import com.secoo.mall.common.util.file.IOUtil;
import com.secoo.mall.common.util.net.IpUtil;
import com.secoo.mall.common.util.string.StringUtil;
import com.secoo.mall.common.util.sys.SystemUtil;
import com.secoo.mall.datasource.constant.DataSourceConstant;
import com.secoo.mall.datasource.errorcode.DataSourceError;
import com.secoo.mall.datasource.util.SysUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Objects;
@Slf4j
public class EncryptorFactory<T> {
private volatile static EncryptorFactory instance;
private Encryptor<T> encryptor;
private final String privateKey = initPrivateKey();
/**
* 初始化是进行远程加载加密文件
*/
private EncryptorFactory() {
createEncryptor();
}
public static EncryptorFactory getInstance() {
if (instance == null) {
synchronized (EncryptorFactory.class) {
if (instance == null)
instance = new EncryptorFactory();
}
}
return instance;
}
public Encryptor<T> getEncryptor() {
return encryptor;
}
public String getPrivateKey() {
return privateKey;
}
/**
* 同步方式获取数据
*
* @return
*/
private String initPrivateKey() {
String appId = SystemUtil.APP_ID;
if (StringUtil.isEmpty(appId)) {
throw new BusinessException(DataSourceError.APP_ID_NOT_EXIST);
}
HttpURLConnection connection = null;
try {
URL url = new URL(String.format(DataSourceConstant.APP_SALT_KEY_PATH, appId));
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.addRequestProperty("appId", appId);
connection.addRequestProperty("accessToken", SysUtil.getProperty("accessToken"));
connection.addRequestProperty("hostIp", IpUtil.getHostIp());
connection.addRequestProperty("hostName", IpUtil.getHostName());
connection.setConnectTimeout(DataSourceConstant.HTTP_CONNETION_TIME_COUT.intValue());
connection.connect();
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();
List<String> strings = IOUtil.readLines(inputStream, CharConstant.CHARSET_NAME);
log.info("get key secucess");
return String.join("", strings);
}
} catch (Exception e) {
log.error("connetion server error", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
private void createEncryptor() {
if (StringUtil.isNotEmpty(this.privateKey)) {
MatrixUrlClassLoader.getInstance().loadByUrl(DataSourceConstant.SECURITY_FILE_JAR_PATH);
String[] args = this.privateKey.split(DataSourceConstant.ENCRY_FLAG);
encryptor = MatrixUrlClassLoader.getInstance().loadClassByFullName("com.secoo.mall.app.security.encryptor.StringEncryptor", Encryptor.class, new Class[]{String.class, String.class}, args);
}
/**
* 如果无法从远程创建解密对象,则进行降级处理
*/
if (Objects.isNull(encryptor)) {
encryptor = new Encryptor<T>() {
@Override
public T encrypt(T value) {
return value;
}
@Override
public T decrypt(T encryptedValue) {
return encryptedValue;
}
};
}
}
public static void main(String[] args) {
Encryptor encryptor = EncryptorFactory.getInstance().getEncryptor();
String key = "8d5862bcc9d076f20d2788cd731e4aa1cc7a0d187b1e9b9245d35f0f18f51968";
System.out.println(encryptor.decrypt(key));
}
}
package com.secoo.mall.datasource.factory;
import com.secoo.mall.datasource.config.MatrixDataSourceConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class HikariDataSourceFactory extends AbsDataSourceFactory<HikariDataSource> {
@Override
protected HikariDataSource convertAndCreate(MatrixDataSourceConfig config) {
//基础配置
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(config.getUrl());
hikariConfig.setPoolName(config.getName());
hikariConfig.setUsername(config.getUsername());
hikariConfig.setPassword(config.getPassword());
//连接相关配置
hikariConfig.setMinimumIdle(config.getMinimumIdle());
hikariConfig.setMinimumIdle(config.getMinimumIdle());
hikariConfig.setMaximumPoolSize(config.getMaximumPoolSize());
hikariConfig.setIdleTimeout(config.getIdleTimeout());
hikariConfig.setMaxLifetime(config.getMaxLifetime());
hikariConfig.setConnectionTimeout(config.getConnectionTimeout());
return new HikariDataSource(hikariConfig);
}
}
package com.secoo.mall.datasource.holder;
import com.secoo.mall.common.util.string.StringUtil;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* 数据源管理工具
*/
public final class DataSourceContextHolder {
private static final ThreadLocal<Deque<String>> DATA_SOURCE_HOLDER = new ThreadLocal() {
@Override
protected Object initialValue() {
return new ArrayDeque();
}
};
private DataSourceContextHolder() {
}
/**
* 获取数据源
*
* @return 数据源名臣
*/
public static String getDs() {
return DATA_SOURCE_HOLDER.get().peek();
}
/**
* 设置数据源
*
* @param ds
*/
public static void setDs(String ds) {
DATA_SOURCE_HOLDER.get().push(StringUtil.isNotEmpty(ds) ? ds : "");
}
/**
* 如果当前线程是连续切换数据源 只会移除掉当前方法的数据源名称
*/
public static void clear() {
Deque<String> deque = DATA_SOURCE_HOLDER.get();
deque.poll();
if (deque.isEmpty()) {
forceClear();
}
}
/**
* 强制清空线程中的数据源
* <p>手动清空数据源,防止OOM</p>
*/
public static void forceClear() {
DATA_SOURCE_HOLDER.remove();
}
}
package com.secoo.mall.datasource.properties;
import com.secoo.mall.datasource.config.MatrixDataSourceConfig;
import com.secoo.mall.datasource.constant.DataSourceTypeEnum;
import lombok.Data;
@Data
public class MatrixDataSourceProperties extends MatrixDataSourceConfig {
public static final String PREFIX = "spring.datasource.matrix";
public static final DataSourceTypeEnum DEFAULT_DATASOURCE_TYPE = DataSourceTypeEnum.HIKARI;
public MatrixDataSourceProperties() {
}
/**
* SourceType DRUID or HIKARI.
* Default value HIKARI.
*/
private DataSourceTypeEnum type = DEFAULT_DATASOURCE_TYPE;
public void setType(String type) {
this.type = DataSourceTypeEnum.getByName(type);
}
}
package com.secoo.mall.datasource.provider;
import com.google.common.collect.Maps;
import com.secoo.mall.app.security.encryptor.Encryptor;
import com.secoo.mall.datasource.bean.MatrixDataSource;
import com.secoo.mall.datasource.config.DataSourceConfig;
import com.secoo.mall.datasource.constant.DataSourceConstant;
import com.secoo.mall.datasource.factory.EncryptorFactory;
import com.secoo.mall.datasource.properties.MatrixDataSourceProperties;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
public abstract class AbsDataSourceProvider<T extends MatrixDataSourceProperties> implements DataSourceProvider {
private Encryptor<String> encryptor = EncryptorFactory.getInstance().getEncryptor();
@Override
public Map<String, DataSource> loadDataSources() {
List<T> list = getDataSourceProperties();
Map<String, DataSource> dataSourceMap = Maps.newHashMapWithExpectedSize(list.size());
for (T properties : list) {
DataSource dataSource = new MatrixDataSource(properties.getType(), properties);
//取得原数据源名称
String dsName = properties.getName().replace(DataSourceConfig.POOL_NAME_PRIFIX, "");
dataSourceMap.put(dsName, dataSource);
}
return dataSourceMap;
}
/**
* 解密相关加密属性项项
*/
public String decryptPropertyItemValue(String value) {
if (value.contains(DataSourceConstant.ENCRY_FLAG)) {
value = encryptor.decrypt(value);
}
return value;
}
protected abstract List<T> getDataSourceProperties();
}
package com.secoo.mall.datasource.provider;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.google.common.collect.Lists;
import com.secoo.mall.common.core.exception.BusinessException;
import com.secoo.mall.common.util.colletion.CollectionUtil;
import com.secoo.mall.common.util.string.StringUtil;
import com.secoo.mall.datasource.constant.DataSourceConstant;
import com.secoo.mall.datasource.errorcode.DataSourceError;
import com.secoo.mall.datasource.properties.MatrixDataSourceProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.MethodUtils;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 从Apollo配置中心进行加载
*/
@Slf4j
public class ApolloDataSourceProvider extends AbsDataSourceProvider<MatrixDataSourceProperties> {
/**
* 从appollo加载配置信息
*
* @return
*/
@Override
protected List<MatrixDataSourceProperties> getDataSourceProperties() {
Config appConfig = ConfigService.getConfig(DataSourceConstant.DB_NAMESPACE);
Set<String> propertyNames = appConfig.getPropertyNames();
List<MatrixDataSourceProperties> list = Lists.newArrayList();
Map<String, DataSource> dataSourceMap = new HashMap<>();
if (CollectionUtil.isEmpty(propertyNames)) {
throw new BusinessException(DataSourceError.APOLLO_CONFIG_NOT_EXIST);
}
//用数据源名字为key,进行分组
Map<String, List<String>> propertyMap = propertyNames.stream().filter(pro -> pro.contains(MatrixDataSourceProperties.PREFIX)).map(pro -> pro.replace(MatrixDataSourceProperties.PREFIX, ""))
.collect(Collectors.groupingBy(str -> str.split(DataSourceConstant.PROPETY_SPLIT_CHAR)[1]));
try {
for (Map.Entry<String, List<String>> entry : propertyMap.entrySet()) {
String dsName = entry.getKey();
MatrixDataSourceProperties matrixDataSourceProperties = new MatrixDataSourceProperties();
matrixDataSourceProperties.setName(dsName);
for (String property : entry.getValue()) {
String propertyFullPath = MatrixDataSourceProperties.PREFIX + property;
String value = decryptPropertyItemValue(appConfig.getProperty(propertyFullPath, ""));
//得到实际的属性,首字母大写
String beanProperty = StringUtil.capitalize(property.split(DataSourceConstant.PROPETY_SPLIT_CHAR)[2]);
MethodUtils.invokeExactMethod(matrixDataSourceProperties, "set" + beanProperty, value);
}
log.info("init datasource name:{}", dsName);
list.add(matrixDataSourceProperties);
}
} catch (Exception e) {
log.error("e:", e);
throw new BusinessException(DataSourceError.APOLLO_CONFIG_NOT_EXIST);
}
return list;
}
}
package com.secoo.mall.datasource.provider;
import javax.sql.DataSource;
import java.util.Map;
public interface DataSourceProvider {
/**
* 加载定义的数据源
*
* @return
*/
Map<String, DataSource> loadDataSources();
}
package com.secoo.mall.datasource.provider;
import com.secoo.mall.datasource.properties.MatrixDataSourceProperties;
import lombok.Setter;
import java.util.List;
/**
* 默认的,基于Spring的配置的加载方式
*/
public class DefaultDataSourceProvider extends AbsDataSourceProvider<MatrixDataSourceProperties> {
/**
* 注入配置
*/
@Setter
private List<MatrixDataSourceProperties> dataSourceConfigs;
@Override
protected List<MatrixDataSourceProperties> getDataSourceProperties() {
return this.dataSourceConfigs;
}
}
package com.secoo.mall.datasource.util;
import lombok.extern.slf4j.Slf4j;
import java.util.Properties;
@Slf4j
public class SysUtil {
private static Properties properties = new Properties();
public static void setProperty(String key, String value) {
properties.setProperty(key, value);
}
public static String getProperty(String key) {
return properties.getProperty(key);
}
}
package com.secoo.mall.mybatis.datasouce;
import com.secoo.mall.datasource.bean.MatrixDataSource;
import com.secoo.mall.datasource.config.MatrixDataSourceConfig;
import com.secoo.mall.datasource.constant.DataSourceTypeEnum;
import org.junit.Test;
public class DataSourceTest {
@Test
public void testCreateDataSource() {
MatrixDataSourceConfig config = new MatrixDataSourceConfig();
config.setName("01");
// config.setType(DataSourceType.HIKARI);
config.setUrl("jdbc:mysql://127.0.0.1:3306/appmsdb?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false");
config.setPassword("mysql");
config.setUsername("root");
MatrixDataSource dataSource = new MatrixDataSource(DataSourceTypeEnum.HIKARI, config);
System.out.println(dataSource);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.1.9.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>matrix-datasource</artifactId>
<packaging>pom</packaging>
<modules>
<module>matrix-datasource-core</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.2.0</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>app-security-algo</artifactId>
<version>1.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-core</artifactId>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-util</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
# 介绍
mybatis-starter
# 特点
-
# 开始
- 添加依赖
- Maven:需要在自己项目的pom.xml增加,以下配置。
**注意:前置条件需要依赖项目中需要设置matrix的parent**
```xml
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>mybatis-starter</artifactId>
</dependency>
```
# 数据源设计
- core实现由远程加载解密class,根据全局app.id获取加密信息
- starter等组件完成对配置中心、数据源包装
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>matrix-mybatis</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.1.9.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>matrix-mybatis-core</artifactId>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>matrix-datasource-core</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.secoo.mall.mybatis.bean;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.secoo.mall.mybatis.config.MatrixMybatisConfig;
import com.secoo.mall.mybatis.config.MatrixMybatisGlobalConfig;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.io.IOException;
public class MatrixMybatisSqlSessionFactoryBean extends MybatisSqlSessionFactoryBean {
public MatrixMybatisSqlSessionFactoryBean(){
}
public MatrixMybatisSqlSessionFactoryBean(MatrixMybatisConfig matrixMybatisConfig, MatrixMybatisGlobalConfig matrixMybatisGlobalConfig) {
this.setConfiguration(matrixMybatisConfig);
this.setGlobalConfig(matrixMybatisGlobalConfig);
this.setTypeAliasesPackage(matrixMybatisConfig.getBeanAliasPackages());
try {
this.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(matrixMybatisConfig.getResourceClassPath()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.secoo.mall.mybatis.config;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.toolkit.PackageHelper;
import com.secoo.mall.common.constant.CommonConstant;
import com.secoo.mall.common.util.string.StringUtil;
import com.secoo.mall.common.util.sys.SystemUtil;
import lombok.Data;
import org.apache.ibatis.type.JdbcType;
@Data
public class MatrixMybatisConfig extends MybatisConfiguration {
private String beanAliasPackages = StringUtil.join(PackageHelper.convertTypeAliasesPackage("com.secoo.mall.**.bean.domain"), ",");
private String resourceClassPath = "classpath:mybatis/*.xml";
public MatrixMybatisConfig() {
if (!SystemUtil.ENV.equals(CommonConstant.Env.PRO)) {
this.addInterceptor(new PerformanceInterceptor());
}
//空值转为null
this.setJdbcTypeForNull(JdbcType.NULL);
// 驼峰转下划线
this.setMapUnderscoreToCamelCase(true);
//分页插件
this.addInterceptor(new PaginationInterceptor());
this.setBeanAliasPackages(beanAliasPackages);
this.setResourceClassPath(resourceClassPath);
}
public MatrixMybatisConfig(String beanAliasPackages,String resourceClassPath) {
this();
this.setBeanAliasPackages(beanAliasPackages);
this.setResourceClassPath(resourceClassPath);
}
}
package com.secoo.mall.mybatis.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.secoo.mall.mybatis.handler.FillDefaultValueHandler;
import lombok.Setter;
import java.util.Objects;
@Setter
public class MatrixMybatisGlobalConfig extends GlobalConfig {
/**
* 增加全局默认的配置
*/
public MatrixMybatisGlobalConfig() {
this.setMetaObjectHandler(getFillDefaultValueHandler());
this.setDbConfig(getDbConfig());
}
public DbConfig getDefaultDbConfig() {
if (Objects.isNull(getDbConfig())) {
return createDefaultDbConfig();
}
return getDbConfig();
}
public MetaObjectHandler getFillDefaultValueHandler() {
return Objects.isNull(this.getMetaObjectHandler()) ? new FillDefaultValueHandler() : this.getMetaObjectHandler();
}
private DbConfig createDefaultDbConfig() {
DbConfig dbConfig = new DbConfig();
dbConfig.setIdType(IdType.AUTO);
dbConfig.setDbType(DbType.MYSQL);
return dbConfig;
}
}
...@@ -6,7 +6,6 @@ import org.springframework.stereotype.Component; ...@@ -6,7 +6,6 @@ import org.springframework.stereotype.Component;
import java.util.Date; import java.util.Date;
@Component
public class FillDefaultValueHandler implements MetaObjectHandler { public class FillDefaultValueHandler implements MetaObjectHandler {
@Override @Override
public void insertFill(MetaObject metaObject) { public void insertFill(MetaObject metaObject) {
......
...@@ -3,43 +3,36 @@ ...@@ -3,43 +3,36 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix-mybatis</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>mybatis-starter</artifactId> <artifactId>matrix-mybatis-starter</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>common-core</artifactId> <artifactId>matrix-mybatis-core</artifactId>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-util</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis-plus-boot-starter</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId> <artifactId>spring-boot-starter-aop</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>spring-tx</artifactId> <artifactId>config-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
...@@ -15,7 +15,7 @@ import javax.annotation.Resource; ...@@ -15,7 +15,7 @@ import javax.annotation.Resource;
@Aspect @Aspect
@Component @Component
@ConditionalOnProperty(value = "matrix.aop-transaction.enabled",havingValue = "true") @ConditionalOnProperty(value = "matrix.aop-transaction.enabled", havingValue = "true")
public class AopTransaction { public class AopTransaction {
@Resource @Resource
private PlatformTransactionManager transactionManager; private PlatformTransactionManager transactionManager;
......
package com.secoo.mall.mybatis.config;
import com.secoo.mall.mybatis.bean.MatrixMybatisSqlSessionFactoryBean;
import com.secoo.mall.mybatis.spring.boot.autoconfigure.MatrixMybatisAutoConfiguration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import javax.sql.DataSource;
//@Configuration
//@AutoConfigureAfter(MatrixMybatisAutoConfiguration.class)
public class MatrixMybatisConfiguration {
/* @Bean
@ConditionalOnMissingBean(SqlSessionFactory.class)
public SqlSessionFactory sqlSessionFactory(DataSource dataSource,MatrixMybatisConfig matrixMybatisConfig,MatrixMybatisGlobalConfig matrixMybatisGlobalConfig) throws Exception {
MatrixMybatisSqlSessionFactoryBean sqlSessionFactory = new MatrixMybatisSqlSessionFactoryBean(matrixMybatisConfig,matrixMybatisGlobalConfig);
*//* sqlSessionFactory.setGlobalConfig(matrixMybatisGlobalConfig());
sqlSessionFactory.setConfiguration(matrixMybatisConfig());*//*
sqlSessionFactory.setDataSource(dataSource);
return sqlSessionFactory.getObject();
}*/
}
package com.secoo.mall.mybatis.spring.boot.autoconfigure;
import com.secoo.mall.datasource.properties.MatrixDataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = MatrixDefaultDataSourceProperties.PREFIX)
public class MatrixDefaultDataSourceProperties extends MatrixDataSourceProperties {
public static final String PREFIX = MatrixDataSourceProperties.PREFIX + ".default";
}
package com.secoo.mall.mybatis.spring.boot.autoconfigure;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import com.baomidou.mybatisplus.extension.toolkit.PackageHelper;
import com.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration;
import com.secoo.mall.common.util.string.StringUtil;
import com.secoo.mall.datasource.bean.MatrixDataSource;
import com.secoo.mall.datasource.bean.MatrixDynamicDataSource;
import com.secoo.mall.datasource.provider.ApolloDataSourceProvider;
import com.secoo.mall.datasource.provider.DataSourceProvider;
import com.secoo.mall.datasource.util.SysUtil;
import com.secoo.mall.mybatis.bean.MatrixMybatisSqlSessionFactoryBean;
import com.secoo.mall.mybatis.config.MatrixMybatisConfig;
import com.secoo.mall.mybatis.config.MatrixMybatisGlobalConfig;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
@Configuration
@ConditionalOnClass(MatrixDataSource.class)
@AutoConfigureBefore({DataSourceAutoConfiguration.class, MybatisPlusAutoConfiguration.class})
@AutoConfigureAfter(ApolloAutoConfiguration.class)
@EnableConfigurationProperties({MatrixDefaultDataSourceProperties.class})
//@Import(MatrixMybatisAutoConfiguration.class)
@Slf4j
public class MatrixMybatisAutoConfiguration {
@Setter
private MatrixDefaultDataSourceProperties matrixDefaultDataSourceProperties;
public MatrixMybatisAutoConfiguration() {
log.info("Init MatrixDataSouceAutoConfiguration");
}
@Value("${config.app.security.accessToken}")
private String acccessToken;
@Bean
@ConditionalOnMissingBean(DataSourceProvider.class)
public DataSourceProvider dataSourceProvider() {
SysUtil.setProperty("accessToken", acccessToken);
return new ApolloDataSourceProvider();
}
/**
* 如果没有声明,则使用默认的
*
* @return
*/
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource() {
return new MatrixDynamicDataSource("default");
}
@Bean
@ConditionalOnMissingBean(SqlSessionFactory.class)
public SqlSessionFactory sqlSessionFactory(DataSource dataSource, MatrixMybatisConfig matrixMybatisConfig, MatrixMybatisGlobalConfig matrixMybatisGlobalConfig) throws Exception {
MatrixMybatisSqlSessionFactoryBean sqlSessionFactory = new MatrixMybatisSqlSessionFactoryBean(matrixMybatisConfig,matrixMybatisGlobalConfig);
sqlSessionFactory.setDataSource(dataSource);
return sqlSessionFactory.getObject();
}
@Bean
@ConditionalOnMissingBean(MatrixMybatisGlobalConfig.class)
public MatrixMybatisGlobalConfig matrixMybatisGlobalConfig() {
MatrixMybatisGlobalConfig globalConfig = new MatrixMybatisGlobalConfig();
return globalConfig;
}
@Bean
@ConditionalOnMissingBean(MatrixMybatisConfig.class)
public MatrixMybatisConfig matrixMybatisConfig() {
MatrixMybatisConfig config = new MatrixMybatisConfig();
return config;
}
}
package com.secoo.mall.mybatis.spring.boot.initializer;
import com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.ConfigurableEnvironment;
public class MybatisApplicationContextInitializer extends ApolloApplicationContextInitializer {
private static Logger log = LoggerFactory.getLogger(MybatisApplicationContextInitializer.class);
public static String MYBATIS_ENCRYPT_PWD = "mybatis.encryptor.pwd";
public static String MYBATIS_ENCRYPT_SALT = "mybatis.encryptor.salt";
public static String ENCRYPT_FILE_NAME = "encryptor.properties";
@Override
protected void initialize(ConfigurableEnvironment environment) {
super.initialize(environment);
}
// public static Integer ORDER = ApolloApplicationContextInitializer.DEFAULT_ORDER + 100;
/* @Override
public void initialize(ConfigurableApplicationContext context) {
//log.info("initialize.....................");
ConfigurableEnvironment environment = context.getEnvironment();
if (!environment.containsProperty(MYBATIS_ENCRYPT_PWD)) {
Properties properties = new Properties();
//从-D读取
initDConfig(properties);
//从文件加载
initFileConfig(properties);
//解密配置
initApolloConfig(properties);
environment.getPropertySources();
environment.getPropertySources().addFirst((new PropertiesPropertySource("matrixProperties", properties)));
}
}
@Override
public int getOrder() {
return ORDER;
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
// log.info("postProcessEnvironment.......");
}
private void initDConfig(Properties properties) {
if (System.getProperty(MYBATIS_ENCRYPT_PWD) != null) {
properties.setProperty(MYBATIS_ENCRYPT_PWD, System.getProperty(MYBATIS_ENCRYPT_PWD));
properties.setProperty(MYBATIS_ENCRYPT_SALT, System.getProperty(MYBATIS_ENCRYPT_SALT));
}
}
private void initFileConfig(Properties properties) {
if(!properties.containsKey(MYBATIS_ENCRYPT_PWD)) {
try {
File file = ResourceUtils.getFile(SystemUtils.USER_HOME + File.separator + ENCRYPT_FILE_NAME);
if (!file.exists()) {
// log.warn(ENCRYPT_FILE_NAME + " not exist");
return;
}
properties.load(new FileInputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
*//**
* 解密相关的配置
*//*
private void initApolloConfig(Properties properties){
Config appConfig = ConfigService.getConfig("db.config");
Set<String> propertyNames = appConfig.getPropertyNames();
// log.info(propertyNames.toString());
}*/
}
package com.secoo.mall.mybatis.spring.boot.listener;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
@Slf4j
@NoArgsConstructor
public class MybatisApplicationRunListener implements SpringApplicationRunListener, Ordered {
public static String MYBATIS_ENCRYPT_PWD = "mybats.encryptor.pwd";
public static String MYBATIS_ENCRYPT_SALT = "mybats.encryptor.salt";
public static String ENCRYPT_FILE_NAME = "encryptor.properties";
public static Integer ORDER = ApolloApplicationContextInitializer.DEFAULT_ORDER + 1;
public MybatisApplicationRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting() {
log.info("Appication Starting.....");
}
/**
* 配置加载的依次顺序:
* 1.-spring.config方式加载外部配置
* 2.-D获取
* 3.本地
*
* @param environment
*/
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
if (!environment.containsProperty(MYBATIS_ENCRYPT_PWD)) {
Properties properties = new Properties();
//从-D读取
initDConfig(properties);
//从文件加载
initFileConfig(properties);
//解密配置
// initApolloConfig(properties);
environment.getPropertySources();
environment.getPropertySources().addFirst((new PropertiesPropertySource("matrixProperties", properties)));
}
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
log.info("contextPrepared......");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
@Override
public void started(ConfigurableApplicationContext context) {
}
@Override
public void running(ConfigurableApplicationContext context) {
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
}
@Override
public int getOrder() {
return ORDER;
}
private void initDConfig(Properties properties) {
if (System.getProperty(MYBATIS_ENCRYPT_PWD) != null) {
properties.setProperty(MYBATIS_ENCRYPT_PWD, System.getProperty(MYBATIS_ENCRYPT_PWD));
properties.setProperty(MYBATIS_ENCRYPT_SALT, System.getProperty(MYBATIS_ENCRYPT_SALT));
}
}
private void initFileConfig(Properties properties) {
if (!properties.containsKey(MYBATIS_ENCRYPT_PWD)) {
try {
File file = ResourceUtils.getFile(SystemUtils.USER_HOME + File.separator + ENCRYPT_FILE_NAME);
if (!file.exists()) {
log.warn(ENCRYPT_FILE_NAME + " not exist");
return;
}
properties.load(new FileInputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 解密相关的配置
*/
private void initApolloConfig(Properties properties) {
Config appConfig = ConfigService.getConfig("db.config");
Set<String> propertyNames = appConfig.getPropertyNames();
log.info(propertyNames.toString());
}
}
com.secoo.mall.mybatis.spring.boot.autoconfigure.MatrixDataSouceAutoConfiguration=
\ No newline at end of file
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.secoo.mall.mybatis.spring.boot.autoconfigure.MatrixMybatisAutoConfiguration
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId>
<version>1.1.9.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>matrix-mybatis</artifactId>
<packaging>pom</packaging>
<modules>
<module>matrix-mybatis-starter</module>
<module>matrix-mybatis-core</module>
</modules>
<properties>
<mybatis-plus.version>3.1.0</mybatis-plus.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>matrix-mybatis-core</artifactId>
<version>1.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>matrix-mybatis-starter</artifactId>
<version>1.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>matrix-datasource-core</artifactId>
<version>1.1.9.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-core</artifactId>
</dependency>
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>common-util</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
# 介绍
mybatis-starter基于[mybatis-plus](https://mp.baomidou.com/)进行二次封装,简化对dao层数据访问操作。
# 特点
- 提供分页Page对象统一封装
- 提供分页对象结果DataPage,进行统一定义
- 非生产环境提供sql打印
- 支持createTime默认字段填充(见demo)
- 支持事务切面。增加matrix.aop-transaction.enabled配置,默认false,未开启,此时在需要的事务上增加@Transactional。修改为true,表示service方法名以add、save、create、modify、update、remove、delete为前缀的方法自动追加事务。
# 最佳实践
- matrix.aop-transaction.enabled设置为true,节省事务配置
- bean路径放置com.secoo.mall.**.bean.domain
- xml放置在resource/mybatis路径下
- 对于复杂sql使用xml,如多表关联查询,对于单表操作使用QueryWapper操作
- 所有与数据叫交互放到Mapper中,不要直接写在service中。如
```
@Mapper
public interface ProjectMapper extends BaseMapper<Project> {
default Project getByName(String name) {
return this.selectOne(new QueryWrapper<Project> ().lambda().eq(Project::getName, name).ne(Project::getStatus, ProjectConstant.Status.DELETE).last(" limit 1"));
}
```
# 文档
- [mybaties-plus开发指南](https://mp.baomidou.com/guide/)
# 开始
- 添加依赖
- Maven:需要在自己项目的pom.xml增加,以下配置。
**注意:前置条件需要依赖项目中需要设置matrix的parent**
```xml
<dependency>
<groupId>com.secoo.mall</groupId>
<artifactId>mybatis-starter</artifactId>
</dependency>
```
# 示例
- Bean自动填充字段 @TableField
```
public class Project extends AbsBaseBean {
......
@ApiModelProperty(value = "创建时间", hidden = true)
@TableField(fill = FieldFill.INSERT)
private Date createTime;
.....
}
```
- 分页工具类PageUtil使用
- ProjectController
```
@ApiOperation(value = "应用多属性查询", notes = "应用多属性查询")
@PostMapping("/search")
public Object search(Project project, ReqPage reqPage, Sort sort) {
Page<Project> page = PageUtil.createPage(reqPage, sort);
return service.search(project, page);
}
```
- ProjectService
```
public DataPage<Project> search(Project project, Page<Project> page) {
IPage<Project> iPage = mapper.search(project, page);
return PageUtil.createDataPage(iPage);
}
```
- 访问方式
http://localhost:8080/doc.html切换为web可以进行调试
\ No newline at end of file
package com.secoo.mall.mybatis.config;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.baomidou.mybatisplus.extension.toolkit.PackageHelper;
import com.secoo.mall.common.constant.CommonConstant;
import com.secoo.mall.mybatis.handler.FillDefaultValueHandler;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Configuration
public class MybatisConfig {
@Value("${spring.profiles.active}")
private String profile;
@Resource
private MybatisPlusProperties mybatisPlusProperties;
@Bean("mybatisSqlSession")
public SqlSessionFactory sqlSessionFactory(DataSource dataSource, GlobalConfig globalConfig) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
String[] aliasesPackages = PackageHelper.convertTypeAliasesPackage("com.secoo.mall.**.bean.domain");
List<String> list = Stream.of(aliasesPackages).collect(Collectors.toList());
/*文件包别名加载*/
sqlSessionFactory.setTypeAliasesPackage(StringUtils.join(list, ","));
/*配置文件*/
sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/*.xml"));
/* 数据源 */
sqlSessionFactory.setDataSource(dataSource);
/* entity扫描,mybatis的Alias功能 */
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
/* 驼峰转下划线 */
configuration.setMapUnderscoreToCamelCase(true);
/* 分页插件 */
configuration.addInterceptor(new PaginationInterceptor());
/* 乐观锁插件 */
// configuration.addInterceptor(new OptimisticLockerInterceptor());
//非生产环境加载的插件
if (!CommonConstant.Env.PRO.equals(profile)) {
configuration.addInterceptor(new PerformanceInterceptor());
}
sqlSessionFactory.setConfiguration(configuration);
/* 自动填充插件 */
globalConfig.setMetaObjectHandler(new FillDefaultValueHandler());
sqlSessionFactory.setGlobalConfig(globalConfig);
return sqlSessionFactory.getObject();
}
@Bean("globalConfig")
public GlobalConfig globalConfig() {
GlobalConfig conf = new GlobalConfig();
GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
dbConfig.setIdType(IdType.AUTO);
conf.setDbConfig(dbConfig);
return conf;
}
@Bean
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
}
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
<packaging>pom</packaging> <packaging>pom</packaging>
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<module>common-core</module> <module>common-core</module>
<module>common-util</module> <module>common-util</module>
<module>redis-starter</module> <module>redis-starter</module>
<module>mybatis-starter</module> <module>matrix-mybatis</module>
<module>mongodb-starter</module> <module>mongodb-starter</module>
<module>elasticsearch-starter</module> <module>elasticsearch-starter</module>
<module>openfeign-starter</module> <module>openfeign-starter</module>
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
<module>config-starter</module> <module>config-starter</module>
<module>protocol-starter</module> <module>protocol-starter</module>
<module>logger-starter</module> <module>logger-starter</module>
<module>matrix-datasource</module>
</modules> </modules>
...@@ -30,7 +31,6 @@ ...@@ -30,7 +31,6 @@
<java.version>1.8</java.version> <java.version>1.8</java.version>
<dubbo-starter.version>2.7.1</dubbo-starter.version> <dubbo-starter.version>2.7.1</dubbo-starter.version>
<dubbo.version>2.7.2</dubbo.version> <dubbo.version>2.7.2</dubbo.version>
<matrix.version>1.0.1-DEV-SNAPSHOT</matrix.version>
</properties> </properties>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version> <version>2.1.9.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
...@@ -48,62 +48,62 @@ ...@@ -48,62 +48,62 @@
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>logger-starter</artifactId> <artifactId>logger-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>monitor-starter</artifactId> <artifactId>monitor-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>common-core</artifactId> <artifactId>common-core</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>config-starter</artifactId> <artifactId>config-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>common-util</artifactId> <artifactId>common-util</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>redis-starter</artifactId> <artifactId>redis-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>mybatis-starter</artifactId> <artifactId>matrix-mybatis-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>mongodb-starter</artifactId> <artifactId>mongodb-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>elasticsearch-starter</artifactId> <artifactId>elasticsearch-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>protocol-starter</artifactId> <artifactId>protocol-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>rocketmq-starter</artifactId> <artifactId>rocketmq-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<artifactId>openfeign-starter</artifactId> <artifactId>openfeign-starter</artifactId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>
...@@ -153,22 +153,6 @@ ...@@ -153,22 +153,6 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>20.0</version> <version>20.0</version>
...@@ -281,14 +265,6 @@ ...@@ -281,14 +265,6 @@
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.0.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
...@@ -315,12 +291,12 @@ ...@@ -315,12 +291,12 @@
<snapshotRepository> <snapshotRepository>
<id>secoo-dev</id> <id>secoo-dev</id>
<name>secoo-dev-repository</name> <name>secoo-dev-repository</name>
<url>http://secoo-dev:secoo-dev@nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-dev/</url> <url>http://nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-dev/</url>
</snapshotRepository> </snapshotRepository>
<repository> <repository>
<id>secoo-pro</id> <id>secoo-pro</id>
<name>secoo-pro-repository</name> <name>secoo-pro-repository</name>
<url>http://secoo-pro:secoo-PRO@nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-pro/</url> <url>http://nexus.secoo.com:8081/nexus/content/repositories/secoo-hosted-pro/</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>matrix</artifactId> <artifactId>matrix</artifactId>
<groupId>com.secoo.mall</groupId> <groupId>com.secoo.mall</groupId>
<version>1.1.8.RELEASE</version> <version>1.1.9.RELEASE</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment