Coder Social home page Coder Social logo

jvm-sandbox-repeater's Introduction

logo

Build Status License GitHub issues

基于JVM-Sandbox的录制/回放通用解决方案

jvm-sandbox-repeaterJVM-Sandbox生态体系下的重要模块,它具备了JVM-Sandbox的所有特点,插件式设计便于快速适配各种中间件,封装请求录制/回放基础协议,也提供了通用可扩展的各种丰富API。

目标人群 - 面向测试开发工程师

  • 线上有个用户请求一直不成功,我想在测试环境Debug一下,能帮我复现一下吗?
  • 压测流量不知道怎么构造,数据结构太复杂,压测模型也难以评估,有什么好的办法吗?
  • 不想写接口测试脚本了,我想做一个流量录制系统,把线上用户场景做业务回归,可能会接入很多服务系统,不想让每个系统都进行改造,有好的框架选择吗?
  • 我想做一个业务监控系统,对线上核心接口采样之后做一些业务校验,实时监控业务正确性。

如果你有以上的想法或需求,jvm-sandbox-repeater 都将是你的不二选择方案;框架基于JVM-Sandbox,拥有JVM-Sandbox的一切特性,同时封装了以下能力:

  • 录制/回放基础协议,可快速配置/编码实现一类中间件的录制/回放
  • 开放数据上报,对于录制结果可上报到自己的服务端,进行监控、回归、问题排查等上层平台搭建

项目简介

repeater的核心能力是什么?

1. 通用录制/回放能力

  • 无侵入式录制HTTP/Java/Dubbo入参/返回值录制能力(业务系统无感知)
  • 基于TTL提供多线程子调用追踪,完整追踪一次请求的调用路径
  • 入口请求(HTTP/Dubbo/Java)流量回放、子调用(Java/Dubbo)返回值Mock能力

2. 快速可扩展API实现

  • 录制/回放插件式架构
  • 提供标准接口,可通过配置/简单编码实现一类通用插件

3. standalone工作模式

  • 无需依赖任何服务端/存储,可以单机工作,提供录制/回放能力

repeater的可以应用到哪些场景?

1. 业务快速回归

  • 基于线上流量的录制/回放,无需人肉准备自动化测试脚本、准备测试数据

2. 线上问题排查

  • 录制回放提供"昨日重现"能力,还原线上真实场景到线下做问题排查和Debug
  • 动态方法入参/返回值录制,提供线上快速问题定位

3. 压测流量准备

  • 0成本录制HTTP/Dubbo等入口流量,作为压测流量模型进行压测

4. 实时业务监控

  • 动态业务监控,基于核心接口数据录制回流到平台,对接口返回数据正确性进行校验和监控

核心原理

流量录制

对于Java调用,一次流量录制包括一次入口调用(entranceInvocation)(eg:HTTP/Dubbo/Java)和若干次子调用(subInvocations)。流量的录制过程就是把入口调用和子调用绑定成一次完整的记录,框架抽象了基础录制协议,调用的组装由调用插件(InvokePlugin)来完成,需要考虑解决的核心问题:

  • 快速开发和适配新插件
  • 绑定入口调用和子调用(解决多线程上下文传递问题)
  • invocation唯一定位,保障回放时精确匹配
  • 自定义流量采样、过滤、发送、存储

框架的核心逻辑录制协议基于JVM-Sandbox的BEFORERETRUNTHROW事件机制进行录制流程控制,详见DefaultEventListener

基于TTL解决跨线程上下文传递问题,开启RepeaterConfig.useTtl之后支持多线程子调用录制

开放插件定义enhance埋点/自定义调用组装方式快速实现插件适配

Invocation抽象Identity统一定位由插件自己扩展实现

基于Tracer实现应用内链路追踪、采样;同时支持多种过滤方式,插件可自由扩展;

public void onEvent(Event event) throws Throwable {
    try {
        /*
         * event过滤;针对单个listener,只处理top的事件
         */
        /** -------- **/
        /*
         * 初始化Tracer开启上下文追踪[基于TTL,支持多线程上下文传递]
         */
        /** -------- **/
        /*
         * 执行基础过滤
         */
        /** -------- **/
        /*
         * 执行采样计算
         */
        /** -------- **/
        /*
         * processor filter
         */
        /** -------- **/
        /*
         * 分发事件处理
         */
    } catch (ProcessControlException pe) {
        /*
         * sandbox流程干预
         */
    } catch (Throwable throwable) {
    	 /*
    	  * 统计异常
    	  */
    } finally {
        /*
         * 清理上下文
         */
    }
}

流量回放

流量回放,获取录制流量的入口调用入参,再次发起调用。注意:读接口或者幂等写接口可以直接回放,否则在生产环境请谨慎使用,可能会造成脏数据;用户可自行选择mock回放或者非mock,回放过程要解决的核心问题:

  • 多种入口(HTTP/Dubbo/Java)的回放发起
  • 自定义回放流量数据来源、回放结果的上报
  • 自定义mock/非mock回放、回放策略
  • 开放回放流程关键节点hook

回放过程通过异步EventBus方式订阅回放请求;基于FlowDispather进行回放流量分发,每个类型回放插件实现RepeaterSPI完成回放请求发起;每次回放请求可决定本地回放是否mock,插件也自由实现mock逻辑,mock流程代码

mock回放:回放流量子调用(eg:mybatis/dubbo)不发生真实调用,从录制子调用中根据 MockStrategy 搜索匹配的子调用,利用JVM-Sandbox的流程干预能力,有匹配结果,进行throwReturnImmediately返回,没有匹配结果则抛出异常阻断流程,避免重复调用污染数据

public void doMock(BeforeEvent event, Boolean entrance, InvokeType type) throws ProcessControlException {
    /*
     * 获取回放上下文
     */
    RepeatContext context = RepeatCache.getRepeatContext(Tracer.getTraceId());
    /*
     * mock执行条件
     */
    if (!skipMock(event, entrance, context) && context != null && context.getMeta().isMock()) {
        try {
            /*
             * 构建mock请求
             */
            final MockRequest request = MockRequest.builder()
                    ...
                    .build();
            /*
             * 执行mock动作
             */
            final MockResponse mr = StrategyProvider.instance().provide(context.getMeta().getStrategyType()).execute(request);
            /*
             * 处理策略推荐结果
             */
            switch (mr.action) {
  					...
            }
        } catch (ProcessControlException pce) {
            throw pce;
        } catch (Throwable throwable) {
            ProcessControlException.throwThrowsImmediately(new RepeatException("unexpected code snippet here.", throwable));
        }
    }
}

合作共建的公司团队

v



已支持的插件列表

Java生态中间件及各种框架众多,各公司技术选型差异较大没办法统一适配,目前适配了几款常用插件作为示例,如有需求可以通过issue方式提交,同时也欢迎大家来贡献开发插件

