从零开始的数据访问层:统一的数据源

数据源的初始化

在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。这和我们要求找到一个数据源来抽象所有数据源,按照程序需要访问十分契合。
因为是一个抽象类,需要实现下面方法

    @Override
    protected Object determineCurrentLookupKey() {
        return MultiDataSourcesSwitcher.getDataSourceType();
    }

由使用者引入我们的配置文件,从而产生MultiDataSources这个类的bean。

    public MultiDataSources() {
        try {
            initializeDataSources();
        } catch (Exception e) {
            throw new IllegalStateException("datasource initialize error..", e);
        }
    }

    private void initializeDataSources() throws SQLException, IllegalAccessException {
        for (String dbtype : dataSourceNames) {//dataSourceNames是本工程所有需要支持的数据源
            DruidDataSource dataSource = this.dataSourceAssembler(dbtype);
            dataSources.put(dbtype, dataSource);
            targetDataSources.put(dbtype, dataSource);
        }
        defaultDBType = dataSourceList.getProperty("DefaultDataSource", null);
        this.setDefaultTargetDataSource(targetDataSources.get(defaultDBType));
        this.setTargetDataSources(targetDataSources);
    }


    private DruidDataSource dataSourceAssembler(String dbtype) throws IllegalAccessException, SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        String namespace = config.getProperty(dbtype, null);
        namespaceDataSource.put(namespace, dbtype);
        Config ds = ConfigService.getConfig(namespace);
        //处理用户名密码信息
        dataSource.setFilters("com.umetrip.dal.druid.DataSourceConfigFilter");
        // 处理了slowsqlmillis设置,首次设置时使用
        ArrayList<Filter> statFilters = new ArrayList<>();
        statFilters.add(getDruidStatFilterProxy(ds));
        dataSource.setProxyFilters(statFilters);

        Properties connectProperties = new Properties();
        connectProperties.setProperty("config.decrypt", "true");
        connectProperties.setProperty("dbtype", dbtype);
        connectProperties.setProperty("config.name", configPassword.getProperty(dbtype, null));
        dataSource.setConnectProperties(connectProperties);

        for(String propertyName : ds.getPropertyNames()) {
            if("username".equals(propertyName) || "password".equals(propertyName) || "slowsqlmillis".equals(propertyName)) continue;
            dataSourceAssemblerHelper(dataSource, propertyName, ds.getProperty(propertyName, null));
        }
        //注册动态监听配置变化的Listener
        ds.addChangeListener(new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                updateDataSource(changeEvent);
            }
        });
        return dataSource;
    }

    //根据设置注入属性
    private void dataSourceAssemblerHelper(DruidDataSource dataSource, String propertyName, String propertyVal) {
        try {
            //处理slowsqlmillis属性reload逻辑。方法是把上次注册的filter取出来删掉,重新建立新设置的filter载入
            if (propertyName.equalsIgnoreCase("slowsqlmillis")) {
                try {
                    List<Filter> proxyFilters = dataSource.getProxyFilters();
                    List<Filter> newFilters = new ArrayList<>();
                    for (Filter f : proxyFilters) {
                        if (AopUtils.isAopProxy(f)) {
                            StatFilter statFilter = new StatFilter();
                            statFilter.setSlowSqlMillis(Long.valueOf(propertyVal));
                            AspectJProxyFactory factory = new AspectJProxyFactory(statFilter);
                            factory.addAspect(UmeCatStatFilterAspect.class);
                            newFilters.add((Filter)factory.getProxy());
                        } else {
                            newFilters.add(f);
                        }
                    }
                    dataSource.clearFilters();
                    dataSource.setProxyFilters(newFilters);
                    return;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return;
            }
            if("username".equals(propertyName) || "password".equals(propertyName)) {
                return;
            }
            Field field = dataSource.getClass().getSuperclass().getDeclaredField(propertyName);
            field.setAccessible(true);
            switch (TypeName.valueOf(field.getType().getSimpleName().toUpperCase())) {
                case INT:
                case INTEGER:
                    field.set(dataSource, Integer.valueOf(propertyVal));
                    break;
                case LONG:
                    field.set(dataSource, Long.valueOf(propertyVal));
                    break;
                case BOOLEAN:
                    field.set(dataSource, Boolean.valueOf(propertyVal));
                    break;
                case STRING:
                    field.set(dataSource, propertyVal);
                    break;
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
        }
    }

    //更新设置
    private void updateDataSource(ConfigChangeEvent changeEvent) {
        DruidDataSource updateDS = (DruidDataSource)dataSources.get(namespaceDataSource.get(changeEvent.getNamespace()));
        for (String key : changeEvent.changedKeys()) {
            ConfigChange change = changeEvent.getChange(key);
            dataSourceAssemblerHelper(updateDS, change.getPropertyName(), change.getNewValue());
        }
    }

数据源的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值