# Elab-Spring 该项目用来针对一些Spring的拓展做一些统一的封装使得在使用上非常方便 这里只是大概介绍一下功能的使用。 ### 按需使用 ```java // 如果有相应的配置文件参数,需要将配置文件注入到里面来 @PropertySource(value = {"classpath:database.properties","classpath:autoConfig.properties"},encoding = "UTF-8") // 直接导入相关的配置类 @Import({SpringCommonConfig.class, DataSourceConfigBean.class, JdbcBeanConfig.class, TransactionConfigBean.class}) ``` ### 直接使用 ```java @EnableElabSpring ``` 其中该注解内有很多方法,可以根据自己的需要进行开启关闭 ------ [TOC] ## 功能介绍 ### 配置相关 #### SpringCommonConfig 基本的Spring相关的配置 封装了**ClientHttpRequestFactory**、**RestTemplate**、**PropertyPlaceholderConfigurer**等类. 有一些可变的参数可以再配置文件中指定,这里面的数据都是默认值,可以不填写 ```perl # httpClient连接数 httpClient.connect.timeOut=120000 # httpClient超时时间 httpClient.read.timeOut=120000 # 读取property配置文件的路径 spring.resources.path=classpath:*.properties ``` #### ThreadConfiguration 异步线程的相关配置,涵盖了定时线程、异步队列、并行线程等等 具体的使用方式参考: `ThreadProcessUtils` #### SwaggerConfigBean ``` #是否开启swagger swagger.enable=必填 # controller路径 swagger2.basePackage=必填 # api的标题 swagger2.title=必填 # 描述 swagger2.description=必填 # 团队服务的URL swagger2.termsOfServiceUrl=必填 # 许可证地址 swagger2.licenseUrl=必填 # 版本号 swagger2.version=必填 ``` ##### swagger 新增扫描多个包的情况 `swagger2.basePackage` : 用以","号分割 ```yaml swagger2: basePackage: com.elab.marketing.brand.service.impl,com.elab.marketing.brand.controllers title: brand description: 品牌app微服务 termsOfServiceUrl: http://www.elab-plus.com licenseUrl: http://127.0.0.1:5312/doc.html version: 1.0.0 enable: true ``` #### SpringMvcConfig 基本的SpringMVC容器相关的配置 封装了MultipartResolver等相关配置 ```perl # 文件上传大小配置 mvc.multipartResolver.MaxUploadSize=10485760 ``` #### CommonException 全局异常定义 直接注入就拥有全局异常功能 - `BusinessException` : 该异常表示业务中出现的参数不对,以及一些不会记录Log的异常会直接封装成code+msg返回给前端 #### LogResponseBodyAdvice 日志id作为结果集返回 直接注入拥有全局返回日志id的功能 #### RestTemplateUtils - 新增`IRestFallback`回调接口 - `DefaultRestFallBack` 默认的回调 : 一旦请求出现异常,则将该次请求数据记录到`mng_http_failure_data`表中 > 如果业务有特殊处理,可以实现该接口去覆盖DefaultRestFallBack类的实现。 ```sql CREATE TABLE `mng_http_failure_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `url` varchar(200) DEFAULT NULL COMMENT '请求路径', `req_method` varchar(10) DEFAULT NULL COMMENT '请求方式 GET/POST', `req_body` text COMMENT '请求参数', `res_body` text COMMENT '返回结果', `header_body` text COMMENT '请求头信息', `req_retry` int(11) DEFAULT NULL COMMENT '请求重试次数', `req_status` int(11) DEFAULT NULL COMMENT '请求状态 -1失败 1成功 ', `cat_id` varchar(50) DEFAULT NULL COMMENT '链路编号', `error_msg` varchar(500) DEFAULT NULL, `status` int(11) DEFAULT NULL COMMENT '状态:1 有效 -1 无效', `created` datetime DEFAULT NULL COMMENT '创建时间', `updated` datetime DEFAULT NULL COMMENT '修改时间', `creator` varchar(20) DEFAULT NULL COMMENT '创建者', `updator` varchar(20) DEFAULT NULL COMMENT '修改者', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='http故障数据记录'; ``` **如何应用到业务中** 1. 配置类 ```java @Bean public IRestFallback restFallback() { DefaultRestFallBack restFallBack = new DefaultRestFallBack(); return restFallBack; } @Bean public RestTemplateUtils restTemplateUtils(@Autowired RestTemplate restTemplate) { RestTemplateUtils restTemplateUtils = new RestTemplateUtils(); restTemplateUtils.setRestTemplate(restTemplate); // 将默认的配置类加入到其中 restTemplateUtils.setRestFallback(restFallback()); return restTemplateUtils; } ``` 具体使用: ```java // 默认采用的失败回调 -> DefaultRestFallBack String post = restTemplateUtils.post(url, jsonObject, String.class); // 自定义采用的失败回调 --> 实现IRestFallback接口 = MyRestFallBack String post = restTemplateUtils.post(url, jsonObject, String.class, new MyRestFallBack()); ``` ### 异步线程 里面封装了消息串联的逻辑,当异步线程产生时,会和主线程的消息进行串联。 **将线程加入异步队列** 加入进去的参数会先放入异步队列进行排队,然后通过消费线程消费该方法。 ```java // 希望被记录下来的消息内容 Map dataMap = new HashMap(); dataMap.put("id","asdsa"); ThreadProcessUtils.addRealTimeQueue(() -> { logger.info("这是一个异步消息" + Cat.getCurrentMessageId()); // 做业务操作. }, dataMap); ``` **将加入调度队列** 这里是负责周期性执行数据 ```java ThreadProcessUtils.addSchedulingList(()->{ System.out.println("这是一个调度操作" + Cat.getCurrentMessageId()); }); ``` **配置相关** ```yaml spring: elab: thread: real-queue-size: 1000 # 异步队列大小 scheduling-interval-second: 30 # 调度间隔时长(秒) ``` #### 并行处理 该框架的使用方式和`CompletableFuture`基本保持一致,只是仅仅涵盖了链路串联功能。 希望大家能够统一使用框架封装的,好处就是在修改的时候能统一修改,调优也是。 - 单个请求 ```java CompletableFuture stringCompletableFuture = ThreadProcessUtils.supplyAsync(() -> { logger.info("任务开始之前:" + Cat.getCurrentMessageId()); try { Thread.sleep(3000); } catch (Exception e) { } logger.info("任务开始之后:" + Cat.getCurrentMessageId()); return "ABC"; }); // 在此期间可以执行其他业务操作 // 需要注意的是到这一步是阻塞的。 String s = stringCompletableFuture.get(); ``` - 多个请求,按照顺序返回结果 ```java // 这里需要注意的是第一个参数,true代表是等所有结果加载完了才返回,false是先提交任务执行,这个过程不一定能拿到结果。 CompletableFuture[] completableFutures = ThreadProcessUtils.supplyAsync(true,() -> { logger.info("任务1 - 开始" + Cat.getCurrentMessageId()); Thread.sleep(3000); logger.info("任务1 - 结束" + Cat.getCurrentMessageId()); return "ABC1"; }, () -> { logger.info("任务2 - 开始:" + Cat.getCurrentMessageId()); logger.info("任务2 - 结束" + Cat.getCurrentMessageId()); return "ABC2"; }); // 如果上面是true表示结果加载完了才会执行到这里,如果是false的话,就需要这里阻塞去拿结果. for (int i = 0; i < completableFutures.length; i++) { String s = completableFutures[i].get(); logger.info("结果:" + s); } ``` - 多个请求,按照提交的key拿到结果 ```java Map> taskMap = new LinkedHashMap<>(); taskMap.put("A", () -> { logger.info("A 开始" + Cat.getCurrentMessageId()); sleep(1000); logger.info("A 结束" + Cat.getCurrentMessageId()); return "A-result"; }); taskMap.put("B", () -> { logger.info("B 开始" + Cat.getCurrentMessageId()); sleep(1000); logger.info("B 结束" + Cat.getCurrentMessageId()); return "B-result"; }); taskMap.put("C", () -> { logger.info("C 开始" + Cat.getCurrentMessageId()); sleep(1000); logger.info("C 结束" + Cat.getCurrentMessageId()); return "C-result"; }); Map> completableFutureMap = ThreadProcessUtils.supplyAsync(taskMap); // 根据提交的key,获取对应的值 String a = completableFutureMap.get("A").get(); String b = completableFutureMap.get("B").get(); String c = completableFutureMap.get("C").get(); logger.info("获取对应的结果:" + a); logger.info("获取对应的结果:" + b); logger.info("获取对应的结果:" + c); ``` ### 功能类 #### ContainerRefresh 当Spring容器刷新完成之后,希望被回调处理的类 ```java ContainerRefresh.getInstance().register((arg) -> { // 处理容器被刷新完成之后回调的业务逻辑 }); ``` 通过`ContainerRefreshRunner`实现**SpringBoot**的`ApplicationRunner`接口完成回调 #### SpringEventUtils 事件推送器; **1. 关注事件** 通过实现`ApplicationListener`,其中`EventA` 代表一个参数事件.通过订阅该时间之后,有发送器发送该时间立即被唤醒. **2. 推送事件** 通过`SpringEventUtils` 来发送一个事件消息,交给关注`EventA`包装的订阅器. ```java SourceModel sourceModel = new SourceModel(); sourceModel.setName("abc"); SpringEventUtils.syncEventPublisher(new EventA(sourceModel)); ```