2012-05-08 14 views
12

Tengo un servicio web SOAP activo implementado con CXF en Java. ¿Cuál sería una buena forma de calcular la ejecución del método en el lado del servidor?Cálculo de tiempo de ejecución de solicitud de servicio web

Lo que he hecho por ahora es utilizar interceptores. Definí public static long start en mi InInterceptor (Phase.RECEIVE). Y en mi OutInterceptor (Phase.SEND) calculo el tiempo de respuesta como esta:

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

¿Hay una mejor manera de hacer esto? Estaba leyendo acerca de la ejecución del método a través del proxy, pero no tengo ni idea de cómo hacerlo.

actualización Pregunta:

Googled un poco más de un encontrar mi camino cerca de la segunda manera es decir, utilizando el Proxy:

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

Basándose en los comentarios a esta pregunta hasta el momento, el uso de interceptores es mejor que usar proxy. Estoy buscando reducir la velocidad del servicio web lo menos posible (esto ciertamente lo ralentizará) y al mismo tiempo obtener una medición precisa del rendimiento.

+0

Creo que el mecanismo anterior es bueno. –

+0

Yo recomendaría los interceptores, también – mtraut

Respuesta

10

No recomendaría su primer acercamiento al uso de InInterceptor y OutInterceptor - la razón es que no hay una manera limpia de almacenar el tiempo de inicio - el enfoque que tiene el token para almacenarlo en una variable estática no funcionará en un subproceso ambiente.

Su segundo método para usar el AOP es muy bueno, sin embargo, no le dará el tiempo que pasa en la pila de CXF, solo proporcionará el tiempo una vez que la llamada llega a su nivel de servicio.

me siento el mejor enfoque va a utilizar un filtro de servlet, se puede hacer esto:

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."); 
} 

y proporcionar la asignación al mismo URI en el que ha proporcionado la asignación para CXFServlet.

Esto debería ser mucho más limpio. Si desea algo aún más granular, puede combinar este enfoque con su enfoque de AOP para encontrar el tiempo de respuesta global y luego descomponerlo en los tiempos del método de servicio individual.

<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 por ser _muy_ útil de hecho. Una nota: si está utilizando Spring Security, tenga en cuenta que también se aplica a través de un filtro y que debe tener cuidado con el orden de los filtros para asegurarse de que también está cronometrando la capa de seguridad (o no, dependiendo de en lo que quieras). –

3

creo interceptores pueden poner datos arbitrarios en el objeto Message, para que pueda almacenar la hora de inicio y más tarde no recuperarlo a cabo para calcular el tiempo transcurrido.

// 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"); 
    } 
} 

tiendas CXF algunos de sus propios datos en el mapa de mensajes, pero la mayoría de sus claves comienzan con org.apache.cxf o javax.xml.ws, por lo que se acaba de hacer su mapa de teclado único usando el nombre de clase completo de una de tus interceptores

+0

Lo intenté, y no funcionará, los objetos almacenados usando message.put() en el interceptor de recepción no están disponibles a través de message.put en send interceptor. –

+0

En lugar de almacenar información de tiempo de inicio de solicitud en el objeto de Mensaje, puede insertar en ThreadLocal y luego recuperarlo en el interceptor de salida. –

0

calcular la ejecución del método en el lado del servidor?

¡Usando Interceptors está midiendo CXF también!
Me refiero a Interceptors se utilizan para pre/post procesar un mensaje en relación con su lógica de aplicación.
Usando el Interceptor sus medidas incluyen partes de la cadena de flujo CXF.
Si esto es lo que quieres, entonces está bien.
Pero si quiere medir la ejecución de su método, debe poner el intervalo de tiempo en relación con su método.

4

Basado en matts' answer Trabajé siguiendo. La clave es que en OutgoingInterceptor necesita recibir un mensaje entrante y obtener la marca de tiempo inicial a partir de eso.

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

Creo que necesitas usar msg.getExchange(). Put/remove? – jontejj

+0

Gracias funcionó para mí :) – Niamath

Cuestiones relacionadas