Bladeren bron

优化动态数据源

zhouhao 6 jaren geleden
bovenliggende
commit
9f0aa5c714
21 gewijzigde bestanden met toevoegingen van 397 en 193 verwijderingen
  1. 3 3
      hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DynamicDataSourceProxy.java
  2. 1 4
      hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/AbstractDynamicDataSourceService.java
  3. 0 3
      hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/DataSourceCache.java
  4. 8 0
      hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/strategy/AnnotationDataSourceSwitchStrategyMatcher.java
  5. 3 3
      hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcher.java
  6. 0 1
      hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultTableSwitcher.java
  7. 16 0
      hsweb-datasource/hsweb-datasource-api/src/test/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcherTest.java
  8. 1 0
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-api/src/main/java/org/hswebframework/web/entity/datasource/DataSourceConfigEntity.java
  9. 18 27
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InServiceJtaDataSourceRepository.java
  10. 33 0
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InDBDynamicDataSourceConfig.java
  11. 134 0
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InDBDynamicDataSourceService.java
  12. 85 0
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InDBJtaDynamicDataSourceService.java
  13. 8 8
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/datasource/DataSourceConfigMapper.xml
  14. 0 104
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/test/java/org/hswebframework/web/service/datasource/simple/InServiceJtaDataSourceRepositoryTests.java
  15. 11 4
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/pom.xml
  16. 0 31
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/src/main/java/org/hswebframework/web/datasource/starter/DataSourceAutoConfiguration.java
  17. 68 0
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/src/main/java/org/hswebframework/web/datasource/starter/InDBDynamicDataSourceAutoConfiguration.java
  18. 1 1
      hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/src/main/resources/META-INF/spring.factories
  19. 2 1
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/dimension/DimensionContext.java
  20. 5 2
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/dimension/parser/ScriptCandiateDimensionParserStrategy.java
  21. 0 1
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/imp/ProcessConfigurationServiceImpl.java

+ 3 - 3
hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DynamicDataSourceProxy.java

@@ -1,5 +1,7 @@
 package org.hswebframework.web.datasource;
 
+import lombok.SneakyThrows;
+
 import javax.sql.DataSource;
 import java.io.PrintWriter;
 import java.sql.Connection;
@@ -47,6 +49,7 @@ public class DynamicDataSourceProxy implements DynamicDataSource {
     }
 
     @Override
+    @SneakyThrows
     public DatabaseType getType() {
         if (databaseType == null) {
             lock.lock();
@@ -57,13 +60,10 @@ public class DynamicDataSourceProxy implements DynamicDataSource {
                 try (Connection connection = proxy.getConnection()) {
                     databaseType = DatabaseType.fromJdbcUrl(connection.getMetaData().getURL());
                 }
-            } catch (SQLException e) {
-                throw new UnsupportedOperationException(e);
             } finally {
                 lock.unlock();
             }
         }
-
         return databaseType;
     }
 

+ 1 - 4
hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/AbstractDynamicDataSourceService.java

