当前位置: 首页 > news >正文

个人网站内容怎么写免费php源码网

个人网站内容怎么写,免费php源码网,电商网站开发文档,智慧工厂管理系统背景 在本系列的前面一篇博客评论中#xff0c;有小伙伴指出#xff0c;API服务存在线程安全问题#xff1a; https://blog.csdn.net/seawaving/article/details/122905199#comments_34477405 今天来确认下#xff0c;线程是否安全#xff1f;如不安全#xff0c;如何…背景 在本系列的前面一篇博客评论中有小伙伴指出API服务存在线程安全问题 https://blog.csdn.net/seawaving/article/details/122905199#comments_34477405 今天来确认下线程是否安全如不安全如何修复 ‍ 回顾 先来回顾下先前的实现可能存在线程安全的是自己实现的过滤器链如下 package tech.abc.platform.cip.api.framework;import tech.abc.platform.cip.common.entity.ApiRequest; import tech.abc.platform.cip.common.entity.ApiResponse;import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List;/*** API服务过滤器链条** author wqliu* date 2022-2-12**/ public class ApiFilterChain {/*** 请求*/private ApiRequest request;/*** 响应*/private ApiResponse response new ApiResponse();/*** 过滤器集合*/private final ListApiFilter filters;/*** 过滤器迭代器*/private IteratorApiFilter iterator;public ApiFilterChain() {filters Collections.EMPTY_LIST;}public ApiFilterChain(ApiFilter... filters) {this.filters Arrays.asList(filters);}/*** 获取请求** return {link ApiRequest}*/public ApiRequest getRequest() {return this.request;}/*** 获取响应** return {link ApiResponse}*/public ApiResponse getResponse() {return this.response;}/*** 执行过滤** param request 请求* param response 响应*/public void doFilter(ApiRequest request, ApiResponse response) {// 如迭代器为空则初始化if (this.iterator null) {this.iterator this.filters.iterator();}// 集合中还有过滤器则继续往下传递if (this.iterator.hasNext()) {ApiFilter nextFilter this.iterator.next();nextFilter.doFilter(request, response, this);}// 将处理结果更新到属性中this.request request;this.response response;}/*** 重置*/public void reset() {this.request null;this.response null;this.iterator null;}} 该类是参照官方的MockFilterChain实现的源码如下 /** Copyright 2002-2018 the original author or authors.** 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** https://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.springframework.mock.web;import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List;import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils;/*** Mock implementation of the {link javax.servlet.FilterChain} interface.** pA {link MockFilterChain} can be configured with one or more filters and a* Servlet to invoke. The first time the chain is called, it invokes all filters* and the Servlet, and saves the request and response. Subsequent invocations* raise an {link IllegalStateException} unless {link #reset()} is called.** author Juergen Hoeller* author Rob Winch* author Rossen Stoyanchev* since 2.0.3* see MockFilterConfig* see PassThroughFilterChain*/ public class MockFilterChain implements FilterChain {Nullableprivate ServletRequest request;Nullableprivate ServletResponse response;private final ListFilter filters;Nullableprivate IteratorFilter iterator;/*** Register a single do-nothing {link Filter} implementation. The first* invocation saves the request and response. Subsequent invocations raise* an {link IllegalStateException} unless {link #reset()} is called.*/public MockFilterChain() {this.filters Collections.emptyList();}/*** Create a FilterChain with a Servlet.* param servlet the Servlet to invoke* since 3.2*/public MockFilterChain(Servlet servlet) {this.filters initFilterList(servlet);}/*** Create a {code FilterChain} with Filters and a Servlet.* param servlet the {link Servlet} to invoke in this {link FilterChain}* param filters the {link Filter}s to invoke in this {link FilterChain}* since 3.2*/public MockFilterChain(Servlet servlet, Filter... filters) {Assert.notNull(filters, filters cannot be null);Assert.noNullElements(filters, filters cannot contain null values);this.filters initFilterList(servlet, filters);}private static ListFilter initFilterList(Servlet servlet, Filter... filters) {Filter[] allFilters ObjectUtils.addObjectToArray(filters, new ServletFilterProxy(servlet));return Arrays.asList(allFilters);}/*** Return the request that {link #doFilter} has been called with.*/Nullablepublic ServletRequest getRequest() {return this.request;}/*** Return the response that {link #doFilter} has been called with.*/Nullablepublic ServletResponse getResponse() {return this.response;}/*** Invoke registered {link Filter Filters} and/or {link Servlet} also saving the* request and response.*/Overridepublic void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {Assert.notNull(request, Request must not be null);Assert.notNull(response, Response must not be null);Assert.state(this.request null, This FilterChain has already been called!);if (this.iterator null) {this.iterator this.filters.iterator();}if (this.iterator.hasNext()) {Filter nextFilter this.iterator.next();nextFilter.doFilter(request, response, this);}this.request request;this.response response;}/*** Reset the {link MockFilterChain} allowing it to be invoked again.*/public void reset() {this.request null;this.response null;this.iterator null;}/*** A filter that simply delegates to a Servlet.*/private static final class ServletFilterProxy implements Filter {private final Servlet delegateServlet;private ServletFilterProxy(Servlet servlet) {Assert.notNull(servlet, servlet cannot be null);this.delegateServlet servlet;}Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {this.delegateServlet.service(request, response);}Overridepublic void init(FilterConfig filterConfig) throws ServletException {}Overridepublic void destroy() {}Overridepublic String toString() {return this.delegateServlet.toString();}}} ‍ 这个类用在了我们API服务中如下 package tech.abc.platform.cip.api.service.impl;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import tech.abc.platform.cip.api.exception.ApiException; import tech.abc.platform.cip.api.framework.ApiFilterChain; import tech.abc.platform.cip.api.framework.BasicValidateFilter; import tech.abc.platform.cip.api.framework.BusinessFilter; import tech.abc.platform.cip.api.framework.FrameworkValidateFilter; import tech.abc.platform.cip.api.service.ApiRestService; import tech.abc.platform.cip.common.entity.ApiRequest; import tech.abc.platform.cip.common.entity.ApiResponse; import tech.abc.platform.cip.enums.ApiServiceExecuteResultEnum; import tech.abc.platform.cip.service.ApiServiceLogService; import tech.abc.platform.common.exception.CustomException;import java.time.LocalDateTime;/*** * API服务技术框架实现** author wqliu* date 2022-2-10**/ Service public class ApiRestServiceImpl implements ApiRestService {private ApiFilterChain filterChain;Autowiredprivate ApiServiceLogService apiServiceLogService;public ApiRestServiceImpl(FrameworkValidateFilter frameworkValidateFilter,BusinessFilter businessFilter, BasicValidateFilter basicValidateFilter) {filterChain new ApiFilterChain(basicValidateFilter, frameworkValidateFilter, businessFilter);}Overridepublic ApiResponse handle(ApiRequest apiRequest) {LocalDateTime receiveTime LocalDateTime.now();ApiResponse apiResponse new ApiResponse();try {filterChain.doFilter(apiRequest, apiResponse);apiResponse this.filterChain.getResponse();apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.SUCCESS.name());} catch (CustomException ex) {// 自定义异常处理apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());apiResponse.setErrorCode(S00);apiResponse.setErrorMessage(ex.getMessage());} catch (ApiException ex) {// API异常处理apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());apiResponse.setErrorCode(ex.getErrorCode());apiResponse.setErrorMessage(ex.getMessage());} catch (Exception ex) {// 非预期异常处理apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());apiResponse.setErrorCode(S99);apiResponse.setErrorMessage(未定义异常 ex.getMessage());} finally {// 需要重置为下次请求服务filterChain.reset();// 记录日志apiServiceLogService.recordLog(apiRequest, apiResponse, receiveTime);}return apiResponse;} } 分析 其中ApiRestServiceImpl使用的Service注解Spring的默认处理是单例模式ApiFilterChain是在构造函数中new出来的。线程安全的关键点在于ApiFilterChain持有和保存了ApiRequest和ApiResponse对象。 从代码层面分析了一下ApiFilterChain确实没有持有ApiRequest和ApiResponse对象的必要通过方法接收ApiRequest对象然后处理过程中修改ApiResponse对象都是引用没必要再保存一份。 至于当时为什么这么写大概是参照官方MockFilterChain写法高度信任而没有深度思考是否需要这么做。 ‍ 验证 上面是从代码层面分析接下来就动手验证下线程安全问题是否存在借此也夯实下实际工作中很少用到的多线程并发及线程安全基础。 如何验证呢 其实思路也挺简单发起多次接口调用通过日志输出对象的HashCode看看HashCode是否是同一个就好了。 ‍ 使用Postman来做接口测试调用平台内置的查询待处理消息的服务接口platform.message.query如下 注为方便测试把签名验证处理临时注释掉了因此入参sign属性随便写了个1111以通过非空验证。 ‍ 在服务接口处理中添加日志输出这里用error而不是info目的是更容易找到如下 然后使用postman发起两次接口调用查看日志如下 可以看到无论是ApiRestService还是其所属的filterChain哈希码是完全相同的已经足以说明就是同一个对象因此存在线程安全问题。当接口同时收到多个请求时也就是多线程并发时持有的请求对象和响应对象会混乱掉是个大问题。 ‍ 修正 既然问题已经确认那接下来就修正它。 在前面分析环节实际已经分析出来filterChain并不需要持有请求对象和响应对象去除掉后就从根本上解决了线程安全问题调整如下 package tech.abc.platform.cip.api.framework;import tech.abc.platform.cip.common.entity.ApiRequest; import tech.abc.platform.cip.common.entity.ApiResponse;import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List;/*** API服务过滤器链条** author wqliu* date 2022-2-12**/ public class ApiFilterChain {/*** 过滤器集合*/private final ListApiFilter filters;/*** 过滤器迭代器*/private IteratorApiFilter iterator;public ApiFilterChain() {filters Collections.EMPTY_LIST;}public ApiFilterChain(ApiFilter... filters) {this.filters Arrays.asList(filters);}/*** 执行过滤** param request 请求* param response 响应*/public void doFilter(ApiRequest request, ApiResponse response) {// 如迭代器为空则初始化if (this.iterator null) {this.iterator this.filters.iterator();}// 集合中还有过滤器则继续往下传递if (this.iterator.hasNext()) {ApiFilter nextFilter this.iterator.next();nextFilter.doFilter(request, response, this);}}/*** 重置*/public void reset() {this.iterator null;}} 测试功能正常如下 ‍ 新的疑问点 在调整ApiFilterChain的过程中去除了存在线程安全的ApiRequest和ApiResponse对象同时发现还持有一个过滤器集合对象 private final List filters该对象在构造方法中初始化在接口服务的finally里执行reset清理工作不过reset方法是重置过滤器集合的迭代器而不是清空过滤器集合本身。 假设是多线程并发情况下A、B两个请求先后到达A请求处理结束了调用reset清空了过滤器的迭代器而B请求还在只走完了3个过滤器中的2个会不会有问题呢 按照前面的验证方法输出哈希码确定是同一个对象。 要做并发测试比较麻烦得辅助Jmeter等工具来实现了 这个地方高度怀疑存在线程安全问题比较彻底的解决办法就是把API服务变更为非单例模式。 彻底改造 接口服务对应的控制器中直接new对象不使用依赖注入如下 RestController RequestMapping(/api) Slf4j public class ApiRestController {PostMapping(/rest)AllowAllpublic ResponseEntityApiResponse post(RequestBody ApiRequest apiRequest) {ApiRestService apiRestService new ApiRestServiceImpl();ApiResponse apiResponse apiRestService.handle(apiRequest);return new ResponseEntityApiResponse(apiResponse, HttpStatus.OK);}}ApiRestServiceImpl去除Service注解从而也不再是单例模式调整构造方法以及内部获取类的方式如下 package tech.abc.platform.cip.api.service.impl;import lombok.extern.slf4j.Slf4j; import tech.abc.platform.cip.api.exception.ApiException; import tech.abc.platform.cip.api.framework.ApiFilterChain; import tech.abc.platform.cip.api.framework.BasicValidateFilter; import tech.abc.platform.cip.api.framework.BusinessFilter; import tech.abc.platform.cip.api.framework.FrameworkValidateFilter; import tech.abc.platform.cip.api.service.ApiRestService; import tech.abc.platform.cip.common.entity.ApiRequest; import tech.abc.platform.cip.common.entity.ApiResponse; import tech.abc.platform.cip.enums.ApiServiceExecuteResultEnum; import tech.abc.platform.cip.service.ApiServiceLogService; import tech.abc.platform.common.exception.CustomException; import tech.abc.platform.common.utils.SpringUtil;import java.time.LocalDateTime;/*** * API服务技术框架实现** author wqliu* date 2022-2-10**/Slf4j public class ApiRestServiceImpl implements ApiRestService {private ApiFilterChain filterChain;public ApiRestServiceImpl() {BusinessFilter businessFilter SpringUtil.getBean(BusinessFilter.class);FrameworkValidateFilter frameworkValidateFilter SpringUtil.getBean(FrameworkValidateFilter.class);BasicValidateFilter basicValidateFilter SpringUtil.getBean(BasicValidateFilter.class);filterChain new ApiFilterChain(basicValidateFilter, frameworkValidateFilter, businessFilter);}Overridepublic ApiResponse handle(ApiRequest apiRequest) {LocalDateTime receiveTime LocalDateTime.now();ApiResponse apiResponse new ApiResponse();try {filterChain.doFilter(apiRequest, apiResponse);apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.SUCCESS.name());} catch (CustomException ex) {// 自定义异常处理apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());apiResponse.setErrorCode(S00);apiResponse.setErrorMessage(ex.getMessage());} catch (ApiException ex) {// API异常处理apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());apiResponse.setErrorCode(ex.getErrorCode());apiResponse.setErrorMessage(ex.getMessage());} catch (Exception ex) {// 非预期异常处理apiResponse.setExecuteResult(ApiServiceExecuteResultEnum.ERROR.name());apiResponse.setErrorCode(S99);apiResponse.setErrorMessage(未定义异常 ex.getMessage());} finally {ApiServiceLogService apiServiceLogService SpringUtil.getBean(ApiServiceLogService.class);// 记录日志apiServiceLogService.recordLog(apiRequest, apiResponse, receiveTime);}return apiResponse;} } 运行发现多次接口调用进行测试每次接口调用无论是ApiRestService还是ApiFilterChain都不是同一个对象了因此线程肯定是安全的了。 ‍ 开源平台资料 平台名称一二三开发平台 简介 企业级通用开发平台 设计资料[csdn专栏] 开源地址[Gitee] 开源协议MIT 如果您在阅读本文时获得了帮助或受到了启发希望您能够喜欢并收藏这篇文章为它点赞~ 请在评论区与我分享您的想法和心得一起交流学习不断进步遇见更加优秀的自己
http://www.w-s-a.com/news/574217/

