为什么Spring会初始化我的Aspect两次?

时间:2016-09-25 17:04:56

标签: java spring-boot java-8 aspectj spring-aop

我有一个简单的方面是围绕一个方法做一些逻辑。我正在使用Spring Boot和AspjectJ。出于某种原因,该方面的构造函数被调用两次。

我的方面如下:

@Aspect
@Component
public class HandlerLoggingAspect {
  private static final Logger log = LoggerFactory.getLogger(HandlerLoggingAspect.class);

  public HandlerLoggingAspect() {
    log.info("Initialising HandlerLoggingAspect");
  }

  @Around("execution (* io.netty.handler.codec.ByteToMessageDecoder+.decode(*,*,*)) && args(ctx,byteBuf,outList)")
  public void interceptByteDecoding(ProceedingJoinPoint joinPoint, ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> outList) throws Throwable {
    setupMdcAroundJoinPoint(joinPoint, ctx);
  }

 //... rest of the code ...
}

方面运行正常,我期待它的方法,但由于某种原因Spring Boot初始化我的方面两次。 Intialising HandlerLoggingAspect消息在开始时出现两次。

2016-09-25 18:36:26.041 [main] DEBUG  Running with Spring Boot v1.4.0.RELEASE, Spring v4.3.2.RELEASE
2016-09-25 18:36:26.041 [main] INFO   No active profile set, falling back to default profiles: default
2016-09-25 18:36:29.891 [main] INFO   Initialising HandlerLoggingAspect
2016-09-25 18:36:29.892 [main] INFO   Initialising HandlerLoggingAspect

如果我从Aspect中删除@Component,则根本不会初始化它。

我的主要课程如下:

@ComponentScan
@Configuration
@EnableAutoConfiguration
@EnableAspectJAutoProxy
@SpringBootApplication
public class Launcher implements CommandLineRunner {
  private static final Logger log = LoggerFactory.getLogger(Launcher.class);

  public static void main(String[] args) {
    SpringApplication.run(Launcher.class, args);
  }

  @Override
  public void run(String... strings) throws Exception {
     //... logic performed by the class ...
  }
}

如果它有任何区别,这是我pom.xml中用于AspectJ编译时编织的插件配置。

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version>
        <aspectj-maven-plugin.version>1.8</aspectj-maven-plugin.version>
        <org.aspectj.version>1.8.9</org.aspectj.version>

        <org.springframework.boot.version>1.4.0.RELEASE</org.springframework.boot.version>
    </properties>

...
       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <proc>none</proc>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>${aspectj-maven-plugin.version}</version>
            <configuration>
                <complianceLevel>${java.version}</complianceLevel>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <showWeaveInfo/>
                <forceAjcCompile>true</forceAjcCompile>
                <sources/>
                <weaveDirectories>
                    <weaveDirectory>${project.build.directory}/classes</weaveDirectory>
                </weaveDirectories>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>       <!-- use this goal to weave all your main classes -->
                        <goal>test-compile</goal>  <!-- use this goal to weave all your test classes -->
                    </goals>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${org.aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>

当我分析其余的日志时,似乎只有一个实例实际上拦截了切入点。所以至少那是好的。

这种双重初始化的原因是什么?

** 更多信息 **

在Spring文档中,似乎有一些关于Aspects初始化两次的内容。

http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/aop.html#aop-proxying

然而它说下面的内容(我使用的是Spring 4.3.2):

  

从Spring 4.0开始,代理对象的构造函数不会   由于将创建CGLIB代理实例,因此再次调用两次   通过Objenesis。仅当您的JVM不允许构造函数时   绕过,您可能会看到双重调用和相应的调试   来自Spring的AOP支持的日志条目。

还写了以下内容,因为我使用的是@EnableAspectJAutoProxy注释,所以也应该适用,所以我知道我使用的是CGLIB代理:

  

要明确:使用proxy-target-class="true"   <tx:annotation-driven/><aop:aspectj-autoproxy/><aop:config/>   元素将强制使用CGLIB代理来处理所有这三个代理。

我使用的是Java 1.8。我使用的组件组合之间是否存在任何已知的不兼容性,这会阻止上述构造函数绕过?

2 个答案:

答案 0 :(得分:0)

我发现了有关将AspectJ与Spring应用程序一起使用的Spring文档的说明。就像它说的:“这确保Spring通过向AspectJ索要长宽比实例,而不是尝试自己创建实例来获取。”,您可以从中找到实例:

<bean id="profiler" class="com.xyz.profiler.Profiler" factory-method="aspectOf">
    <property name="profilingStrategy" ref="jamonProfilingStrategy"/>
</bean>

希望对您有帮助。

答案 1 :(得分:0)

尝试使用其他编译器,如果使用的是Ajc,请从IDE设置将其更改为其他名称;它对我有用。