@@ -10,10 +10,8 @@ import org.hswebframework.web.datasource.exception.DataSourceNotFoundException;
 import javax.annotation.PreDestroy;
 import javax.sql.DataSource;
 import java.sql.SQLException;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
 
 /**
  * @author zhouhao
@@ -45,12 +43,11 @@ public abstract class AbstractDynamicDataSourceService<C extends DynamicDataSour
 
     @Override
     public DynamicDataSource getDataSource(String dataSourceId) {
-        DataSourceCache cache = dataSourceStore.get(dataSourceId);
         C config = repository.findById(dataSourceId);
         if (config == null) {
             throw new DataSourceNotFoundException(dataSourceId, "数据源" + dataSourceId + "不存在");
-
         }
+        DataSourceCache cache = dataSourceStore.get(dataSourceId);
         if (cache == null) {
             cache = createCache(config);
             dataSourceStore.put(dataSourceId, cache);

+ 0 - 3
hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/DataSourceCache.java

@@ -40,9 +40,6 @@ public class DataSourceCache {
                 initLatch = null;
             }
         }
-        if (closed) {
-            throw new DataSourceClosedException(dataSource.getId());
-        }
         return dataSource;
     }
 

+ 8 - 0
hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/strategy/AnnotationDataSourceSwitchStrategyMatcher.java

@@ -5,14 +5,22 @@ import org.hswebframework.web.datasource.annotation.UseDataSource;
 import org.hswebframework.web.datasource.annotation.UseDefaultDataSource;
 
 import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * @author zhouhao
  * @since 3.0.0-RC
  */
 public class AnnotationDataSourceSwitchStrategyMatcher extends CachedDataSourceSwitchStrategyMatcher {
+    static final Set<String> ignoreMethod = new HashSet<>(Arrays.asList("toString", "clone", "equals"));
+
     @Override
     public Strategy createStrategyIfMatch(Class target, Method method) {
+        if (ignoreMethod.contains(method.getName())) {
+            return null;
+        }
         UseDataSource useDataSource = AopUtils.findAnnotation(target, method, UseDataSource.class);
         UseDefaultDataSource useDefaultDataSource = AopUtils.findAnnotation(target, method, UseDefaultDataSource.class);
 

+ 3 - 3
hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcher.java

@@ -28,7 +28,7 @@ public class DefaultDataSourceSwitcher implements DataSourceSwitcher {
     @Override
     public void useLast() {
         // 没有上一次了
-        if (getUsedHistoryQueue().size() == 0) {
+        if (getUsedHistoryQueue().isEmpty()) {
             return;
         }
         //移除队尾,则当前的队尾则为上一次的数据源
@@ -38,7 +38,7 @@ public class DefaultDataSourceSwitcher implements DataSourceSwitcher {
             if (null != current) {
                 logger.debug("try use last data source : {}", currentDataSourceId());
             } else {
-                logger.debug("try use default data source");
+                logger.debug("try use last default data source");
             }
         }
     }
@@ -62,7 +62,7 @@ public class DefaultDataSourceSwitcher implements DataSourceSwitcher {
 
     @Override
     public String currentDataSourceId() {
-        if (getUsedHistoryQueue().size() == 0) {
+        if (getUsedHistoryQueue().isEmpty()) {
             return null;
         }
 

+ 0 - 1
hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultTableSwitcher.java

@@ -1,6 +1,5 @@
 package org.hswebframework.web.datasource.switcher;
 
-import lombok.extern.slf4j.Slf4j;
 import org.hswebframework.web.ThreadLocalUtils;
 
 import java.util.HashMap;

+ 16 - 0
hsweb-datasource/hsweb-datasource-api/src/test/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcherTest.java

@@ -41,4 +41,20 @@ public class DefaultDataSourceSwitcherTest {
 
     }
 
+    @Test
+    public void testChangeSwitcher2() {
+
+        switcher.use("test");//切换为test
+        assertEquals(switcher.currentDataSourceId(), "test");
+        switcher.useDefault();
+        switcher.useDefault();
+        switcher.useDefault();
+        assertTrue(switcher.currentDataSourceId() == null);
+        switcher.useLast();
+        switcher.useLast();
+        switcher.useLast();
+        assertEquals(switcher.currentDataSourceId(), "test");
+    }
+
+
 }

+ 1 - 0
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-api/src/main/java/org/hswebframework/web/entity/datasource/DataSourceConfigEntity.java

@@ -2,6 +2,7 @@ package org.hswebframework.web.entity.datasource;
 
 import org.hswebframework.web.commons.entity.GenericEntity;
 
+
 /**
  * 数据源配置 实体
  *

+ 18 - 27
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InServiceJtaDataSourceRepository.java

@@ -1,38 +1,39 @@
 package org.hswebframework.web.service.datasource.simple;
 
-import com.alibaba.fastjson.JSON;
+import org.hswebframework.web.bean.FastBeanCopier;
 import org.hswebframework.web.commons.entity.factory.EntityFactory;
-import org.hswebframework.web.datasource.jta.AtomikosDataSourceConfig;
-import org.hswebframework.web.datasource.jta.JtaDataSourceRepository;
+import org.hswebframework.web.datasource.annotation.UseDefaultDataSource;
+import org.hswebframework.web.datasource.config.DynamicDataSourceConfigRepository;
 import org.hswebframework.web.entity.datasource.DataSourceConfigEntity;
 import org.hswebframework.web.service.datasource.DataSourceConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 import java.util.stream.Collectors;
 
 /**
  * @author zhouhao
  * @since 1.0
  */
-public class InServiceJtaDataSourceRepository implements JtaDataSourceRepository {
+@Transactional(propagation = Propagation.NOT_SUPPORTED)
+public class InDBDataSourceRepository implements DynamicDataSourceConfigRepository<InDBDynamicDataSourceConfig> {
     private DataSourceConfigService dataSourceConfigService;
 
-    private EntityFactory entityFactory;
+    public InDBDataSourceRepository(DataSourceConfigService dataSourceConfigService) {
+        this.dataSourceConfigService = dataSourceConfigService;
+    }
 
-    @Autowired
-    public void setEntityFactory(EntityFactory entityFactory) {
-        this.entityFactory = entityFactory;
+    public InDBDataSourceRepository() {
     }
 
-    @Autowired
     public void setDataSourceConfigService(DataSourceConfigService dataSourceConfigService) {
         this.dataSourceConfigService = dataSourceConfigService;
     }
 
-    protected AtomikosDataSourceConfig convert(DataSourceConfigEntity entity) {
+    protected InDBDynamicDataSourceConfig convert(DataSourceConfigEntity entity) {
         if (null == entity) {
             return null;
         }
@@ -40,43 +41,33 @@ public class InServiceJtaDataSourceRepository implements JtaDataSourceRepository
         if (config == null) {
             return null;
         }
-        Object xaProperties = config.get("xaProperties");
-        Properties properties = new Properties();
-
-        if (xaProperties instanceof String) {
-            xaProperties = JSON.parseObject(((String) xaProperties));
-        }
-        if (xaProperties instanceof Map) {
-            properties.putAll(((Map) xaProperties));
-        }
-        config.remove("xaProperties");
-        AtomikosDataSourceConfig target = entityFactory.copyProperties(config, new AtomikosDataSourceConfig());
+        InDBDynamicDataSourceConfig target = FastBeanCopier.copy(config, InDBDynamicDataSourceConfig::new);
         target.setId(entity.getId());
         target.setName(entity.getName());
         target.setDescribe(entity.getDescribe());
-        target.setXaProperties(properties);
+        target.setProperties(config);
         return target;
     }
 
     @Override
-    public List<AtomikosDataSourceConfig> findAll() {
+    public List<InDBDynamicDataSourceConfig> findAll() {
         return dataSourceConfigService.select().stream()
                 .map(this::convert)
                 .collect(Collectors.toList());
     }
 
     @Override
-    public AtomikosDataSourceConfig findById(String dataSourceId) {
+    public InDBDynamicDataSourceConfig findById(String dataSourceId) {
         return convert(dataSourceConfigService.selectByPk(dataSourceId));
     }
 
     @Override
-    public AtomikosDataSourceConfig add(AtomikosDataSourceConfig config) {
+    public InDBDynamicDataSourceConfig add(InDBDynamicDataSourceConfig config) {
         throw new UnsupportedOperationException("add AtomikosDataSourceConfig not support");
     }
 
     @Override
-    public AtomikosDataSourceConfig remove(String dataSourceId) {
+    public InDBDynamicDataSourceConfig remove(String dataSourceId) {
         throw new UnsupportedOperationException("remove datasource not support");
     }
 }

+ 33 - 0
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InDBDynamicDataSourceConfig.java

@@ -0,0 +1,33 @@
+package org.hswebframework.web.service.datasource.simple;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.web.datasource.config.DynamicDataSourceConfig;
+
+import java.util.Map;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Getter
+@Setter
+public class InDBDynamicDataSourceConfig extends DynamicDataSourceConfig {
+
+    private static final long serialVersionUID = 89025460456111917L;
+
+    private Map<String, Object> properties;
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof InDBDynamicDataSourceConfig) {
+            return o.hashCode() == hashCode();
+        }
+        return super.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+        return properties == null ? 0 : properties.hashCode();
+    }
+}

+ 134 - 0
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InDBDynamicDataSourceService.java

@@ -0,0 +1,134 @@
+package org.hswebframework.web.service.datasource.simple;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.hswebframework.web.BusinessException;
+import org.hswebframework.web.bean.FastBeanCopier;
+import org.hswebframework.web.datasource.DataSourceHolder;
+import org.hswebframework.web.datasource.DynamicDataSource;
+import org.hswebframework.web.datasource.DynamicDataSourceProxy;
+import org.hswebframework.web.datasource.annotation.UseDefaultDataSource;
+import org.hswebframework.web.datasource.config.DynamicDataSourceConfigRepository;
+import org.hswebframework.web.datasource.service.AbstractDynamicDataSourceService;
+import org.hswebframework.web.datasource.service.DataSourceCache;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ReflectionUtils;
+
+import javax.sql.DataSource;
+import java.io.Closeable;
+import java.lang.reflect.Method;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @author zhouhao
+ * @since 1.0.0
+ */
+@Slf4j
+@Transactional(propagation = Propagation.NOT_SUPPORTED)
+public class InDBDynamicDataSourceService extends AbstractDynamicDataSourceService<InDBDynamicDataSourceConfig> {
+
+    public InDBDynamicDataSourceService(DynamicDataSourceConfigRepository<InDBDynamicDataSourceConfig> repository,
+                                        DynamicDataSource defaultDataSource) {
+
+        super(repository, defaultDataSource);
+    }
+
+    ExecutorService executorService = Executors.newFixedThreadPool(2);
+
+    @Override
+    public DynamicDataSource getDataSource(String dataSourceId) {
+        try {
+            DataSourceHolder.switcher().useDefault();
+            return super.getDataSource(dataSourceId);
+        } finally {
+            DataSourceHolder.switcher().useLast();
+        }
+    }
+
+    protected void closeDataSource(DataSource dataSource) {
+        if (null == dataSource) {
+            return;
+        }
+        try {
+            if (dataSource instanceof Closeable) {
+                ((Closeable) dataSource).close();
+            } else {
+                Method closeMethod = ReflectionUtils.findMethod(dataSource.getClass(), "close");
+                if (closeMethod != null) {
+                    ReflectionUtils.invokeMethod(closeMethod, dataSource);
+                }
+            }
+        } catch (Exception e) {
+            log.warn("关闭数据源[{}]失败", dataSource, e);
+        }
+    }
+
+    @Override
+    @SneakyThrows
+    protected DataSourceCache createCache(InDBDynamicDataSourceConfig config) {
+        if (config.getProperties() == null) {
+            throw new UnsupportedOperationException("配置不存在");
+        }
+
+        CountDownLatch initCountDownLatch = new CountDownLatch(1);
+        DataSourceProperties dataSourceProperties = new DataSourceProperties();
+        FastBeanCopier.copy(config.getProperties(), dataSourceProperties);
+        AtomicReference<DataSource> dataSourceReference = new AtomicReference<>();
+        AtomicBoolean closed = new AtomicBoolean();
+        AtomicBoolean success = new AtomicBoolean();
+        int initTimeOut = Integer.parseInt(String.valueOf(config.getProperties().getOrDefault("InitTimeout", "20")));
+
+        executorService.submit(() -> {
+            try {
+                DataSource dataSource = dataSourceProperties
+                        .initializeDataSourceBuilder()
+                        .build();
+                dataSourceReference.set(dataSource);
+                FastBeanCopier.copy(config.getProperties(), dataSource);
+                //test datasource init success
+                dataSource.getConnection().close();
+                if (closed.get()) {
+                    closeDataSource(dataSource);
+                } else {
+                    success.set(true);
+                }
+            } catch (Exception e) {
+                log.warn("初始化数据源[{}]失败", config.getId(), e);
+            } finally {
+                initCountDownLatch.countDown();
+            }
+        });
+
+        try {
+            @SuppressWarnings("all")
+            boolean waitSuccess = initCountDownLatch.await(initTimeOut, TimeUnit.SECONDS);
+        } catch (@SuppressWarnings("all") InterruptedException ignore) {
+            //ignore
+        }
+        if (!success.get()) {
+            closed.set(true);
+            closeDataSource(dataSourceReference.get());
+            throw new BusinessException("初始化数据源[" + config.getId() + "]失败");
+        }
+        return new DataSourceCache(
+                config.getProperties().hashCode(),
+                new DynamicDataSourceProxy(config.getId(), dataSourceReference.get()),
+                initCountDownLatch, config) {
+            @Override
+            public void closeDataSource() {
+                super.closeDataSource();
+                closed.set(true);
+                InDBDynamicDataSourceService.this.closeDataSource(getDataSource().getNative());
+            }
+        };
+
+    }
+}

+ 85 - 0
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/java/org/hswebframework/web/service/datasource/simple/InDBJtaDynamicDataSourceService.java

@@ -0,0 +1,85 @@
+package org.hswebframework.web.service.datasource.simple;
+
+import com.alibaba.fastjson.JSON;
+import org.hswebframework.web.bean.FastBeanCopier;
+import org.hswebframework.web.datasource.DynamicDataSource;
+import org.hswebframework.web.datasource.config.DynamicDataSourceConfigRepository;
+import org.hswebframework.web.datasource.jta.AtomikosDataSourceConfig;
+import org.hswebframework.web.datasource.jta.JtaDynamicDataSourceService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+/**
+ * @author zhouhao
+ * @since 1.0.0
+ */
+public class InDBJtaDynamicDataSourceService extends JtaDynamicDataSourceService {
+
+    static AtomikosDataSourceConfig convert(InDBDynamicDataSourceConfig entity) {
+        if (null == entity) {
+            return null;
+        }
+        Map<String, Object> config = entity.getProperties();
+        if (config == null) {
+            return null;
+        }
+        Object xaProperties = config.get("xaProperties");
+        Properties properties = new Properties();
+
+        if (xaProperties instanceof String) {
+            xaProperties = JSON.parseObject(((String) xaProperties));
+        }
+        if (xaProperties instanceof Map) {
+            properties.putAll(((Map) xaProperties));
+        }
+        config.remove("xaProperties");
+        AtomikosDataSourceConfig target = FastBeanCopier.copy(config, new AtomikosDataSourceConfig() {
+            private static final long serialVersionUID = -2704649332301331803L;
+
+            @Override
+            public int hashCode() {
+                return entity.hashCode();
+            }
+        });
+        target.setId(entity.getId());
+        target.setName(entity.getName());
+        target.setDescribe(entity.getDescribe());
+        target.setXaProperties(properties);
+
+        return target;
+    }
+
+    public InDBJtaDynamicDataSourceService(DynamicDataSourceConfigRepository<InDBDynamicDataSourceConfig> repository,
+                                           DynamicDataSource defaultDataSource) {
+
+        super(new DynamicDataSourceConfigRepository<AtomikosDataSourceConfig>() {
+            @Override
+            public List<AtomikosDataSourceConfig> findAll() {
+                return repository.findAll().stream()
+                        .map(InDBJtaDynamicDataSourceService::convert)
+                        .filter(Objects::nonNull)
+                        .collect(Collectors.toList());
+            }
+
+            @Override
+            public AtomikosDataSourceConfig findById(String dataSourceId) {
+                return convert(repository.findById(dataSourceId));
+            }
+
+            @Override
+            public AtomikosDataSourceConfig add(AtomikosDataSourceConfig config) {
+                throw new UnsupportedOperationException("不支持添加数据源配置");
+            }
+
+            @Override
+            public AtomikosDataSourceConfig remove(String dataSourceId) {
+                throw new UnsupportedOperationException("不支持删除数据源配置");
+            }
+        }, defaultDataSource);
+    }
+
+}

+ 8 - 8
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/main/resources/org/hswebframework/web/dao/mybatis/mappers/datasource/DataSourceConfigMapper.xml

@@ -4,12 +4,12 @@
         "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.hswebframework.web.dao.datasource.DataSourceConfigDao">
     <resultMap id="DataSourceConfigResultMap" type="org.hswebframework.web.entity.datasource.DataSourceConfigEntity">
-              <id property="id" column="u_id" javaType="string" jdbcType="VARCHAR"/>
-            <result property="name" column="name" javaType="String" jdbcType="VARCHAR"/>
-            <result property="enabled" column="enabled" javaType="Long" jdbcType="DECIMAL"/>
-            <result property="createDate" column="create_date" javaType="java.util.Date" jdbcType="DATE"/>
-            <result property="properties" column="properties" javaType="String" jdbcType="CLOB"/>
-            <result property="describe" column="describe" javaType="String" jdbcType="VARCHAR"/>
+        <id property="id" column="u_id" javaType="string" jdbcType="VARCHAR"/>
+        <result property="name" column="name" javaType="String" jdbcType="VARCHAR"/>
+        <result property="enabled" column="enabled" javaType="Long" jdbcType="DECIMAL"/>
+        <result property="createDate" column="create_date" javaType="java.util.Date" jdbcType="DATE"/>
+        <result property="properties" column="properties" javaType="java.util.Map" jdbcType="CLOB"/>
+        <result property="describe" column="describe" javaType="String" jdbcType="VARCHAR"/>
     </resultMap>
 
     <!--用于动态生成sql所需的配置-->
@@ -17,8 +17,8 @@
         <bind name="resultMapId" value="'DataSourceConfigResultMap'"/>
         <bind name="tableName" value="'s_datasource_conf'"/>
     </sql>
-  
-    <insert id="insert" parameterType="org.hswebframework.web.entity.datasource.DataSourceConfigEntity" >
+
+    <insert id="insert" parameterType="org.hswebframework.web.entity.datasource.DataSourceConfigEntity">
         <include refid="config"/>
         <include refid="BasicMapper.buildInsertSql"/>
     </insert>

+ 0 - 104
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-local/src/test/java/org/hswebframework/web/service/datasource/simple/InServiceJtaDataSourceRepositoryTests.java

@@ -1,104 +0,0 @@
-package org.hswebframework.web.service.datasource.simple;
-
-import org.hswebframework.web.commons.entity.factory.MapperEntityFactory;
-import org.hswebframework.web.datasource.jta.AtomikosDataSourceConfig;
-import org.hswebframework.web.entity.datasource.DataSourceConfigEntity;
-import org.hswebframework.web.entity.datasource.SimpleDataSourceConfigEntity;
-import org.hswebframework.web.service.datasource.DataSourceConfigService;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import java.util.*;
-
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
-
-/**
- * @author zhouhao
- * @since 3.0
- */
-@RunWith(MockitoJUnitRunner.class)
-public class InServiceJtaDataSourceRepositoryTests {
-
-    @InjectMocks
-    InServiceJtaDataSourceRepository repository = new InServiceJtaDataSourceRepository();
-
-    @Mock
-    DataSourceConfigService dataSourceConfigService;
-
-    AtomikosDataSourceConfig config = new AtomikosDataSourceConfig();
-
-    {
-        repository.setEntityFactory(new MapperEntityFactory());
-        config.setMinPoolSize(12);
-        config.setMaxPoolSize(999);
-        config.setId("test-ds");
-        config.setName("测试");
-        config.setDescribe("测试");
-        config.setXaDataSourceClassName("com.alibaba.druid.DruidDataSource");
-        Properties properties = new Properties();
-        properties.setProperty("url", "jdbc:h2:mem:core;DB_CLOSE_ON_EXIT=FALSE");
-        properties.setProperty("username", "sa");
-        properties.setProperty("password", "");
-        config.setXaProperties(properties);
-    }
-
-    @Before
-    public void init() {
-        DataSourceConfigEntity configEntity = SimpleDataSourceConfigEntity
-                .builder()
-                .createDate(new Date())
-                .describe("测试")
-                .enabled(1L)
-                .name("测试")
-                .build();
-        Map<String, Object> properties = new HashMap<>();
-        properties.put("minPoolSize", config.getMinPoolSize() + "");
-        properties.put("maxPoolSize", config.getMaxPoolSize() + "");
-        properties.put("borrowConnectionTimeout", config.getBorrowConnectionTimeout());
-        properties.put("reapTimeout", config.getReapTimeout());
-        properties.put("initTimeout", config.getInitTimeout());
-        properties.put("xaDataSourceClassName", config.getXaDataSourceClassName());
-        properties.put("xaProperties", config.getXaProperties());
-        configEntity.setProperties(properties);
-        configEntity.setId("test-ds");
-        when(dataSourceConfigService.selectByPk("test-ds")).thenReturn(configEntity);
-        when(dataSourceConfigService.select()).thenReturn(new ArrayList<>(Arrays.asList(configEntity)));
-    }
-
-    @Test
-    public void testQuery() {
-        AtomikosDataSourceConfig dataSourceConfig = repository.findById("test-ds");
-        assertNotNull(dataSourceConfig);
-        assertEquals(dataSourceConfig.hashCode(), config.hashCode());
-    }
-
-    @Test
-    public void testQuery2() {
-        AtomikosDataSourceConfig dataSourceConfig = repository.findAll().get(0);
-        assertNotNull(dataSourceConfig);
-        assertEquals(dataSourceConfig.hashCode(), config.hashCode());
-    }
-
-    @Test
-    public void testUD() {
-        try {
-            repository.remove("test-ds");
-            assertTrue(false);
-        } catch (UnsupportedOperationException e) {
-
-        }
-        try {
-            repository.add(config);
-            assertTrue(false);
-        } catch (UnsupportedOperationException e) {
-
-        }
-    }
-
-}

+ 11 - 4
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/pom.xml

@@ -29,19 +29,26 @@
             <artifactId>hsweb-system-datasource-local</artifactId>
             <version>${project.version}</version>
         </dependency>
-      
+
         <dependency>
             <groupId>org.hswebframework.web</groupId>
             <artifactId>hsweb-system-datasource-web</artifactId>
             <version>${project.version}</version>
         </dependency>
-      
+
+        <dependency>
+            <groupId>org.hswebframework.web</groupId>
+            <artifactId>hsweb-datasource-jta</artifactId>
+            <version>${project.version}</version>
+            <optional>true</optional>
+        </dependency>
+
         <dependency>
             <groupId>com.h2database</groupId>
             <artifactId>h2</artifactId>
             <scope>test</scope>
         </dependency>
-      
+
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid</artifactId>
@@ -69,6 +76,6 @@
             <version>2.5</version>
             <scope>test</scope>
         </dependency>
-      
+
     </dependencies>
 </project>

+ 0 - 31
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/src/main/java/org/hswebframework/web/datasource/starter/DataSourceAutoConfiguration.java

@@ -1,31 +0,0 @@
-/*
- *  Copyright 2016 http://www.hswebframework.org
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *
- */
-
-package org.hswebframework.web.datasource.starter;
-
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * @author zhouhao
- */
-@Configuration
-@ComponentScan({"org.hswebframework.web.service.datasource.simple"
-        , "org.hswebframework.web.controller.datasource"})
-public class DataSourceAutoConfiguration {
-}

+ 68 - 0
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/src/main/java/org/hswebframework/web/datasource/starter/InDBDynamicDataSourceAutoConfiguration.java

@@ -0,0 +1,68 @@
+/*
+ *  Copyright 2016 http://www.hswebframework.org
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ */
+
+package org.hswebframework.web.datasource.starter;
+
+import org.hswebframework.web.datasource.DynamicDataSourceAutoConfiguration;
+import org.hswebframework.web.datasource.DynamicDataSourceProxy;
+import org.hswebframework.web.datasource.DynamicDataSourceService;
+import org.hswebframework.web.service.datasource.DataSourceConfigService;
+import org.hswebframework.web.service.datasource.simple.InDBDataSourceRepository;
+import org.hswebframework.web.service.datasource.simple.InDBDynamicDataSourceService;
+import org.hswebframework.web.service.datasource.simple.InDBJtaDynamicDataSourceService;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+/**
+ * @author zhouhao
+ */
+@Configuration
+@ComponentScan({"org.hswebframework.web.service.datasource.simple"
+        , "org.hswebframework.web.controller.datasource"})
+@AutoConfigureBefore(DynamicDataSourceAutoConfiguration.class)
+public class InDBDynamicDataSourceAutoConfiguration {
+
+    @Bean
+    public InDBDataSourceRepository inDBDataSourceRepository(DataSourceConfigService dataSourceConfigService) {
+        return new InDBDataSourceRepository(dataSourceConfigService);
+    }
+
+    @Bean
+    @ConditionalOnMissingClass("org.hswebframework.web.datasource.jta.JtaDynamicDataSourceService")
+    public DynamicDataSourceService inDBDynamicDataSourceService(InDBDataSourceRepository repository,
+                                                                 DataSource dataSource) {
+        return new InDBDynamicDataSourceService(repository, new DynamicDataSourceProxy("dataSource", dataSource));
+    }
+
+    @Configuration
+    @ConditionalOnClass(org.hswebframework.web.datasource.jta.JtaDynamicDataSourceService.class)
+    public static class InDBJtaDynamicDataSourceServiceAutoConfiguration {
+        @Bean
+        public DynamicDataSourceService inDBJtaDynamicDataSourceService(InDBDataSourceRepository repository,
+                                                                        DataSource dataSource) {
+            return new InDBJtaDynamicDataSourceService(repository, new DynamicDataSourceProxy("dataSource", dataSource));
+        }
+    }
+
+}

+ 1 - 1
hsweb-system/hsweb-system-datasource/hsweb-system-datasource-starter/src/main/resources/META-INF/spring.factories

@@ -1,3 +1,3 @@
 # Auto Configure
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-org.hswebframework.web.datasource.starter.DataSourceAutoConfiguration
+org.hswebframework.web.datasource.starter.InDBDynamicDataSourceAutoConfiguration

+ 2 - 1
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/dimension/DimensionContext.java

@@ -25,7 +25,8 @@ public class DimensionContext {
     private String activityId;
 
     /**
-     * 上一环节
+     * 当前环节
      */
     private TaskInfo task;
+
 }

+ 5 - 2
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/dimension/parser/ScriptCandiateDimensionParserStrategy.java

@@ -4,6 +4,7 @@ import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.hswebframework.expands.script.engine.DynamicScriptEngine;
 import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory;
+import org.hswebframework.web.Lists;
 import org.hswebframework.web.Maps;
 import org.hswebframework.web.entity.authorization.UserEntity;
 import org.hswebframework.web.entity.organizational.PersonEntity;
@@ -16,6 +17,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 import org.springframework.util.DigestUtils;
 import org.springframework.util.StringUtils;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -67,6 +69,7 @@ public class ScriptCandiateDimensionParserStrategy implements CandidateDimension
 
         Object obj = engine.execute(id, Maps.<String, Object>buildMap()
                 .put("user", creator)
+                .put("creator", creator)
                 .put("creatorId", creatorId)
                 .put("context", context)
                 .get())
@@ -82,7 +85,7 @@ public class ScriptCandiateDimensionParserStrategy implements CandidateDimension
                 } else if (target instanceof UserEntity) {
                     return ((UserEntity) target).getId();
                 } else {
-                    return ((Relation) o).getRelation();
+                    return ((Relation) o).getTarget();
                 }
             } else {
                 log.warn("不支持的关系:{}", o);
@@ -101,7 +104,7 @@ public class ScriptCandiateDimensionParserStrategy implements CandidateDimension
             if (result == null) {
                 return new java.util.ArrayList<>();
             }
-            return Collections.singletonList(result);
+            return Lists.buildList(result).get();
         }
     }
 

+ 0 - 1
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/imp/ProcessConfigurationServiceImpl.java

@@ -100,7 +100,6 @@ public class ProcessConfigurationServiceImpl implements ProcessConfigurationServ
                     context.setActivityId(activityId);
                     context.setProcessDefineId(processDefineId);
                     context.setTask(task);
-
                     CandidateDimension dimension = candidateDimensionParser
                             .parse(context, configEntity.getCandidateDimension());