I have a spring boot project which already uses Spring AOP. For a new feature there is requirement to use cflow
pointcut, hence AspectJ has to be integrated.
I am successfully able to Compile Time Weave aspect into my project and can see the aspect running. I know loadtime weaving should be used when the project has lombok but i manage to run it using the following blog.
Here is the plugin in pom.xml for compile time weaving.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>11</complianceLevel>
<source>11</source>
<target>11</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>process-classes</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sources/>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
<forceAjcCompile>true</forceAjcCompile>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<phase>process-test-classes</phase>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sources/>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
<forceAjcCompile>true</forceAjcCompile>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/test-classes</weaveDirectory>
</weaveDirectories>
</configuration>
</execution>
</executions>
</plugin>
The role of the aspect is to query a database with intercepted jointpoint. For this I am trying to inject the Spring bean annotated with @Repository
into the aspect. As aspect is not a spring component I can not @Autowire repository in aspect class.
Repository Class
@Repository
public interface SampleRepository extends JpaRepository<Sample, String> {
}
Aspect Class
@Aspect
@Slf4j
public class SampleAspect {
}
Code already tried is
@Aspect
@Configurable
@Slf4j
public class SampleAspect {
}
@Bean
public SampleAspect sampleAspect(){
SampleAspect sampleAspect = Aspects.aspectOf(SampleAspect.class);
sampleAspect.setRepository(sampleRepository);
return sampleAspect;
}
In both of the above steps I am getting the error unsupported jointpoint cflow.
Initialization of bean failed; nested exception is org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException: contains unsupported pointcut primitive 'cflow'
Am I missing something here ? I need to inject a bean into plain old aspectj.
Making the POJO class you want to @Autowire
a dependency into @Configurable
is correct, also if that class happens to be a native AspectJ aspect. Making the native aspect a @Bean
or a @Component
is, however, a wrong and counter-productive approach, because that registers the aspect a second time as a Spring AOP aspect, which also explains the UnsupportedPointcutPrimitiveException ... cflow
problem.
Missing in this picture is the information that for @Configurable
, to work, you need AnnotationBeanConfigurerAspect
from spring-aspects
on the classpath. This is true both for the load-time and compile-time weaving scenarios. I.e., you want something like this in your POM:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
In the AspectJ Maven Plugin configuration, you then also need to declare spring-aspects
as an aspect library:
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
For more details, see this related answer.
Slightly off topic: I find the approach to use Maven Compiler and AspectJ Maven within a single module in subsequent phases, working on the same output directory, questionable, even though in your case it seems to work. I recommend to build an unwoven module version with Maven Compiler and Lombok in module A and then in module B weave aspects into the classes from A. All other modules should depend on B and not the intermediary A. In order to avoid A to be a transitive dependency, having the same classes in two different versions on the classpath, probably it makes sense to give A provided
scope when declaring it a dependency of B.