相关文章:

  • 山东政务网站建设文字logo免费设计在线生成
  • 韩雪个人网站唐山网络运营推广
  • 查建设工程业绩在哪个网站网站建设优化服务如何
  • 江苏省建设工程安全监督网站商洛网站制作
  • 海淀网站建设wzjs51网页设计页面配色分析
  • 网站的备案流程图垦利网站制作
  • 行业用品网站怎么建设外链买东西的网站都有哪些
  • 淘宝做促销的网站集团门户网站建设策划
  • 网站排行榜查询怎样把个人介绍放到百度
  • vps 网站上传河北省招投标信息网
  • 武进网站建设咨询网站定制公司选哪家
  • 郑州市建设投资集团公司网站深圳企业网站建设推荐公司
  • 天津个人网站备案查询dz网站恢复数据库
  • 关于网站建设的期刊文献宣传片文案
  • 物业网站模板下载wordpress+菜单大小
  • 网站建设案例教程视频空间刷赞网站推广
  • 网站建设借鉴做外贸球衣用什么网站
  • 网站建设的前途微信公众号制作网站
  • 做网站之前要安装什么网站改进建议有哪些
  • 网站建设+管理系统开发山东专业网站建设公司
  • 基础微网站开发咨询中国印花图案设计网站
  • 找最新游戏做视频网站天津市招标投标公共服务平台
  • 电影订票网站怎么做注册地址出租多少钱
  • 做网站的规划和设想怎样做能让招聘网站记住密码
  • 建站知乎网站公告建设方案
  • 济南市住房和城乡建设局官方网站淮阳住房和城乡建设网站
  • 网站的设计特点有哪些seo推广要多少钱
  • wordpress开通多站点好处软件开发外包公司的设计一般多少钱
  • 为什么我的网站做不起来微信网页版登录手机版下载
  • 苏州市建设职业中心网站北京网站优化方法