插件类型 录制 回放 Mock 支持时间 贡献者
http-plugin × 201906 zhaoyb1990
dubbo-plugin × 201906 zhaoyb1990
ibatis-plugin × 201906 zhaoyb1990
mybatis-plugin × 201906 ztbsuper
java-plugin 201906 zhaoyb1990
redis-plugin × 201910 ElesG
hibernate × 201910 zhaoyb1990
spring-data-jpa × 201910 zhaoyb1990

相关文档

钉钉交流群

pic

jvm-sandbox-repeater's People

Contributors

buynowdev avatar dknebula avatar elesg avatar jske91 avatar lemon-simple avatar mi-cool avatar xuminwlt avatar zhaoyb1990 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jvm-sandbox-repeater's Issues

使用okhttp3的接口封装的httpUtil工具类方法,录制报错,提示序列化失败

repeater代码版本

develop20190829

报错时录制的方法

public class HttpUtils {

    /**
     * 等待时间30s
     * 加上日志打印日志
     */
    private static OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .addNetworkInterceptor(new HttpLoggingInterceptor(new OkHttpLogger())
                    .setLevel(HttpLoggingInterceptor.Level.BODY))
            .build();


    public static Response post(String url, String body) throws IOException {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), body);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        return client.newCall(request).execute();
    }
}

报错日志

{"data":{"id":36648,"projectType":104043,"name":"自助投[新手流程]","aliasName":"自助投[新手流程]","code":"ZZT1040432019081336648","status":160,"businessType":"103004","remark":null,"descp":null,"availableAmt":9000000.00000,"invtMinAmt":100.00000,"invtMaxAmt":10000000.00000,"invtUnitAmt":100.00000,"rate":12.50000,"maxRate":12.50000,"feeRate":0.00000,"bonusRate":0.00000,"amount":10000000.00000,"totalPeriodCnt":180,"periodType":100,"amortType":180,"frozenDays":30,"frozenDaysType":100,"clientType":7,"exitDurationCnt":null,"perPeriodCnt":null,"perPeriodType":null,"investType":1,"invtStartTime":"2019-08-13 14:31:02","invtEndTime":"2019-08-18 14:31:02","intrStartDate":null,"intrEndDate":null,"assetExchange":"1","matchAssetType":"10","assetNos":"","ruleJson":null,"investCount":null,"couponTypes":[16,17],"supportLockCycleExit":false,"reviveable":false,"supportRevive":false,"supportSetReinvestStrategy":false,"isAutoInvt":0,"productType":100,"feePeriod":null,"isPrivilegeRate":true},"msg":"OK","status":10000000}2019-08-30 20:41:09 DEBUG DefaultEventListener#doBefore.identity={"uri":"java://com.xx.server.utils.HttpUtils/post~(Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Response;"}
2019-08-30 20:41:09 DEBUG DefaultEventListener.onEvent.invokeType=java
2019-08-30 20:41:09 DEBUG DefaultEventListener#doReturn.response=
2019-08-30 20:41:40 ERROR Error occurred serialize
com.alibaba.jvm.sandbox.repeater.plugin.core.serialize.SerializeException: [Error-1001]-hessian-serialize-error
	at com.alibaba.jvm.sandbox.repeater.plugin.core.serialize.HessianSerializer.serialize(HessianSerializer.java:43)
	at com.alibaba.jvm.sandbox.repeater.plugin.core.serialize.AbstractSerializerAdapter.serialize2String(AbstractSerializerAdapter.java:30)
	at com.alibaba.jvm.sandbox.repeater.plugin.core.wrapper.SerializerWrapper.inTimeSerialize(SerializerWrapper.java:98)
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultInvocationListener.onInvocation(DefaultInvocationListener.java:41)
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultEventListener.doReturn(DefaultEventListener.java:230)
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultEventListener.onEvent(DefaultEventListener.java:125)
	at com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers.handleEvent(EventListenerHandlers.java:102)
	at com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers.handleOnEnd(EventListenerHandlers.java:404)
	at com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers.onReturn(EventListenerHandlers.java:579)
	at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at java.com.alibaba.jvm.sandbox.spy.Spy.spyMethodOnReturn(Spy.java:216)
	at com.xx.server.utils.HttpUtils.post(HttpUtils.java:35)
	at com.xx.server.utils.DingtalkUtils.sendDingtalkMessage(DingtalkUtils.java:28)
	at com.xx.server.delivery.JiraNotificationDelivery.lambda$sendNotification$0(JiraNotificationDelivery.java:47)
	at java.lang.Iterable.forEach(Iterable.java:75)
	at com.xx.server.delivery.JiraNotificationDelivery.sendNotification(JiraNotificationDelivery.java:47)
	at com.xx.server.impl.AlertServiceImpl.receiveJiraNotification(AlertServiceImpl.java:185)
	at com.xx.server.impl.AlertServiceImpl$$FastClassBySpringCGLIB$$3cd85ab3.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
	at com.xx.server.config.WebLogAspect.doAround(WebLogAspect.java:61)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
	at com.xx.xx.filter.FilterChain$1.filter(FilterChain.java:78)
	at com.xx.xx.filter.FilterChainItem.doFilter(FilterChainItem.java:15)
	at com.xx.xx.server.filter.SimpleServerFilter.filter(SimpleServerFilter.java:27)
	at com.xx.xx.filter.FilterChainItem.doFilter(FilterChainItem.java:15)
	at com.xx.xx.validation.ValidatorFilter.filter(ValidatorFilter.java:65)
	at com.xx.xx.filter.FilterChainItem.doFilter(FilterChainItem.java:15)
	at com.xx.xx.server.filter.SimpleServerFilter.filter(SimpleServerFilter.java:27)
	at com.xx.xx.filter.FilterChainItem.doFilter(FilterChainItem.java:15)
	at com.xx.xx.server.filter.ExceptionFilter.filter(ExceptionFilter.java:32)
	at com.xx.xx.filter.FilterChainItem.doFilter(FilterChainItem.java:15)
	at com.xx.xx.filter.FilterChain.doFilter(FilterChain.java:40)
	at com.xx.xx.filter.GlobalFilterAspect.filter(GlobalFilterAspect.java:54)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
	at com.xx.server.impl.AlertServiceImpl$$EnhancerBySpringCGLIB$$57882692.receiveJiraNotification(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:112)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
	at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
	at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at com.alibaba.ttl.TtlRunnable.run(TtlRunnable.java:51)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
Caused by: com.caucho.hessian.io.IOExceptionWrapper: Read timed out

应用挂载了repeater,并且开启ttl的情况下,每执行一次ThreadPoolExecutor 的submit、execute方法,某些类的实例会不断的增加,gc时都回收不掉

bug描述

应用挂载了repeater,并且开启ttl的情况下,每执行一次ThreadPoolExecutor 的submit、execute方法,以下一些类的实例都会不断的增加,在系统执行ygc、甚至fgc之后都不会释放

