线程池实战: 通过渠道接口标识异步执行对应接口

1 pom.xml

创建Springboot项目,在pom.xml中加入如下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.mlsama</groupId>
   <artifactId>springboot-oracle</artifactId>
   <version>1.0.0</version>
   <packaging>jar</packaging>

   <name>springboot-oracle</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.0.3.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <autoconfig.plugin.version>1.2</autoconfig.plugin.version>
   </properties>

   <dependencies>
      <!-- 配置WEB启动器 SpringMVC、Restful、jackson -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.mybatis.spring.boot</groupId>
         <artifactId>mybatis-spring-boot-starter</artifactId>
         <version>1.3.2</version>
      </dependency>
      <!--整合junit-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <!--aop依赖-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>

      <!--lombok约束-->
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
      </dependency>
      <!--日记-->
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>log4j-over-slf4j</artifactId>
      </dependency>
      <!--oracle-->
      <dependency>
         <groupId>com.oracle</groupId>
         <artifactId>ojdbc6</artifactId>
         <version>11.2.0.1.0</version>
      </dependency>
      <!--c3p0连接池-->
      <dependency>
         <groupId>com.mchange</groupId>
         <artifactId>c3p0</artifactId>
         <version>0.9.5.2</version>
      </dependency>
      <!-- 配置devtools开启热部署 -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-devtools</artifactId>
      </dependency>
      <!-- FreeMarker启动器 -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-freemarker</artifactId>
      </dependency>
      <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
      <dependency>
         <groupId>commons-io</groupId>
         <artifactId>commons-io</artifactId>
         <version>2.6</version>
      </dependency>
      <dependency>
         <groupId>commons-lang</groupId>
         <artifactId>commons-lang</artifactId>
         <version>2.6</version>
      </dependency>
      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>15.0</version>
      </dependency>
      <dependency>
         <groupId>commons-httpclient</groupId>
         <artifactId>commons-httpclient</artifactId>
         <version>3.1</version>
      </dependency>
      <!--ThreadFactory,ThreadPoolExecutor等-->
      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>15.0</version>
      </dependency>
      <dependency>
         <groupId>commons-net</groupId>
         <artifactId>commons-net</artifactId>
         <version>3.0.1</version>
      </dependency>
      <!--Springbatch-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-batch</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.batch</groupId>
         <artifactId>spring-batch-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-lang3</artifactId>
         <version>3.5</version>
      </dependency>
      <dependency>
         <groupId>com.h2database</groupId>
         <artifactId>h2</artifactId>
      </dependency>
   </dependencies>

   <build>
      <!--构建后项目的名称-->
      <finalName>${project.artifactId}</finalName>
      <!--构建后项目存放
      的文件夹.project.basedir:项目根目录-->
      <directory>${project.basedir}/target</directory>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
               <fork>true</fork><!-- 如果没有该项配置,devtools不会起作用,即应用不会restart -->
            </configuration>
         </plugin>
         <!-- spring Boot在编译的时候,是有默认JDK版本的,如果我们期望使用我们要的JDK版本的话,那么要配置-->
         <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <groupId>org.apache.maven.plugins</groupId>
            <configuration>
               <source>1.8</source>
               <target>1.8</target>
               <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
         </plugin>
         <!--<plugin>
            &lt;!&ndash;需要使用这个插件配合下面的resources标签&ndash;&gt;
            <artifactId>maven-resources-plugin</artifactId>
            <configuration>
               <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
            <version>2.6</version>
         </plugin>
         <plugin>
            <groupId>com.alibaba.citrus.tool</groupId>
            <artifactId>autoconfig-maven-plugin</artifactId>
            <version>${autoconfig.plugin.version}</version>
            <configuration>
               <charset>UTF-8</charset>
               <dest>${project.artifact.file}</dest>
            </configuration>
            <executions>
               <execution>
                  <phase>package</phase>
                  <goals>
                     <goal>autoconfig</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
         <plugin>
            <groupId>pl.project13.maven</groupId>
            <artifactId>git-commit-id-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
               <execution>
                  <goals>
                     <goal>revision</goal>
                  </goals>
               </execution>
            </executions>
            <configuration>
               <verbose>true</verbose>
               <dateFormat>yyyyMMddHHmmss</dateFormat>
               &lt;!&ndash; ".git"文件路径;默认值:${project.basedir}/.git; &ndash;&gt;
               <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
               &lt;!&ndash;若项目打包类型为pom,是否取消构建;默认值:true;&ndash;&gt;
               <skipPoms>false</skipPoms>
               &lt;!&ndash;是否生成"git.properties"文件;默认值:false;&ndash;&gt;
               <generateGitPropertiesFile>false</generateGitPropertiesFile>
            </configuration>
         </plugin>-->
      </plugins>
      <!-- 需要使用这个标签合配合上面的maven-resources-pluginc插件,不然ops.properties不能获取项目信息和git的信息-->
      <!-- 发现有原来有引用 ../*-persistence模块config文件下面ds 数据源配置文件的依赖 -->
      <!-- 发现有原来有引用 ../*-persistence模块config文件下面mapper xml文件的依赖 -->
      <!-- 这里要求吧上面的文件在另外的模块打入jar里面,加入dependency -->
      <!-- 不允许源文件级别的依赖,请干净地使用下面配置-->
      <resources>
         <resource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
         </resource>
      </resources>
   </build>
</project>

2 接口信息配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--初始化对象时,加载类中的init方法-->
    <bean id="serviceHander" class="com.mlsama.springbootoracle.hander.ServiceHander" init-method="init">
        <!--给类属性赋值-->
        <property name="serviceNames">
            <map>
                <!--代收-->
                <entry key="16245840" value="collection"/>
            </map>
        </property>
    </bean>
</beans>

3 初始化接口信息

   创建类com.mlsama.springbootoracle.hander.ServiceHander

@Data
@Slf4j
public class ServiceHander {
    /**
     * 接口信息与对象,必须是静态的,否则再次调用时,map为null
     */
    private static Map<String, Map<String,Object>> serviceCache = new HashMap<>(16);

    /**
     * 配置在application.xml中的接口名称
     */
    private Map<String, String> serviceNames;

    /**
     * 1.实现ApplicationContextAware接口,获取applicationContext上下文对象
     * 进而获取bean对象
     * 2.@Autowired
     */
    @Autowired
    private ApplicationContext applicationContext;

    public static ServiceHander INSTANCE = new ServiceHander();

    private ServiceHander(){}

    /**
     * 初始化接口
     */
    public void init() {
        if (serviceNames != null){
            log.info("初始化的接口信息如下:");
            for (String procCode : serviceNames.keySet()){
                if (StringUtils.isNotBlank(serviceNames.get(procCode))){
                    List<String> methods = Arrays.asList(serviceNames.get(procCode).split(","));
                    log.info("{}:{}",procCode,methods);
                    Map<String,Object> map = new HashMap<>(16);
                    for (String method : methods){
                        map.put(method,applicationContext.getBean(procCode+"_"+method));
                    }
                    serviceCache.put(procCode,map);
                }
            }
        }else {
            throw new CommonSystemServiceException(ResultCodeConstant.RESPONSE_CODE_6601,"服务没有配置");
        }
    }
    /**
     * 根据通道号和接口名称获取接口对象
     * @param procCode
     * @param method
     * @return
     */
    public Object getBean(String procCode,String method){
        if (serviceCache.containsKey(procCode) &&
                serviceCache.get(procCode).containsKey(method)){
            return serviceCache.get(procCode).get(method);
        }
        return null;
    }
}

