1. 设置数据库属性
包括:数据库名称、用户名、密码
在business下创建dto文件夹,自定义SegmentInfo.java,继承AmqServer
package com.hikvision.isc.module.business.dto;
import com.hikvision.starfish.discovery.AmqServer;
import lombok.Data;
@Data
public class SegmentInfo extends AmqServer {
//数据库名称
private String dbname;
//用户名
private String dbusername;
//密码
private String dbpassword;
}
2. 配置文件中配置数据库信息
以本地数据库和ibuilding数据库为例,在配置文件中配置两个数据库的信息
#多数据库切换——数据库配置
#本地数据库信息
localDburl=jdbc:postgresql://10.196.1.45:7092/sscvhb_sscvhbdb
localUserName=sscvhb_sscvhbdb_user
localingPwd=StgR23C3
#ibuilding数据库信息
ibuildDburl=jdbc:postgresql://10.196.1.45:7092/ibuilding_ibuildingdb
ibuildingUserName=ibuilding_ibuildingdb_user
ibuildingPwd=I65BRJSB
3. 引入db模块
在business下引入db模块,该模块包含五个文件
3.1 DataSourceSwitchAspect
切换数据源
package com.hikvision.isc.module.business.db;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: wangyongqiang13
* @Date: 2020/12/22 9:15
*/
@Component
@Aspect
@Order(-1) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
public class DataSourceSwitchAspect {
private final static Logger log = LoggerFactory.getLogger(DataSourceSwitchAspect.class);
//需要从本地数据库获取的数据,需要在mapper文件夹下创建local文件夹,并将mapper文件定义在local文件夹下
@Pointcut("execution(* com.hikvision.isc.sscvhb.module.business.mapper.local..*.*(..))")
private void db1Aspect() {
}
//需要从ibuilding数据库获取的数据,需要在mapper文件夹下创建ibuilding文件夹,并将mapper文件定义在local文件夹下
@Pointcut("execution(* com.hikvision.isc.sscvhb.module.business.mapper.ibuilding..*.*(..))")
private void db2Aspect() {
}
@Before("db1Aspect()")
public void db1() {
log.debug("切换到 local 数据源...");
DbContextHolder.setDbType(DBTypeEnum.db1);
}
@Before("db2Aspect()")
public void db2() {
log.debug("切换到 ibuilding 数据源...");
DbContextHolder.setDbType(DBTypeEnum.db2);
}
}
3.2 DbConfig
用来获取配置文件中的数据库信息
package com.hikvision.isc.module.business.db;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.hikvision.isc.module.business.service.impl.MyHikDiscoveryClientImpl;
import com.hikvision.starfish.discovery.client.impl.HikDiscoveryClientImpl;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* mybatis-plus 扩展配置
*
* @author wangqingxun
* @Date: Created in 2020/12/26
* @since jdk1.8
*/
@Configuration
@MapperScan("com.hikvision.isc.sscvhb.**.mapper*")
public class DbConfig {
private final static Logger log = LoggerFactory.getLogger(DbConfig.class);
//组件表示信息:也是在配置文件中进行配置
@Value("${base.application.componentId}")
private String componentId;
@Value("${base.application.dbSegmentId}")
private String dbSegmentId;
//配置文件中数据库的信息
@Value("${localDburl}")
private String localDburl;
@Value("${localUserName}")
private String localUserName;
@Value("${localingPwd}")
private String localingPwd;
@Value("${ibuildDburl}")
private String ibuildDburl;
@Value("${ibuildingUserName}")
private String ibuildingUserName;
@Value("${ibuildingPwd}")
private String ibuildingPwd;
@Autowired
private MyHikDiscoveryClientImpl myHikDiscoveryClient;
@Autowired
private HikDiscoveryClientImpl hikDiscoveryClient;
private static String driverClass = "org.postgresql.Driver";
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean(name = "db1")
public DataSource db1() {
// SegmentInfo segmentInfo = myHikDiscoveryClient.findAmqServer(componentId,dbSegmentId);
/* log.info("初始化新组件数据库>>>>>>componentId="+componentId+",dbSegmentId="+dbSegmentId+",segmentInfo="+ JSONObject.toJSONString(segmentInfo));
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl("jdbc:postgresql://"+segmentInfo.getIp()+":"+segmentInfo.getPort()+"/"+segmentInfo.getDbName());
dataSource.setUsername(segmentInfo.getDbusername());
dataSource.setPassword(segmentInfo.getDbpassword());*/
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(localDburl);
dataSource.setUsername(localUserName);
dataSource.setPassword(localingPwd);
return dataSource;
}
@Bean(name = "db2")
public DataSource db2() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(ibuildDburl);
dataSource.setUsername(ibuildingUserName);
dataSource.setPassword(ibuildingPwd);
return dataSource;
}
/**
* 动态数据源配置
*
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("db1") DataSource db1,
@Qualifier("db2") DataSource db2
) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map
3.3 DbContextHolder
package com.hikvision.isc.module.business.db;
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
* 设置数据源
*
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum) {
contextHolder.set(dbTypeEnum.getValue());
}
/**
* 取得当前数据源
*
* @return
*/
public static String getDbType() {
return (String) contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clearDbType() {
contextHolder.remove();
}
}
3.4 DBTypeEnum
package com.hikvision.isc.module.business.db;
public enum DBTypeEnum {
db1("db1"),
db2("db2");
private String value;
DBTypeEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
3.5 DynamicDataSource
获取当前使用哪个数据源
package com.hikvision.isc.module.business.db;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 取得当前使用哪个数据源
*
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
4. 自动寻址
在service.impl下创建MyHikDiscoveryClientImpl.java文件夹,继承HikDiscoveryClientImpl(在startfish-discovery-1.8.9.RELEASE.jar包中)
package com.hikvision.starfish.discovery.client.impl;
import com.hikvision.discovery.exception.ServerNotFoundException;
import com.hikvision.notify.dto.servicechange.ServiceChangeMsgDto;
import com.hikvision.starfish.bic.bo.AmqInfo;
import com.hikvision.starfish.bic.client.ServiceDirectoryClient;
import com.hikvision.starfish.bic.constant.BicConstants;
import com.hikvision.starfish.bic.dto.response.ServiceAddressInfoDto;
import com.hikvision.starfish.bic.dto.response.ServiceInfoDto;
import com.hikvision.starfish.core.response.api.ApiResponse;
import com.hikvision.starfish.discovery.AmqServer;
import com.hikvision.starfish.discovery.Server;
import com.hikvision.starfish.discovery.client.HikDiscoveryClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.env.Environment;
import org.springframework.web.client.HttpServerErrorException;
import java.util.Optional;
/**
* @author dengyishi
* @date 2019/5/25
* @since 1.1.0
*/
public class HikDiscoveryClientImpl implements HikDiscoveryClient {
private static final String SUCCESS = "0";
private ServiceDirectoryClient serviceDirectoryClient;
private CacheManager cacheManager;
Server bicServer;
Server casServer;
Server serviceDirectoryServer;
Server licenseServer;
private HikHttpDiscoveryProperties hikHttpDiscoveryProperties;
public HikDiscoveryClientImpl(ServiceDirectoryClient serviceDirectoryClient, CacheManager cacheManager,
Environment environment, HikHttpDiscoveryProperties hikHttpDiscoveryProperties) {
super();
this.serviceDirectoryClient = serviceDirectoryClient;
this.cacheManager = cacheManager;
this.hikHttpDiscoveryProperties = hikHttpDiscoveryProperties;
String bicPort = environment.getRequiredProperty("@bic.bic.port");
bicServer = new Server(environment.getRequiredProperty("@bic.bic.ip"), Integer.valueOf(bicPort), environment.getRequiredProperty("@bic.bic.context"));
String casPort = environment.getRequiredProperty("@bic.cas.port");
casServer = new Server(environment.getRequiredProperty("@bic.cas.ip"), Integer.valueOf(casPort), environment.getRequiredProperty("@bic.cas.context"));
String serviceDirectoryPort = environment.getRequiredProperty("@bic.serviceDirectory.port");
serviceDirectoryServer = new Server(environment.getRequiredProperty("@bic.serviceDirectory.ip"),
Integer.valueOf(serviceDirectoryPort), environment.getRequiredProperty("@bic.serviceDirectory.context"));
String licensePort = environment.getRequiredProperty("@bic.license.port");
licenseServer = new Server(environment.getRequiredProperty("@bic.license.ip"), Integer.valueOf(licensePort), environment.getRequiredProperty("@bic.license.context"));
}
public ServiceInfoDto findService(String componentId, String segmentId) {
ApiResponse result = serviceDirectoryClient.getServiceInfoV2(componentId, segmentId);
return result.getValidatedData(ServerNotFoundException.class,
"寻址" + componentId + "." + segmentId + "时服务目录发生错误");
}
@Cacheable(cacheManager = SERVICE_DISCOVERY_CACHE_MANAGER, cacheNames = SERVICE_DISCOVERY_CACHE, key = "#p0+'.'+#p1", unless = "#result==null")
@Override
public AmqServer findAmqServer(String componentId, String mqSegmentId) {
AmqServer amqServer = new AmqServer();
ServiceInfoDto serviceInfoDto = findService(componentId, mqSegmentId);
if (serviceInfoDto != null && serviceInfoDto.getAmqInfo() != null) {
AmqInfo amqInfo = serviceInfoDto.getAmqInfo();
amqServer.setIp(amqInfo.getIp());
amqServer.setUsername(amqInfo.getUsername());
amqServer.setPassword(amqInfo.getPassword());
amqServer.setSslPort(amqInfo.getSslPort());
amqServer.setPort(amqInfo.getPort());
} else {
throw new ServerNotFoundException("寻址" + componentId + "." + mqSegmentId + "失败,无可用服务信息。请检查寻址参数是否正确");
}
return amqServer;
}
@Cacheable(cacheManager = SERVICE_DISCOVERY_CACHE_MANAGER, cacheNames = SERVICE_DISCOVERY_CACHE, key = "#p0+'.'+#p1", unless = "#result==null")
@Override
public Server findHttpServer(String componentId, String segmentId) {
Server serverInProperties = localPropertiesDiscovery(componentId, segmentId);
if (serverInProperties != null) {
return serverInProperties;
}
Optional customWrapper = getCustom(componentId, segmentId);
if (customDiscoveryResult(customWrapper)) {
return new Server(customWrapper.get().getHost(), customWrapper.get().getPort(), customWrapper.get().getContextPath());
}
ApiResponse result;
String portName = getHttpPortName(customWrapper);
try {
result = serviceDirectoryClient.getServiceInfo(componentId, segmentId);
} catch (HttpServerErrorException e) {
throw new ServerNotFoundException("寻址" + componentId + "." + segmentId + "时服务目录发生内部错误,错误消息:"
+ e.getMessage() + ",HTTP BODY为" + e.getResponseBodyAsString());
}
ServiceInfoDto serviceInfoDto = result.getValidatedData(ServerNotFoundException.class,
"寻址" + componentId + "." + segmentId + "时服务目录发生错误");
if (serviceInfoDto == null) {
throw new ServerNotFoundException("未查询到" + componentId + "." + segmentId + "服务地址,请确认组件标识、服务标识是否正确以及相应组件是否已安装");
}
Optional address = serviceInfoDto.getAddress().stream()
.filter(addressInfo -> portName.equals(addressInfo.getKey())).findAny();
if (!address.isPresent()) {
throw new ServerNotFoundException("寻址" + componentId + "." + segmentId + "失败,无可用HTTP端口地址");
}
return new Server(address.get().getIp(), address.get().getPort(), serviceInfoDto.getContext());
}
private Optional getCustom(String componentId, String segmentId) {
return hikHttpDiscoveryProperties.getCustoms().stream().filter(cp -> (componentId + "." + segmentId).equals(cp.getHostname()) || (componentId + "-" + segmentId).equals(cp.getHostname())).findAny();
}
private boolean customDiscoveryResult(Optional customWrapper) {
if (customWrapper.isPresent()) {
HikHttpDiscoveryProperties.Custom custom = customWrapper.get();
if (StringUtils.isNotBlank(custom.getHost()) && custom.getPort() != null) {
return true;
} else {
return false;
}
} else {
return false;
}
}
private String getHttpPortName(Optional custom) {
if (custom.isPresent()) {
return custom.get().getPortName();
} else {
return BicConstants.KEY_WEB_PORT;
}
}
/**
* 直接从组件配置文件中寻址到核心服务
*
* @param componentId
* @param segmentId
* @return
*/
private Server localPropertiesDiscovery(String componentId, String segmentId) {
if ("bic".equals(componentId) && componentId.equals(segmentId)) {
return bicServer;
}
if ("bic".equals(componentId) && "cas".equals(segmentId)) {
return casServer;
}
if ("bic".equals(componentId) && "serviceDirectory".equals(segmentId)) {
return serviceDirectoryServer;
}
if ("bic".equals(componentId) && "license".equals(segmentId)) {
return licenseServer;
}
return null;
}
@Override
public void receiveMsg(ServiceChangeMsgDto serviceChangeMsgDto) {
if (serviceChangeMsgDto.getData() == null) {
return;
}
serviceChangeMsgDto.getData().getIds().forEach(serviceChangeDetailDto -> {
String componentId = serviceChangeDetailDto.getComponentId();
String segmentId = serviceChangeDetailDto.getServiceType();
cacheManager.getCache(SERVICE_DISCOVERY_CACHE).evict(componentId + "." + segmentId);
});
}
}
5. 按需更改
有时候可能需要不止两个数据库,比如需要三个、四个等等,这个时候可根据模板修改db模块中的相应文件即可