我有一个简单的方面是围绕一个方法做一些逻辑。我正在使用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初始化两次的内容。
但它说下面的内容(我使用的是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。我正在使用的组件组合之间是否存在任何已知的不兼容性,这会阻止上述构造函数绕过?
我在Spring应用程序中找到了使用AspectJ的Spring文档的详细说明。正如它所说的那样:“这确保Spring通过向AspectJ询问它来获取方面实例,而不是尝试自己创建实例。”,您可以从中找到示例:
<bean id="profiler" class="com.xyz.profiler.Profiler" factory-method="aspectOf">
<property name="profilingStrategy" ref="jamonProfilingStrategy"/>
</bean>
希望它能帮到你。
尝试使用其他编译器,如果您使用的是Ajc,请从IDE设置中将其更改为其他内容;它对我有用。