2012-05-08 25 views
12

我在Java中使用CXF实现了一个可用的SOAP Web服务。在服务器端计算方法执行的好方法是什么?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"); 
    } 

有没有更好的方式来做到这一点?我正在阅读关于方法低谷代理的执行情况,但我不知道如何做到这一点。

问题更新:

我GOOGLE了一下更多使用代理即找到我的路约于第二种方式:基于迄今为止的意见对这个问题

@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; 
     } 
    } 

,使用拦截器是比使用代理更好。我希望尽可能减慢Web服务的速度(这肯定会减慢速度),同时获得精确的性能测量。

+0

我觉得上面的机制很好。 –

+0

我推荐拦截器 – mtraut

回答

10

我不会推荐您使用InInterceptor和OutInterceptor的第一种方法 - 原因是没有干净的方式来存储starttime - 您有令牌将其存储在静态变量中的方法在一个线程中不起作用环境。

您使用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> 
+0

+1因为确实很有帮助。一个注意事项:如果您使用的是Spring Security,请注意它也是通过过滤器应用的,并且您需要注意过滤器的顺序以确保您对安全层进行计时(或不计时,具体取决于你想要什么)。 –

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,所以你可以让你的地图上唯一的密钥通过使用一个完全合格的类名你的拦截器。

+0

我试过了,它不起作用,在接收拦截器中使用message.put()存储的对象不能通过发送拦截器中的message.put使用。 –

+0

除了将请求开始时间信息存储在Message对象中,您可以推入ThreadLocal,然后在出站拦截器中检索它。 –

0

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

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

4

基于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"); 
     } 
    }  
} 
+0

我想你需要使用msg.getExchange()。put/remove? – jontejj

+0

谢谢你为我工作:) – Niamath