3 初始化各渠道线程池

@Slf4j
@Service
public class ThreadPool {
    /**
     * 这个应该配在数据库,这里为了方便
     */
    private final static String PROC_CODE_THREAD_CONFIG = "16245840=5";

    private Map<String,ThreadPoolExecutor> procCodeThreadPool = new HashMap<>(16);

    /**
     * 创建bean后,初始化线程池
     */
    @PostConstruct
    public void init(){
        if (StringUtils.isNotBlank(PROC_CODE_THREAD_CONFIG)){
            String[] procCodeConfigs = PROC_CODE_THREAD_CONFIG.split(",");
            for (String procCodeConfig : procCodeConfigs){
                String[] configs = procCodeConfig.split("=");
                if (StringUtils.isNotBlank(configs[0]) && StringUtils.isNotBlank(configs[1])){
                    
                    //创建线程池
                    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                                                                0,Integer.parseInt(configs[1]),10L,
                                                                TimeUnit.SECONDS, new SynchronousQueue(),
                                                                new ThreadPoolExecutorFactoryBean(),
                                                                new ThreadPoolExecutor.AbortPolicy());
                    log.info("************threadPool="+threadPool+"******************");
                    procCodeThreadPool1.put(configs[0],threadPool);
          
                }else {
                    throw new CommonSystemServiceException(ResultCodeConstant.RESPONSE_CODE_6604,"该通道线程池没                         有配置或格式错误");
                }
            }
        }else {
            throw new CommonSystemServiceException(ResultCodeConstant.RESPONSE_CODE_6603,"线程池没有配置");
        }
    }

    /**
     * 根据项目编号获取对应的线程池
     * @param procCode 项目编号
     * @return
     */
    public ThreadPoolExecutor getThreadPool(String procCode){
        if (procCodeThreadPool != null && procCodeThreadPool.get(procCode) != null){
            return procCodeThreadPool.get(procCode);
        }
       return null;
    }
}