java.util.concurrent.FutureTask
com.alibaba.ttl.TtlRunnable
com.alibaba.jvm.sandbox.api.listener.ext.Advice
com.alibaba.jvm.sandbox.api.listener.ext.AdviceAdapterListener.WrapAdvice

demo代码

@Controller
@RequestMapping("/foo")
public class FooController {

    private static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(4, 4,
            0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024),
            new BasicThreadFactory.Builder().namingPattern("common-pool-%d").build());


    @RequestMapping(value = "/test", method = RequestMethod.GET)
    @ResponseBody
    public String submit(@RequestParam("count") int count) {
        for (int i = 0; i < count; i++) {
            EXECUTOR.submit(() -> {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                System.out.println(Thread.currentThread().getName() + " submitted at " + sdf.format(new Date()));
            });
        }
        return "submit OK " + new Date();
    }
}

repeater-congfig配置

{
  "degrade": false,
  "exceptionThreshold": 1000,
  "httpEntrancePatterns": [
   
  ],
  "javaEntranceBehaviors": [
    
  ],
  "javaSubInvokeBehaviors": [
    
  ],
  "pluginIdentities": [
    "http",
    "java-entrance",
    "java-subInvoke",
    "mybatis",
    "ibatis",
    "dubbo-provider",
    "dubbo-consumer"
  ],
  "repeatIdentities": [
    "java",
    "http",
    "dubbo"
  ],
  "sampleRate": 10000,
  "useTtl": true
}

测试方式和结果

应用挂载repeater

应用启动之后,将sandbox、repeater插件挂载到应用进程上

截图_9edaab04-52e3-47f1-9c26-87bda7e85844

image

应用不挂载repeater

应用启动之后,不挂载repeater
截图_7430af08-5223-4606-b00f-7f7585b9933d

Double-Checked Locking

private synchronized static Class<?> getSpringContainerClass() {
if (springContainerClass == null) {
synchronized (mutex) {
if (springContainerClass == null) {
springContainerClass = ClassloaderBridge.instance().findClassInstance(SPRING_CONTAINER_CLASS);
}
}
}
return springContainerClass;
}

Double-Checked Locking is widely cited and used as an efficient method for implementing lazy initialization in a multithreaded environment.
Unfortunately, it will not work reliably in a platform independent way when implemented in Java, without additional synchronization.
declares the springContainerClass field volatile offers a much more elegant solution

standalone mode report Unable to create initial connections of pool.

../jvm-sandbox-repeater-master/bin/repeater.properties
/root/.sandbox-module/cfg/repeater.properties

录制消息投递地址

broadcaster.record.url=http://127.0.0.1:8001/facade/api/record/save

回放结果投递地址

broadcaster.repeat.url=http://127.0.0.1:8001/facade/api/repeat/save

回放消息取数据地址

repeat.record.url=http://127.0.0.1:8001/facade/api/record/%s/%s

配置文件拉取地址

repeat.config.url=http://127.0.0.1:8001/facade/api/config/%s/%s

心跳上报配置

repeat.heartbeat.url=http://127.0.0.1:8001/module/report.json

是否开启脱机工作模式

repeat.standalone.mode=true

是否开启spring advice拦截

repeat.spring.advice.switch=false;

当执行../bin/bootstrap.sh时,报错

2020-04-02 17:09:58.726 ERROR 16821 --- [nio-8001-exec-1] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_141]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_141]
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.MysqlIO.(MysqlIO.java:341) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2192) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2225) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2024) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.ConnectionImpl.(ConnectionImpl.java:779) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.JDBC4Connection.(JDBC4Connection.java:47) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_141]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_141]
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:389) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:310) ~[tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:203) ~[tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:735) [tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:667) [tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:482) [tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.ConnectionPool.(ConnectionPool.java:154) [tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118) [tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) [tomcat-jdbc-8.5.15.jar!/:na]
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) [tomcat-jdbc-8.5.15.jar!/:na]
at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:386) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:87) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:112) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:230) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:237) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:214) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:52) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1512) [hibernate-core-5.0.12.Final.jar!/:5.0.12.Final]
at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:45) [hibernate-entitymanager-5.0.12.Final.jar!/:5.0.12.Final]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:189) [spring-orm-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:380) [spring-orm-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) [spring-tx-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:447) [spring-tx-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277) [spring-tx-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) [spring-tx-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) [spring-tx-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) [spring-data-jpa-1.10.11.RELEASE.jar!/:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) [spring-aop-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) [spring-aop-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at com.sun.proxy.$Proxy97.updateByAppNameAndIp(Unknown Source) [na:na]
at com.alibaba.repeater.console.dal.dao.ModuleInfoDao.save(ModuleInfoDao.java:56) [repeater-console-dal-1.0.0-SNAPSHOT.jar!/:na]
at com.alibaba.repeater.console.service.impl.ModuleInfoServiceImpl.report(ModuleInfoServiceImpl.java:91) [repeater-console-service-1.0.0-SNAPSHOT.jar!/:na]
at com.alibaba.repeater.console.start.controller.page.ModuleInfoController.list(ModuleInfoController.java:49) [classes!/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_141]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_141]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) [spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_141]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_141]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.15.jar!/:8.5.15]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_141]
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_141]
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_141]
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_141]
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_141]
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_141]
at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_141]
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:211) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
at com.mysql.jdbc.MysqlIO.(MysqlIO.java:300) ~[mysql-connector-java-5.1.42.jar!/:5.1.42]
... 103 common frames omitted

