Web服务请求执行时间计算

时间:2012-05-08 18:19:15

标签: java cxf

我在Java中使用CXF实现了一个有效的SOAP Web服务。在服务器端计算方法执行的好方法是什么?

我现在所做的是使用了拦截器。我在我的InInterceptor(Phase.RECEIVE)中定义了public static long start。在我的OutInterceptor(Phase.SEND)中,我计算这样的响应时间:

    @Override
    public void handleMessage(Message arg0) {
        long stop = System.currentTimeMillis();
        long executionTime = stop - RequestStartInterceptor.start;
        System.out.println("execution time was ~" + executionTime + " ms");
    }

有更好的方法吗?我正在阅读有关通过代理方法的执行,但我不知道如何做到这一点。

问题更新:

我用谷歌搜索了一下,使用代理的第二种方式找到了我的方式,即:

@Aspect
public class MyServiceProfiler {



     @Pointcut("execution(* gov.noaa.nhc.*.*(..))")
         public void myServiceMethods() { }

         @Around("myServiceMethods()")
         public Object profile(ProceedingJoinPoint pjp) throws Throwable {
                 long start = System.currentTimeMillis();
                 System.out.println("Going to call the method.");
                 Object output = pjp.proceed();
                 System.out.println("Method execution completed.");
                 long elapsedTime = System.currentTimeMillis() - start;
                 System.out.println("Method execution time: " + elapsedTime + " milliseconds.");
                 return output;
         }
    }

根据对此问题的评论到目前为止,使用拦截器比使用代理更好。我希望尽可能减慢网络服务的速度(这肯定会减慢速度)并同时获得精确的性能测量。

4 个答案:

答案 0 :(得分:10)

我不建议您使用InInterceptor和OutInterceptor的第一种方法 - 原因是没有干净的方式来存储启动时间 - 您将令牌存储在静态变量中的方法将无法在线程环境中工作

您使用AOP的第二种方法非常好,但是它不会花费在CXF堆栈上花费的时间,它只会在呼叫到达您的服务层时提供时间。

我觉得最好的方法是使用servlet过滤器,你可以这样做:

public void doFilter(ServletRequest request,  ServletResponse response, FilterChain chain) throws IOException, ServletException {
    long start = System.currentTimeMillis();   
    chain.doFilter(request, response);
    long elapsedTime = System.currentTimeMillis() - start;
    System.out.println("Method execution time: " + elapsedTime + " milliseconds.");
}

并在您为CXFServlet提供映射的同一uri中提供映射。

这应该更清洁。如果您想要更精细的内容,可以将此方法与AOP方法相结合,以查找总体响应时间,然后将其分解为单个服务方法时间。

<servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/webservices/*</url-pattern>
</servlet-mapping> 
<filter-mapping>
    <filter-name>ExecTimeFilter</filter-name>
    <url-pattern>/webservices/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

答案 1 :(得分:5)

根据matts' answer我的研究结果如下。关键是在OutgoingInterceptor中你需要获取传入消息并从中获取开始时间戳。

public class IncomingInterceptor extends AbstractPhaseInterceptor<Message> {

    public IncomingInterceptor() {
        super(Phase.RECEIVE);
    }

    @Override
    public void handleMessage(Message msg) throws Fault {
        long startTime = System.currentTimeMillis();
        msg.put("my.timing.start", startTime);
    }
}


public class OutgoingInterceptor extends AbstractPhaseInterceptor<Message> {
    Logger log = LoggerFactory.getLogger(AbstractPhaseInterceptor.class);
    public OutgoingInterceptor() {
        super(Phase.SEND);
    }

    @Override
    public void handleMessage(Message msg) throws Fault {
        Long startTime = (Long)msg.getExchange().getInMessage().remove("my.timing.start");
        if (startTime != null) {
            long executionTime = System.currentTimeMillis() - startTime;
            log.info("execution time was ~" + executionTime + " ms");
        } else {
            log.info("timer not found");
        }
    }       
}

答案 2 :(得分:3)

我认为拦截器可以在Message对象中放置任意数据,因此您可以将开始时间存储在那里,然后将其取回以计算已用时间。

// in your receive interceptor
@Override
public void handleMessage(Message message) {
    long startTime = System.currentTimeMillis();
    message.put("my.timing.start", startTime);
}

// in your send interceptor
@Override
public void handleMessage(Message message) {
    Long startTime = message.remove("my.timing.start");
    if (startTime != null) {
        long executionTime = System.currentTimeMillis() - startTime;
        System.out.println("execution time was ~" + executionTime + " ms");
    }
}

CXF在消息映射中存储了一些自己的数据,但其大部分键都以org.apache.cxfjavax.xml.ws开头,因此您只需使用完全限定的类即可使映射键唯一你的一个拦截器的名称。

答案 3 :(得分:0)

  

计算服务器端的方法执行?

使用Interceptors您也在衡量CXF! 我的意思是Interceptors用于预先/后期处理与您的应用程序逻辑相关的消息。
使用Interceptor您的测量值包括CXF流量链的一部分 如果这是你想要的那么好。
但是如果你想测量你的方法执行,你应该把时间间隔与你的方法相关联。