1. 设置数据库属性
包含:数据库名称、用户名、明码
在business下创立dto文件夹,自定义SegmentInfo.java,继承AmqServer
package com.hikvision.isc.module.business.dto;import com.hikvision.starfish.discovery.AmqServer;import lombok.Data;@Datapublic class SegmentInfo extends AmqServer { //数据库名称 private String dbname; //用户名 private String dbusername; //明码 private String dbpassword;}
2. 配置文件中配置数据库信息
以本地数据库和ibuilding数据库为例,在配置文件中配置两个数据库的信息
#多数据库切换——数据库配置#本地数据库信息localDburl=jdbc:postgresql://10.196.1.45:7092/sscvhb_sscvhbdblocalUserName=sscvhb_sscvhbdb_userlocalingPwd=StgR23C3#ibuilding数据库信息ibuildDburl=jdbc:postgresql://10.196.1.45:7092/ibuilding_ibuildingdbibuildingUserName=ibuilding_ibuildingdb_useribuildingPwd=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<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DBTypeEnum.db1.getValue(), db1); targetDataSources.put(DBTypeEnum.db2.getValue(), db2); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(db2); // 程序默认数据源,这个要依据程序调用数据源频次,常常把常调用的数据源作为默认 return dynamicDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2())); MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Mapper.xml")); //PerformanceInterceptor(),OptimisticLockerInterceptor() //增加分页性能 sqlSessionFactory.setPlugins(new Interceptor[]{ paginationInterceptor() });// sqlSessionFactory.setGlobalConfig(globalConfiguration()); //正文掉全局配置,因为在xml中读取就是全局配置 return sqlSessionFactory.getObject(); }}
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<ServiceInfoDto> 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<HikHttpDiscoveryProperties.Custom> customWrapper = getCustom(componentId, segmentId); if (customDiscoveryResult(customWrapper)) { return new Server(customWrapper.get().getHost(), customWrapper.get().getPort(), customWrapper.get().getContextPath()); } ApiResponse<ServiceInfoDto> 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<ServiceAddressInfoDto> 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<HikHttpDiscoveryProperties.Custom> 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<HikHttpDiscoveryProperties.Custom> 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<HikHttpDiscoveryProperties.Custom> 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模块中的相应文件即可