2020-04-02 17:09:58.729 WARN 16821 --- [nio-8001-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 08S01
2020-04-02 17:09:58.729 ERROR 16821 --- [nio-8001-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

java调用回放时反序列化失败

1.在进行java调用时,录制成功,并可以获取到序列化信息,如截图
image

2,回放时能请求到服务,并读取到序列化信息
image
3,(问题)在回放反序列化时报空指针,请问是什么原因导致的,有什么解决办法?
image

image

不支持jdk1.6环境

能否支持jdk1.6?
目前发现在jdk1.6下运行报UnsupportedClassVersionError错误,发现原因是commons-lang3这个包是在jdk1.7下编译的,能否把这个包版本降一下?

LocalDateTime类型返回结果回放失败

问题分支

develop20190829,基于这个分支做了二次开发,但是未涉及hessian-lite库的修改

报错回放的方法

private static DateProvider dateProvider = new LocalDateProvider();

/**
     * 获取当前时间(年月日时分秒)
     *
     * @return
     */
    public static LocalDateTime getNowDateTime() {
        return dateProvider.getNowDateTime();
    }

报错堆栈

java.lang.ClassCastException: java.util.HashMap cannot be cast to java.time.LocalDateTime
	at com.xx.xx.commons.util.DateUtils.getNowDateTime(DateUtils.java)
	at com.xx.xx.p2p.controller.InvestApplyController.investApply(InvestApplyController.java:137)
	at com.xx.xx.p2p.controller.InvestApplyController$$FastClassBySpringCGLIB$$2235ec0a.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
	at com.xx.xx.p2p.controller.InvestApplyController$$EnhancerBySpringCGLIB$$856b3704.investApply(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.xx.xx.xxxhook.RequestCounterFilter.doFilterInternal(RequestCounterFilter.java:27)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.github.xiaoymin.swaggerbootstrapui.filter.SecurityBasicAuthFilter.doFilter(SecurityBasicAuthFilter.java:84)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.github.xiaoymin.swaggerbootstrapui.filter.ProductionSecurityFilter.doFilter(ProductionSecurityFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at com.alibaba.ttl.TtlRunnable.run(TtlRunnable.java:51)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)


对现有文档的3个小建议

您好,我是来自 ppmoney 的测试开发同学。

最近通过阿里技术的公众号推送了解到了这个工具,也第一时间进行了试用。从介绍、试用和一些源码阅读中,感受到这个工具的强大之处,非常感谢阿里能开源这样一个工具!

而在试用的过程中,感受到目前官方提供文档有不少的小问题,用起来不是太流畅。因此根据我个人的一些感受,提一些小的建议:

1、部分超链接404

https://github.com/alibaba/jvm-sandbox-repeater/blob/master/docs/user-guide-cn.md 中的 Slogan Demo究竟发生了什么RepeaterConfig.java 等,点击后都是 404 。建议修正下。

2、json 配置项没有说清楚是放在哪里的。

官方文档中给出的位置只是源码目录的位置,且链接 404 。经过自行试验,可以生效的配置项位置为 ~/.sandbox-module/cfg/repeater-config.json 。但这明显不满足多项目使用不同配置文件的需要,应该不是正确解答。建议补充下。

3、缺少应用到自己的应用时,回放方面的说明

对于自行设置被测应用这个章节,只提到了录制怎么做,没提到回放怎么做,有点懵逼。期望可以详细说明下回放怎么做。

最后,期望这个工具能越来越好。

PS:尝鲜的详细记录我记录在了 testerhome 社区,如果有兴趣可以移步 jvm-sandbox-repeater 尝鲜记录 (持续更新) ,也非常欢迎提出您的宝贵意见建议。

java8 Function类参数反序列化结果与原结果不一致

验证分支

develop20190829

验证方法

HessianSerializeDomain中新增Function类成员变量以及其gettter、setter,以及调整equals、hashcode方法。并执行HessianSerializerTest

修改代码如下:

private Function function = new Function() {
        @Override
        public Object apply(Object o) {
            return null;
        }
    };

 @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        HessianSerializeDomain domain = (HessianSerializeDomain) o;
        return Objects.equals(money, domain.money) &&
                Objects.equals(locale, domain.locale) &&
                Objects.equals(localDateTime, domain.localDateTime) &&
                Objects.equals(localDate, domain.localDate) &&
                Objects.equals(function, domain.function);
    }
 @Override
    public int hashCode() {
        return Objects.hash(money, locale, localDateTime, localDate, function);
    }

执行结果如下:
image

mybatis对于使用了 useGeneratedKeys="true" keyProperty="id"属性的insert sql无法mock。

问题描述

useGeneratedKeys 取值范围true、false 默认值是:false。 含义:设置是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中
keyProperty 取id的key值

使用了这类两个属性的insert sql会对传入的对象进行修改,将插入完成后的id设回给传入的参数。
然后调用了这个方法后,大家可以直接拿执行插入操作的对象中的id进行后面的操作。
如:

public Integer addCat(){
     Cat cat = new cat();
     cat.setName("miao");
     catMapper.insert(cat);
     return cat.getId();
}

由于录制时只关注mybatis的execute方法的入参和返回,没有关注传入参数的改变,导致在上面代码的场景中会出现回放失败的情况。

录制对象存在socket流导致业务请求被阻塞

业务发生阻塞是因为被录制的对象存在socket流导致的,因为在使用hessian序列化时,不支持socket流,会抛错,导致socket关闭,从而出现业务请求被阻塞的现象发生
Caused by: com.caucho.hessian.io.IOExceptionWrapper: Socket closed
field: java.net..socketInputStream
class: java.net.SocksSocketImpl (object=Socket[addr=/
*,port=8623,localport=34642])
at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:224)
at com.caucho.hessian.io.UnsafeSerializer.writeObject(UnsafeSerializer.java:169)
at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465)
at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:296)
... 132 common frames omitted
Caused by: com.caucho.hessian.io.IOExceptionWrapper: Socket closed
field: java.net.AbstractPlainSocketImpl.socketInputStream
at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:305)
at com.caucho.hessian.io.UnsafeSerializer.writeInstance(UnsafeSerializer.java:215)
... 135 common frames omitted
Caused by: java.net.SocketException: Socket closed
at java.net.SocketInputStream.read(SocketInputStream.java:203)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at com.caucho.hessian.io.Hessian2Output.writeByteStream(Hessian2Output.java:1287)
at com.caucho.hessian.io.InputStreamSerializer.writeObject(InputStreamSerializer.java:70)
at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:465)
at com.caucho.hessian.io.UnsafeSerializer$ObjectFieldSerializer.serialize(UnsafeSerializer.java:296)
... 136 common frames omitted

develop20190829-分支发布计划

最新dev分支develop20190829,已Fix了issue里面大部分问题;#13 #14 #9 #10 问题;

关于本次发布的计划包括:

  • redis 插件适配 (原计划7月底-)
  • dubbo 回放支持
  • bug fix
  • ...

大家可以使用情况,讨论下有什么新需求

关于PR的提交,目前有几个PR还没有Agree,原因是PR对问题的解法目前不是最优,没有彻底的解决问题,针对的问题也在本次Dev分支中有解决,大家可以参考一下,也希望大家积极的贡献idea和使用场景

BigDecimal类数据回放错误

问题描述

当需要mock的方法的返回中包含BigDecimal参数,在mock返回的时候BigDecimal类的参数就会变成0。
当mock了getBigDecimal方法后,录制时传入的参数是5,回放时返回的结果是0。

初步猜测是序列化工具的bug,在金融领域很多时候为了保留精度会使用BigDecimal进行金额类数据的操作,请问这个问题能否解决?

实例

@Override
public Response<DemoResponse> getAnoResult(DemoRequest request) {
    DemoResponse response = new DemoResponse();
    BigDecimal id = getBigDecimal(request.getId());
    System.out.println("BigDecimal"+id);
 
    response.setPhone("phone"+id);
    response.setUsername("userName"+id);
    return new Response<>(response);
 
}
 
private BigDecimal getBigDecimal(long num){
    System.out.println("getBigDecimal: "+num);
 
    BigDecimal result  = new BigDecimal(num);
    return result;
}

