title: Spring AOP and AspectJ Load-Time Weaving: Around advice will be invoked twice for private methods
body: <p>I will use Spring AOP and AspectJ Load-Time Weaving to measure execution time of specific private/protected/public methods in my code.</p>
  
  <p>To do this I wrote following annotation with one I will annotate the methods which execution time should be measured:</p>
  
  <pre><code>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 {
  
  }
  </code></pre>
  
  <p>I also wrote the following Aspect:</p>
  
  <pre><code>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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; reporter != null) {
              LOGGER.info("Methods will be measured. Reporter [{}]", reporter.getClass().getCanonicalName());
          }
      }
  }
  </code></pre>
  
  <p>My Spring configuration is as follows:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;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"&gt;
  
      &lt;context:load-time-weaver aspectj-weaving="autodetect" /&gt;
  
      &lt;bean id="measuringAspect" class="at.scan.spring.aop.measuring.MeasuringAspect"
            factory-method="aspectOf"&gt;
          &lt;property name="enabled" value="${measuring.enabled}" /&gt;
          &lt;property name="reporter" ref="measuringReporterService" /&gt;
      &lt;/bean&gt;
  &lt;/beans&gt;
  </code></pre>
  
  <p>I have also placed in the directory <code>src/main/resources/META-INF</code> of my project the following <code>aop.xml</code>:</p>
  
  <pre><code>&lt;!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"&gt;
  &lt;aspectj&gt;
      &lt;weaver&gt;
          &lt;include within="at.scan..*" /&gt;
      &lt;/weaver&gt;
      &lt;aspects&gt;
          &lt;aspect name="at.scan.spring.aop.measuring.MeasuringAspect" /&gt;
      &lt;/aspects&gt;
  &lt;/aspectj&gt;
  </code></pre>
  
  <p>Also I added following Spring AOP and/or AspectJ specific dependencies to my POM:</p>
  
  <ul>
  <li>org.aspectj:aspectjrt:1.8.6 </li>
  <li>org.aspectj:aspectjtools:1.8.6</li>
  <li>org.springframework:spring-aop:4.1.6</li>
  </ul>
  
  <p>Furthermore I use <code>org.aspectj:aspectweaver:1.8.6</code> as Java Agent by starting of my Tomcat.</p>
  
  <p>Everything works fine for annotated public and protected methods but for annotated private methods the around advice of my aspect will by invoked twice and I don't know why.</p>