4 pojo

   BaseReq

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseReq {

    private String logSeq;

    private String procCode;

    private String serviceName;

    @Override
    public String toString() {
        return "logSeq='" + logSeq + '\'' +
                ", procCode='" + procCode + '\'' +
                ", serviceName='" + serviceName + '\'' +
                '}';
    }
}

CollectionReq

@Data
public class CollectionReq extends BaseReq {

    private String account;

    public CollectionReq(){}

    public CollectionReq(String logSeq, String procCode, String serviceName) {
        super(logSeq, procCode, serviceName);
    }

    @Override
    public String toString() {
        String string = super.toString();
        return "CollectionReq{" +
                "account='" + account + '\'' +","+ string;
    }
}

BaseResp

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseResp {

    private String resultCode;

    private String resultMsg;

    @Override
    public String toString() {
        return "resultCode='" + resultCode + '\'' +
                ", resultMsg='" + resultMsg + '\'' +
                '}';
    }
}

CollectionResp

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CollectionResp extends BaseResp {

    private String paySeq;

    @Override
    public String toString(){
        String string = super.toString();
        return "collectionResp{" + "paySeq=" + paySeq +","+ string;
    }
}

5 统一管理层
5.1基础类

public abstract class BaseManager<T extends BaseReq,R extends BaseResp> {

}

5.2 实现类

@Slf4j
public abstract class CollectionManager extends BaseManager<CollectionReq,CollectionResp> {
    //注入请求处理对象
    @Autowired
    private RequestHandel requestHandel;

    public void init(CollectionReq req,CollectionResp resp){
        log.info("logSeq:{},当前对象是{}通道的{}接口",req.getLogSeq(),req.getProcCode(),req.getServiceName());
    }

    public collectionResp domain(CollectionReq req,CollectionResp resp){
        //同步返回处理中
        resp.setPaySeq(req.getLogSeq());
        resp.setResultCode(ResultCodeConstant.RESPONSE_CODE_0050);
        resp.setResultMsg("交易已接受");
        //异步处理请求
        try {
            requestHandel.handel4(new RequestTask(req.getProcCode()) {
                @Override
                public void run() {
                    log.info("***************开始异步处理请求*************");
                    //进入方法的时间
                    long startTime = System.currentTimeMillis();
                    //处理核心请求
                    main(req,resp);
                    long endTime = System.currentTimeMillis();
                    log.info("collection async send to bank and deal response cost {} ms.", endTime - startTime);
                }
            });
        }catch (Exception e){
            log.info("添加到发送银行的队列失败,case:", e);
            resp.setResultCode(ResultCodeConstant.RESPONSE_CODE_6702);
            resp.setResultMsg("添加到发送银行的队列失败");
        }
        return resp;
    }

    public abstract CollectionResp main(CollectionReq req,CollectionResp resp);
}

6 服务层
6.1 API

      基础接口

public interface BaseService<T extends BaseReq,R extends BaseResp> {

    R exeute(T req);
}

渠道接口

public interface CollectionService extends BaseService<CollectionReq,CollectionResp> {
}

6.2 impl


@Service("collection")
public class Collection implements CollectionService {

    @Override
    public CollectionResp exeute(CollectionReq req) {
        //获取真正的操作对象
        CollectionManager manager = (collectionManager) ServiceManagerFactory.INSTANCE.getManager(req.getProcCode(), req.getServiceName());
        CollectionResp resp = new CollectionResp();
        manager.init(req,resp);
        manager.domain(req,resp);
        return resp;
    }
}

7 渠道接口

@Slf4j
@Service("16245840_collection")
public class SzYlcollectionManager extends CollectionManager {

    @Override
    public collectionResp main(CollectionReq req,CollectionResp resp) {
        log.info("1201接口调用成功.");
        resp.setPaySeq(req.getLogSeq());
        resp.setResultCode("0000");
        resp.setResultMsg("成功");
        System.out.println(resp.toString());
        return resp;
    }
}

8 controller

@Controller
public class CollectionController {
    @Autowired
    private Collection collection;

    // http://localhost:8888/collection?procCode=16245840&serviceName=collection
    @GetMapping("/collection")
    @ResponseBody
    public String collection(@RequestParam("procCode")String procCode,@RequestParam("serviceName")String serviceName){
        CollectionReq req = new CollectionReq(BaseUtil.getLogSeq(),procCode,serviceName);
        return collection.exeute(req).toString();
    }
}

9 访问

http://localhost:8888/collection?procCode=16245840&serviceName=collection

猜你喜欢

转载自blog.csdn.net/mlsama/article/details/83652833