回放结果

{
    "success": true,
    "data": {
        "repeatId": "192168015073156699995845010052ed",
        "finish": true,
        "response": "{\n  \"code\" : 200,\n  \"payload\" : {\n    \"username\" : \"userName0\",\n    \"phone\" : \"phone0\"\n  }\n}",
        "originResponse": "{\n  \"code\" : 200,\n  \"payload\" : {\n    \"username\" : \"userName5\",\n    \"phone\" : \"phone5\"\n  }\n}",
        "diff": [
            {
                "op": "replace",
                "path": "/payload/phone",
                "value": "phone0"
            },
            {
                "op": "replace",
                "path": "/payload/username",
                "value": "userName0"
            }
        ],
        "cost": 95,
        "traceId": "192168015073156699995867210002ed",
        "appName": "unknown",
        "environment": "unknown",
        "host": "192.168.15.73",
        "starTime": "2019-08-28T13:45:58.674+0000",
        "endTime": "2019-08-28T13:45:58.768+0000",
        "mockInvocations": [
            {
                "index": 1,
                "traceId": "192168015073156699995867210002ed",
                "repeatId": "192168015073156699995845010052ed",
                "success": true,
                "skip": false,
                "cost": 25,
                "originUri": "java://com.ppmoney.devops.rpc.DemoRpcServiceImpl/getBigDecimal~L",
                "currentUri": "java://com.ppmoney.devops.rpc.DemoRpcServiceImpl/getBigDecimal~L",
                "originArgs": [
                    5
                ],
                "currentArgs": [
                    5
                ]
            }
        ]
    },
    "message": "operate success"
}

使用tomcat部署的应用,dubbo回放失败

跟踪发现,是泛化调用的时候,proxy类用的是当前类加载器,然后dubbo相关的类我, 又配置了rount到应用的加载器
response":{
"@type":"java.lang.IllegalArgumentException",
"localizedMessage":"interface com.alibaba.dubbo.rpc.service.GenericService is not visible from class loader",
"message":"interface com.alibaba.dubbo.rpc.service.GenericService is not visible from class loader",
"stackTrace":[
{
"className":"com.alibaba.dubbo.common.bytecode.Proxy",
"fileName":"Proxy.java",
"lineNumber":96,
"methodName":"getProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.common.bytecode.Proxy",
"fileName":"Proxy.java",
"lineNumber":69,
"methodName":"getProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory",
"fileName":"JavassistProxyFactory.java",
"lineNumber":35,
"methodName":"getProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory",
"fileName":"AbstractProxyFactory.java",
"lineNumber":64,
"methodName":"getProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory",
"fileName":"AbstractProxyFactory.java",
"lineNumber":34,
"methodName":"getProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper",
"fileName":"StubProxyFactoryWrapper.java",
"lineNumber":65,
"methodName":"getProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.rpc.ProxyFactory$Adaptive",
"fileName":"ProxyFactory$Adaptive.java",
"lineNumber":-1,
"methodName":"getProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.config.ReferenceConfig",
"fileName":"ReferenceConfig.java",
"lineNumber":432,
"methodName":"createProxy",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.config.ReferenceConfig",
"fileName":"ReferenceConfig.java",
"lineNumber":335,
"methodName":"init",
"nativeMethod":false
},
{
"className":"com.alibaba.dubbo.config.ReferenceConfig",
"fileName":"ReferenceConfig.java",
"lineNumber":164,
"methodName":"get",
"nativeMethod":false
},
{
"className":"com.alibaba.jvm.sandbox.repeater.plugin.dubbo.DubboRepeater",
"fileName":"DubboRepeater.java",
"lineNumber":70,
"methodName":"executeRepeat",
"nativeMethod":false
},
{
"className":"com.alibaba.jvm.sandbox.repeater.plugin.core.impl.AbstractRepeater",
"fileName":"AbstractRepeater.java",
"lineNumber":47,
"methodName":"repeat",
"nativeMethod":false
},
{
"className":"com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultFlowDispatcher",
"fileName":"DefaultFlowDispatcher.java",
"lineNumber":43,
"methodName":"dispatch",
"nativeMethod":false
},
{
"className":"com.alibaba.jvm.sandbox.repeater.plugin.core.impl.spi.RepeatSubscribeSupporter",
"fileName":"RepeatSubscribeSupporter.java",
"lineNumber":64,
"methodName":"onSubscribe",
"nativeMethod":false
},
{
"className":"sun.reflect.NativeMethodAccessorImpl",
"fileName":"NativeMethodAccessorImpl.java",
"lineNumber":-2,
"methodName":"invoke0",
"nativeMethod":true
},
{
"className":"sun.reflect.NativeMethodAccessorImpl",
"fileName":"NativeMethodAccessorImpl.java",
"lineNumber":62,
"methodName":"invoke",
"nativeMethod":false
},
{
"className":"sun.reflect.DelegatingMethodAccessorImpl",
"fileName":"DelegatingMethodAccessorImpl.java",
"lineNumber":43,
"methodName":"invoke",
"nativeMethod":false
},
{
"className":"java.lang.reflect.Method",
"fileName":"Method.java",
"lineNumber":498,
"methodName":"invoke",
"nativeMethod":false
},
{
"className":"com.google.common.eventbus.Subscriber",
"fileName":"Subscriber.java",
"lineNumber":95,
"methodName":"invokeSubscriberMethod",
"nativeMethod":false
},
{
"className":"com.google.common.eventbus.Subscriber$1",
"fileName":"Subscriber.java",
"lineNumber":80,
"methodName":"run",
"nativeMethod":false
},
{
"className":"com.alibaba.ttl.TtlRunnable",
"fileName":"TtlRunnable.java",
"lineNumber":51,
"methodName":"run",
"nativeMethod":false
},
{
"className":"java.util.concurrent.ThreadPoolExecutor",
"fileName":"ThreadPoolExecutor.java",
"lineNumber":1142,
"methodName":"runWorker",
"nativeMethod":false
},
{
"className":"java.util.concurrent.ThreadPoolExecutor$Worker",
"fileName":"ThreadPoolExecutor.java",
"lineNumber":617,
"methodName":"run",
"nativeMethod":false
},
{
"className":"java.lang.Thread",
"fileName":"Thread.java",
"lineNumber":745,
"methodName":"run",
"nativeMethod":false
}
]
},

dubbo类型入口流量录制

dubbo类型的入口流量 ,入口配置是怎么配置的?现在还是不支持dubbo入口的流量进行回放吗?dubbo接口子调用又是怎么配置的?

怎样mock指定的方法

方法调用链中,只针对自己想要的方法mock,可以在配置文件设置或者有其他方式吗?

进展疑问

