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模块中的相应文件即可