2015-12-11 40 views
0

我将使用Spring AOP和AspectJ加载时织入来测量代码中特定私有/受保护/公用方法的执行时间。Spring AOP和AspectJ加载时编织:围绕建议将被调用两次私有方法

要做到这一点,我写了下面的注释与一个我会标注其执行时间应测量方法:

package at.scan.spring.aop.measuring; 

import org.aspectj.lang.ProceedingJoinPoint; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

/** 
* Annotation for pointcut associated with the advice {@link MeasuringAspect#aroundAdvice(ProceedingJoinPoint)}. 
* @author ilyesve 
* @since 02.12.2015 
*/ 
@Target(value = ElementType.METHOD) 
@Retention(value = RetentionPolicy.RUNTIME) 
public @interface Measured { 

} 

我也写了在以下几个方面:

package at.scan.spring.aop.measuring; 

import org.apache.commons.lang3.builder.ReflectionToStringBuilder; 
import org.apache.commons.lang3.builder.ToStringStyle; 
import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

/** 
* An aspect which contains an advice to measure execution of methods that are annotated with {@link Measured} if it 
* is enabled. 
* After the execution of the annotated method the captured data over its execution will be forwarded to the 
* configured {@link MeasuringReporter}. 
* @author ilyesve 
* @since 02.12.2015 
*/ 
@Aspect 
public class MeasuringAspect { 

    /** LOGGER. */ 
    private static final Logger LOGGER = LoggerFactory.getLogger(MeasuringAspect.class.getPackage().getName()); 

    /** Determines whether the Around advice is enabled. Default is disabled. */ 
    private boolean enabled = false; 

    /** The {@link MeasuringReporter} to report the captured measuring data. */ 
    private MeasuringReporter reporter; 

    /** 
    * The Around advice which will be executed on calling of methods annotated with {@link Measured}. 
    * @param pjp the join point 
    * @throws Throwable on failure 
    * @return result of proceeding of the join point 
    */ 
    @Around("@annotation(Measured)") 
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { 
     Object result = null; 

     if (enabled && reporter != null) { 
      LOGGER.debug("Starting measuring of method '{}.{}()'...", 
        pjp.getSignature().getDeclaringTypeName(), 
        pjp.getSignature().getName()); 

      MeasuringDataDto measuringData = new MeasuringDataDto(pjp.getSignature(), pjp.getArgs()); 

      measuringData.setStartTs(System.currentTimeMillis()); 
      try { 
       measuringData.setResult(pjp.proceed()); 
      } catch (Throwable t) { 
       measuringData.setThrowable(t); 
      } 
      measuringData.setEndTs(System.currentTimeMillis()); 

      try { 
       reporter.report(measuringData); 
      } catch (Throwable t) { 
       LOGGER.error("Unable to report captured measuring data because of an error. MeasuringData [{}]", 
         ReflectionToStringBuilder.toString(measuringData, ToStringStyle.DEFAULT_STYLE, true, true), 
         t); 
      } 

      if (measuringData.getThrowable() != null) { 
       throw measuringData.getThrowable(); 
      } 

      result = measuringData.getResult(); 
     } else { 
      result = pjp.proceed(); 
     } 

     return result; 
    } 

    /** 
    * @param theEnabled if {@code true} the contained advice will be enabled, otherwise disabled 
    */ 
    public final void setEnabled(final boolean theEnabled) { 
     enabled = theEnabled; 
     if (enabled && reporter != null) { 
      LOGGER.info("Methods will be measured. Reporter [{}]", reporter.getClass().getCanonicalName()); 
     } 
    } 

    /** 
    * @param theReporter the {@link MeasuringReporter} to be used to report the captured measuring data about 
    *     execution of an method annotated with {@link Measured} 
    */ 
    public final void setReporter(final MeasuringReporter theReporter) { 
     reporter = theReporter; 
     if (enabled && reporter != null) { 
      LOGGER.info("Methods will be measured. Reporter [{}]", reporter.getClass().getCanonicalName()); 
     } 
    } 
} 

我的Spring配置是如下:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:aop="http://www.springframework.org/schema/aop" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context.xsd 
     http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop.xsd" 
     default-autowire="byName"> 

    <context:load-time-weaver aspectj-weaving="autodetect" /> 

    <bean id="measuringAspect" class="at.scan.spring.aop.measuring.MeasuringAspect" 
      factory-method="aspectOf"> 
     <property name="enabled" value="${measuring.enabled}" /> 
     <property name="reporter" ref="measuringReporterService" /> 
    </bean> 
</beans> 

我也放在目录我的项目以下aop.xml

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> 
<aspectj> 
    <weaver> 
     <include within="at.scan..*" /> 
    </weaver> 
    <aspects> 
     <aspect name="at.scan.spring.aop.measuring.MeasuringAspect" /> 
    </aspects> 
</aspectj> 

而且我添加以下Spring AOP和/或AspectJ的具体依赖于我的POM:

  • org.aspectj:aspectjrt:1.8.6
  • 组织.aspectj:aspectjtools:1.8.6
  • org.springframework:弹簧AOP:4.1.6

Furt我从Tomcat开始使用org.aspectj:aspectweaver:1.8.6作为Java代理。

一切工作正常注释的公共和受保护的方法,但对于注释的私有方法周围的建议,我的方面将通过调用两次,我不知道为什么。

+0

任何反应在我的答案?它能解决你的问题吗? –

回答

0

您的切入点表达式匹配连接点的主题具有@Measured注释的所有连接点。这包括均为方法执行方法调用类型连接点。您可能会看到在私有方法上执行两次的通知,因为您的私有方法是通过建议的类在本地调用的方法。如果你有方法调用建议的代码@Measured注释的其他可见性方法,你会看到这些方法的双重建议执行,以及不仅私人方法。解决方法是更改​​您的切入点表达式,以将连接点限制为method-executionmethod-call。我在你的情况的猜测是该法的执行本身,所以你的切入点表达式会变成这样:

@Around("execution(@Measured * *(..))") 

既然你不标注任何地方你的建议绑定,你甚至都不需要@annotation(Measured)部分。

在您的项目中设置新方面时,通过在aop.xml中启用-showWeaveInfo-verbose来检查编织过程总是一个好主意。

<weaver options="-showWeaveInfo -verbose"> 
... 
</weaver> 

那样会暴露在标准错误类似于这些日志消息(注意行号太):

[[email protected]] weaveinfo Join point 'method-call(void at.scan.spring.aop.measuring.MeasuredClass.test3())' in Type 'at.scan.spring.aop.measuring.MeasuredClass' (MeasuredClass.java:18) advised by around advice from 'at.scan.spring.aop.measuring.MeasuringAspect' (MeasuringAspect.java) 
[[email protected]] weaveinfo Join point 'method-execution(void at.scan.spring.aop.measuring.MeasuredClass.test3())' in Type 'at.scan.spring.aop.measuring.MeasuredClass' (MeasuredClass.java:27) advised by around advice from 'at.scan.spring.aop.measuring.MeasuringAspect' (MeasuringAspect.java) 
0
@Around("execution(* *(..)) && @annotation(Measured)") 
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { 
    ... 
} 

添加执行(* *(..))

相关问题