现在看着代码有很多变动 但是一直没有更新:
比如repeat/{appName}/{traceId}这个里面要用ip 但是参数里也没有 我还要手动save repeat库吗?

no valid repeat found for invoke type

回放的时候报错,详细堆栈:

2019-10-28 20:06:32.244 ERROR[repeat-task-pool-2]c.a.j.s.r.plugin.core.impl.spi.RepeatSubscribeSupporter.onSubscribe:66 -[Error-0000]-uncaught exception occurred when register repeat event, req={_data=QzA6Y29t...
com.alibaba.jvm.sandbox.repeater.plugin.exception.RepeatException: no valid repeat found for invoke type:com.alibaba.jvm.sandbox.repeater.plugin.domain.InvokeType$1@3d344495
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultFlowDispatcher.dispatch(DefaultFlowDispatcher.java:38)
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.spi.RepeatSubscribeSupporter.onSubscribe(RepeatSubscribeSupporter.java:59)
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.spi.RepeatSubscribeSupporter.onSubscribe(RepeatSubscribeSupporter.java:26)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:95)
	at com.google.common.eventbus.Subscriber$1.run(Subscriber.java:80)
	at com.alibaba.ttl.TtlRunnable.run(TtlRunnable.java:51)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

原因推测

com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultFlowDispatcher#dispatch()

Repeater repeater = RepeaterBridge.instance().select(recordModel.getEntranceInvocation().getType());

RepeaterBridge 中使用Map存储Repeater, InvokeType为Key

com.alibaba.jvm.sandbox.repeater.plugin.core.bridge.RepeaterBridge

    private volatile Map<InvokeType, Repeater> cached = new HashMap<InvokeType, Repeater>();

InvokeType接口中有几个默认实现,没有实现hashCode和equals,导致无法在cached中找到对应的Repeater。

public interface InvokeType extends java.io.Serializable {

    InvokeType HTTP = new InvokeType() {
        @Override
        public String name() {
            return "http";
        }
    };

    InvokeType JAVA = new InvokeType() {
        @Override
        public String name() {
            return "java";
        }
    };

    InvokeType MYBATIS = new InvokeType() {
        @Override
        public String name() {
            return "mybatis";
        }
    };

    InvokeType IBATIS = new InvokeType() {
        @Override
        public String name() {
            return "ibatis";
        }
    };

    InvokeType REDIS = new InvokeType() {
        @Override
        public String name() {
            return "redis";
        }
    };

    InvokeType DUBBO = new InvokeType() {
        @Override
        public String name() {
            return "dubbo";
        }
    };

    /**
     * 调用类型名称
     *
     * @return name
     */
    String name();
}

在dubbo的consumer端进行录制回放时,使用java来mock dubbo协议回放报错。

环境说明

  • 系统:Mac Os 10.14.3 (18D109)
  • java版本:
    java version "1.8.0_111"
    Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
    Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

用来尝试录制回放的项目是dubbo的spring示例项目

https://github.com/apache/dubbo-spring-boot-project/tree/master/dubbo-spring-boot-samples/externalized-configuration-samples

复现步骤

1、拉下源码
git clone https://github.com/apache/dubbo-spring-boot-project.git
2、使用idea 打开项目
3、到dubbo-spring-boot-samples/externalized-configuration-samples下,先用run provider服务,再run consumer服务
4、修改repeater-console的/facade/api/config接口,将返回的配置改为

{
    "success": true,
    "data": {
        "pluginsPath": null,
        "exceptionThreshold": 1000,
        "javaEntranceBehaviors": [],
        "pluginIdentities": [
            "http",
            "java-entrance",
            "java-subInvoke",
            "mybatis"
        ],
        "repeatIdentities": [
            "http",
            "java",
            "mybatis"
        ],
        "httpEntrancePatterns": [
            "/say-hello"
        ],
        "sampleRate": 10000,
        "javaSubInvokeBehaviors": [
            {
                "classPattern": "org.apache.dubbo.spring.boot.demo.provider.service.DefaultDemoService",
                "includeSubClasses": false,
                "methodPatterns": [
                    "sayHello"
                ]
            }
        ],
        "useTtl": true,
        "degrade": false
    },
    "message": "operate success"
}

5、以attach模式启动repeater,关联consumer服务的进程id
6、请求consumer暴露的/say-hello接口,从repeater.log看到录制成功日志,拿到traceId
7、调用repeater-console回放接口进行回放

录制、回放过程日志

2019-08-05 16:58:46 INFO  broadcast success,traceId=192168015073156499552592010001ed,resp=HttpUtil.Resp(code=200, body={"success":true,"data":"-/-","message":"operate success"}, message=null)
2019-08-05 16:59:00 INFO  subscribe success params={_data=QzA5Y29tLmFsaWJhYmEuanZtLnNhbmRib3gucmVwZWF0ZXIucGx1Z2luLmRvbWFpbi5SZXBlYXRNZXRhmAdhcHBOYW1lB3RyYWNlSWQEbW9jawhyZXBlYXRJZA9tYXRjaFBlcmNlbnRhZ2UKZGF0YXNvdXJjZQxzdHJhdGVneVR5cGUJZXh0ZW5zaW9uYAd1bmtub3duMCAxOTIxNjgwMTUwNzMxNTY0OTk1NTI1OTIwMTAwMDFlZFQwIDE5MjE2ODAxNTA3MzE1NjQ5OTU1NDAyOTQxMDAwMWVkXWROQzBFY29tLmFsaWJhYmEuanZtLnNhbmRib3gucmVwZWF0ZXIucGx1Z2luLnNwaS5Nb2NrU3RyYXRlZ3kkU3RyYXRlZ3lUeXBlkQRuYW1lYQ9QQVJBTUVURVJfTUFUQ0hIWg==}
2019-08-05 16:59:00 INFO  DefaultFlowDispatcher.dispatch中,RecordModel的traceId:192168015073156499552592010001ed,RepeatMeta的traceId:192168015073156499552592010001ed
2019-08-05 16:59:00 INFO  DefaultFlowDispatcher.dispatch中,RepeatMeta的repeatId:192168015073156499552592010001ed
2019-08-05 16:59:00 INFO  recordModel 中 EntranceInvocation 的 type 的名称: "http"
2019-08-05 16:59:00 INFO  传入 select 的 type: http
2019-08-05 16:59:00 INFO  RepeaterBridge 中的所有 cached: {"java":{"type":{}},"dubbo":{"type":{}},"http":{"type":{}}}
2019-08-05 16:59:00 INFO  cached 中具有的 type: java
2019-08-05 16:59:00 INFO  cached 中的 type java 和传入的 type com.alibaba.jvm.sandbox.repeater.plugin.domain.InvokeType$1@763784d2 作 equals 的结果: false
2019-08-05 16:59:00 INFO  cached 中具有的 type: dubbo
2019-08-05 16:59:00 INFO  cached 中的 type dubbo 和传入的 type com.alibaba.jvm.sandbox.repeater.plugin.domain.InvokeType$1@763784d2 作 equals 的结果: false
2019-08-05 16:59:00 INFO  cached 中具有的 type: http
2019-08-05 16:59:00 INFO  cached 中的 type http 和传入的 type com.alibaba.jvm.sandbox.repeater.plugin.domain.InvokeType$1@763784d2 作 equals 的结果: true
2019-08-05 16:59:00 INFO  AbstractRepeater.repeat中的traceId:192168015073156499554079210002ed
2019-08-05 16:59:00 INFO  AbstractRepeater.repeat中的repeatId:192168015073156499554029410001ed
2019-08-05 16:59:00 INFO  broadcastRepeat中的traceId:192168015073156499554079210002ed
2019-08-05 16:59:00 INFO  broadcastRepeat中的repeatId:192168015073156499554029410001ed
2019-08-05 16:59:00 INFO  broadcast success,traceId=192168015073156499554079210002ed,resp=HttpUtil.Resp(code=200, body={"success":true,"data":"-/-","message":"operate success"}, message=null)

consumer报错日志

2019-08-05 16:38:24.038 ERROR 55981 --- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause

java.lang.RuntimeException: DubboProcessor#assembleRequest only receive #onResponse behavior
	at com.alibaba.jvm.sandbox.repeater.plugin.dubbo.DubboProcessor.assembleRequest(DubboProcessor.java:59) ~[na:na]
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.AbstractInvocationProcessor.doMock(AbstractInvocationProcessor.java:70) ~[na:na]
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultEventListener.doBefore(DefaultEventListener.java:171) ~[na:na]
	at com.alibaba.jvm.sandbox.repeater.plugin.core.impl.api.DefaultEventListener.onEvent(DefaultEventListener.java:124) ~[na:na]
	at com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers.handleEvent(EventListenerHandlers.java:102) ~[na:na]
	at com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers.handleOnBefore(EventListenerHandlers.java:342) ~[na:na]
	at com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandlers.onBefore(EventListenerHandlers.java:565) ~[na:na]
	at sun.reflect.GeneratedMethodAccessor40.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
	at java.com.alibaba.jvm.sandbox.spy.Spy.spyMethodOnBefore(Spy.java:193) ~[na:na]
	at org.apache.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java) ~[dubbo-2.7.1.jar:2.7.1]
	at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:73) ~[dubbo-2.7.1.jar:2.7.1]
	at org.apache.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:57) ~[dubbo-2.7.1.jar:2.7.1]
	at org.apache.dubbo.common.bytecode.proxy0.sayHello(proxy0.java) ~[dubbo-2.7.1.jar:2.7.1]
	at sun.reflect.GeneratedMethodAccessor43.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
	at org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceBeanInvocationHandler.invoke(ReferenceAnnotationBeanPostProcessor.java:165) ~[dubbo-2.7.1.jar:2.7.1]
	at com.sun.proxy.$Proxy80.sayHello(Unknown Source) ~[na:na]
	at org.apache.dubbo.spring.boot.demo.consumer.bootstrap.DubboExternalizedConfigurationConsumerBootstrap.sayHello(DubboExternalizedConfigurationConsumerBootstrap.java:49) ~[classes/:na]
	at sun.reflect.GeneratedMethodAccessor42.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90) ~[spring-boot-actuator-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117) ~[spring-boot-actuator-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106) ~[spring-boot-actuator-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at com.alibaba.ttl.TtlRunnable.run(TtlRunnable.java:51) [sandbox_module_jar_6023817277835998588.jar:na]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.16.jar:9.0.16]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]

HTTP回放无法mock Filter,导致无法回放

目前系统在servlet之前,会 添加Filter,用于权限校验,然后spring访问上先进行filter操作,再进行servlet操作,在录制的时候没有问题,所有请求都能通过filter校验后进入servlet。
但是再回放的时候,因为我们是真实发起请求,导致请求先过filter,在这里就有可能出现日期过期校验,用户信息校验,因为这块在trace生成之前的调用,之前录制没有记录相应的操作,所以导致用例回放,在filter阶段过不去(因为环境不一样,filter中的方法需要mock才能正常进行下去)。

这个问题可能涉及到原有servlet切面的调整,以及入口方法判定之前,还需判定Filter。目前想不到好的解决方案,官方能提供一下解决方案吗?

javaSubInvokeBehaviors中使用通配符和不使用通配符录制结果有差异

条件:类A、B、C 位于包 com.xxx.service下,类A、B、C 中分别有方法A(m)、B(m)、C(m),A(m)先调用B(m)再调用C(m),B(m)和C(m)中分别是一次数据查询
javaSubInvokeBehaviors配置

"javaSubInvokeBehaviors":[
        {
            "classPattern":"com.xxx.service.*",
            "includeSubClasses":false,
            "methodPatterns":[
                "*"
            ]
        }
    ]

通过接口调用A(m)触发录制,查看录制结果中的subInvocations:有A(m)的mock、有两次数据查询的mock,没有B(m)、C(m)的mock

替换javaSubInvokeBehaviors配置

"javaSubInvokeBehaviors":[
        {
            "classPattern":"com.xxx.service.*",
            "includeSubClasses":false,
            "methodPatterns":[
                "*"
            ]
        },
        {
            "classPattern":"com.xxx.service.B",
            "includeSubClasses":false,
            "methodPatterns":[
                "*"
            ]
        },
        {
            "classPattern":"com.xxx.service.C",
            "includeSubClasses":false,
            "methodPatterns":[
                "*"
            ]
        }
    ]

重启插件再次录制,查看录制结果中的subInvocations:有A(m)的mock、有B(m)的mock、有C(m)的mock、有两次数据查询的mock

这个情况是为什么呢?难道com.xxx.service.*这个不是通配了ABC三个类?

ResultSet类型的响应反序列化失败

我对mysql的executeQuery方法进行了监控配置,方法返回的响应是ResultSet类型。ResultSet类型的响应反序列化失败,报[Error-1002]-hessian-deserialize-erroe的错。

Hession 序列化带有Clalendar属性并且有不同属性共享同一个对象的情况下有问题

Hession 序列化带有Clalendar属性并且有不同属性共享同一个对象的情况下有问题,这样的对象序列化之后再反序列化会出现IndexOutOfBoundException. 我debug了一下源码,发现是AbstractSerializer 类里的方法writeObject有问题,如下,如果参数obj是普通对象,那么在执行Object replace = writeReplace(obj)时得到的replace 就为空,是不会走到下面的逻辑里的,而如果obj是Calendar类型的时候,在执行if (out.addRef(obj))时已经往 _ref里面添加了这个Calendar对象本身,这时假设 _refCount是 i , 然后执行Object replace = writeReplace(obj)时会得到一个新的CalendarHandler对象用于替换Calendar对象本身,来被写进序列化流里, 因为replace不为空,这样后面的out.writeObject(replace);out.replaceRef(replace, obj);都会被执行, 结果是 _ref会多一个CalendarHandler对象,它的_refCount是 i+1. 这就导致后面的属性对象的_refCount比实际多1了,如果有多个属性共享一个对象,就会导致比实际多1的ref写进序列化流里。

@Override

public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException
{
if (out.addRef(obj)) {
return;
}

try {
  Object replace = writeReplace(obj);
  
  if (replace != null) {
    // out.removeRef(obj);

    out.writeObject(replace);

    out.replaceRef(replace, obj);

    return;
  }
} catch (RuntimeException e) {
  throw e;
} catch (Exception e) {
  // log.log(Level.FINE, e.toString(), e);
  throw new HessianException(e);
}

Class<?> cl = getClass(obj);

int ref = out.writeObjectBegin(cl.getName());

if (ref < -1) {
  writeObject10(obj, out);
}
else {
  if (ref == -1) {
    writeDefinition20(cl, out);

    out.writeObjectBegin(cl.getName());
  }

  writeInstance(obj, out);
}

}
我在本地改了一下代码,貌似解决了这个问题,有两种改法 , 方法一是将out.replaceRef(replace, obj);改成out.replaceRef(obj,replace),并将Hessian2Output 类的方法replaceRef(Object oldRef, Object newRef) 里的_refs.remove(oldRef);(1397行)改成 _refCount--; 方法二是将上面代码中的
if (out.addRef(obj)){
return;
}
挪到try块的最下面。我个人觉得方法一可能更好一点,因为方法二对于多个属性共享一个Calendar对象的情况,就不会往序列化流里写Ref而是将每个CalendarHadler序列化进流里。

这个IndexOutOfBound的问题虽解决了,但是我不知道这些改法会不会有副作用,因为Hession代码挺多的,我不可能穷尽各种测试案列,还请阿里大神多多指教

PS: 附上重现问题的代码

public class Dog implements Serializable {
private String name;
private Calendar birthDay;
private Calendar raiseDay;

    public String getName() {
        return name;
    }

    public Dog setName(String name) {
        this.name = name;
        return this;
    }

    public Calendar getBirthDay() {
        return birthDay;
    }

    public Dog setBirthDay(Calendar birthDay) {
        this.birthDay = birthDay;
        return this;
    }

    public Calendar getRaiseDay() {
        return raiseDay;
    }

    public Dog setRaiseDay(Calendar raiseDay) {
        this.raiseDay = raiseDay;
        return this;
    }

}

public static void main(String[] args) throws SerializeException {
    Calendar date=Calendar.getInstance();
    Dog dog=new Dog();
    dog.setName("Wang").setBirthDay(date).setRaiseDay(date);


    Object[] objects = new Object[]{dog};
    String requestSerialized2 = SerializerWrapper.hessianSerialize(objects);
    System.out.println(requestSerialized2);



    Object[] obj = SerializerProvider.instance().provide(Serializer.Type.HESSIAN).deserialize(requestSerialized2, Object[].class);

    System.out.println(obj);
}

反序列化问题

子调用记录下来的对象,如果对象包含有map<Integer,Object>的属性,虽然根据classload能拿到classtype,但是在回放是mock这个子调用返回是,hessian使用fastjson反序列化的时候由于:fastjson只接收(Integer,Object)的键值对:
image
image
导致反序列化报错.
以下是mock返回的结构抽象
image
以下是报错信息
image

repeater更新配置接口pushConfig获取_data参数不正确

通过 POST 请求 /sandbox/default/module/http/repeater/pushConfig 时,_data 参数值为:
QzA9Y29tLmFsaWJhYmEuanZtLnNhbmRib3gucmVwZWF0ZXIucGx1Z2luLmRvbWFpbi5SZXBlYXRlckNvbmZpZ5oGdXNlVHRsB2RlZ3JhZGUSZXhjZXB0aW9uVGhyZXNob2xkCnNhbXBsZVJhdGULcGx1Z2luc1BhdGgUaHR0cEVudHJhbmNlUGF0dGVybnMVamF2YUVudHJhbmNlQmVoYXZpb3JzFmphdmFTdWJJbnZva2VCZWhhdmlvcnMQcGx1Z2luSWRlbnRpdGllcxByZXBlYXRJZGVudGl0aWVzYEZGy+jUJxBOeg1eL2dyZWV0aW5nLiokBV4vZm9veUMwN2NvbS5hbGliYWJhLmp2bS5zYW5kYm94LnJlcGVhdGVyLnBsdWdpbi5kb21haW4uQmVoYXZpb3KTDGNsYXNzUGF0dGVybhFpbmNsdWRlU3ViQ2xhc3Nlcw5tZXRob2RQYXR0ZXJuc2EYaGVsbG8uR3JlZXRpbmdDb250cm9sbGVyRnIHW3N0cmluZwhncmVldGluZwNmb295YRhoZWxsby5HcmVldGluZ0NvbnRyb2xsZXJGcZAIZ3JlZXRpbmd7BGh0dHANamF2YS1lbnRyYW5jZQ5qYXZhLXN1Ykludm9rZXoEamF2YQRodHRw

repeater接收到的 _data 值为:QzA9Y29tLmFsaWJhYmEuanZtLnNhbmRib3gucmVwZWF0ZXIucGx1Z2luLmRvbWFpbi5SZXBlYXRlckNvbmZpZ5oGdXNlVHRsB2RlZ3JhZGUSZXhjZXB0aW9uVGhyZXNob2xkCnNhbXBsZVJhdGULcGx1Z2luc1BhdGgUaHR0cEVudHJhbmNlUGF0dGVybnMVamF2YUVudHJhbmNlQmVoYXZpb3JzFmphdmFTdWJJbnZva2VCZWhhdmlvcnMQcGx1Z2luSWRlbnRpdGllcxByZXBlYXRJZGVudGl0aWVzYEZGy jUJxBOeg1eL2dyZWV0aW5nLiokBV4vZm9veUMwN2NvbS5hbGliYWJhLmp2bS5zYW5kYm94LnJlcGVhdGVyLnBsdWdpbi5kb21haW4uQmVoYXZpb3KTDGNsYXNzUGF0dGVybhFpbmNsdWRlU3ViQ2xhc3Nlcw5tZXRob2RQYXR0ZXJuc2EYaGVsbG8uR3JlZXRpbmdDb250cm9sbGVyRnIHW3N0cmluZwhncmVldGluZwNmb295YRhoZWxsby5HcmVldGluZ0NvbnRyb2xsZXJGcZAIZ3JlZXRpbmd7BGh0dHANamF2YS1lbnRyYW5jZQ5qYXZhLXN1Ykludm9rZXoEamF2YQRodHRw

中间的 + 变成了空格。

@zhaoyb1990

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.