You are right, I just noticed that TaskAspects not get triggered at all. I do not see any logs from TaskAspects. Can I use AspectJ inside spring-boot without any spring-aop? Thanks for taking a look and notifying. Much appreaciated.
Basically you just remove the @Component
annotations from the aspects you want use via AspectJ and add those aspects to file src/main/resources/org/aspectj/aop.xml (assuming you use Maven to build your project):
<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options="-verbose -showWeaveInfo">
<!-- only weave classes in our application-specific packages -->
<include within="com.spring.aspect.dynamicflow..*"/>
</weaver>
<aspects>
<aspect name="com.spring.aspect.dynamicflow.aspect.TaskAspects"/>
<aspect name="com.spring.aspect.dynamicflow.activity.AnnotationTask"/>
<aspect name="com.spring.aspect.dynamicflow.activity.ReviewTask"/>
</aspects>
</aspectj>
Then you start your application with -javaagent:/path/to/aspectjweaver.jar
, e.g.something like:
-javaagent:"c:\Users\me\.m2\repository\org\aspectj\aspectjweaver\1.9.4\aspectjweaver-1.9.4.jar"
You can also use both agents, AspectJ Weaver and Spring Instrument, together on the Java command line, e.g.
-javaagent:"c:\Users\me\.m2\repository\org\aspectj\aspectjweaver\1.9.4\aspectjweaver-1.9.4.jar" -javaagent:"c:\Program Files\Java\spring-framework-5.1.9.RELEASE\libs\spring-instrument-5.1.9.RELEASE.jar"
For your convenience and in order to have a example project for myself, I shared my working example in a GitHub repository. There is a branch for Spring AOP and another branch for AspectJ LTW. The diff between those branches looks like this:
diff --git a/src/main/java/com/spring/aspect/dynamicflow/Application.java b/src/main/java/com/spring/aspect/dynamicflow/Application.java
index 2a7021e..3a7636f 100644
--- a/src/main/java/com/spring/aspect/dynamicflow/Application.java
+++ b/src/main/java/com/spring/aspect/dynamicflow/Application.java
@@ -8,6 +8,16 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
+/**
+ * Run this from your IDE with
+ *
+ * a) either just -javaagent:/path/to/aspectjweaver.jar and without @EnableLoadTimeWeaving
+ *
+ * b) or with both -javaagent:/path/to/aspectjweaver.jar -javaagent:/path/to/spring-instrument.jar,
+ * either with or without @EnableLoadTimeWeaving. What benefit this has, I don't know.
+ *
+ * See also my extensive comment in Application class.
+ */
@SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
diff --git a/src/main/java/com/spring/aspect/dynamicflow/ApplicationConfig.java b/src/main/java/com/spring/aspect/dynamicflow/ApplicationConfig.java
index b4698e1..649a6ca 100644
--- a/src/main/java/com/spring/aspect/dynamicflow/ApplicationConfig.java
+++ b/src/main/java/com/spring/aspect/dynamicflow/ApplicationConfig.java
@@ -3,8 +3,34 @@ package com.spring.aspect.dynamicflow;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.context.annotation.EnableLoadTimeWeaving;
+import static org.springframework.context.annotation.EnableLoadTimeWeaving.AspectJWeaving.ENABLED;
+
+/**
+ * Remarks about AspectJ load-time weaving(LTW) in Spring:
+ *
+ * According to the Spring manual it should be enough to put spring-instrument.jar is on the JVM command line
+ * in combination with @EnableLoadTimeWeaving. Actually this does help Spring detect the AspectJ weaver,
+ * I can see the aspects loaded. But obviously this happens too late after the application classes are
+ * already loaded, so the aspects do not have any effect. I even added a static block
+ * static { logger.info("JobProcessImpl class was loaded"); } to JobProcessImpl in order to check it an
+ * the log output occurs right before the aspects are being activated, which of course is too late.
+ *
+ * LTW works if
+ *
+ * a) either I have both Java agents aspectjweaver.jar and spring-instrument.jar on JVM command line
+ * in combination with @EnableLoadTimeWeaving (but then it tries to weave twice, I can see errors in the log)
+ * or without @EnableLoadTimeWeaving (no errors in the log)
+ *
+ * b) or if I only use aspectjweaver.jar without @EnableLoadTimeWeaving.
+ *
+ * The latter is no surprise because AspectJ is independent of Spring and of course works even if Spring is
+ * unaware of its presence. But if I want to advertise its presence via @EnableLoadTimeWeaving, I do not
+ * understand why spring-instrument.jar is not enough, as described in the Spring manual.
+ */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.spring.aspect.dynamicflow")
+//@EnableLoadTimeWeaving(aspectjWeaving = ENABLED)
public class ApplicationConfig {}
diff --git a/src/main/java/com/spring/aspect/dynamicflow/activity/AnnotationTask.java b/src/main/java/com/spring/aspect/dynamicflow/activity/AnnotationTask.java
index 3c6d5c4..bbdd5b1 100644
--- a/src/main/java/com/spring/aspect/dynamicflow/activity/AnnotationTask.java
+++ b/src/main/java/com/spring/aspect/dynamicflow/activity/AnnotationTask.java
@@ -6,9 +6,7 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-@Component
@Aspect
public class AnnotationTask extends Task {
private static final Logger log = LoggerFactory.getLogger(AnnotationTask.class);
diff --git a/src/main/java/com/spring/aspect/dynamicflow/activity/ReviewTask.java b/src/main/java/com/spring/aspect/dynamicflow/activity/ReviewTask.java
index ece0ff6..f364da2 100644
--- a/src/main/java/com/spring/aspect/dynamicflow/activity/ReviewTask.java
+++ b/src/main/java/com/spring/aspect/dynamicflow/activity/ReviewTask.java
@@ -6,9 +6,7 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-@Component
@Aspect
public class ReviewTask extends Task {
private static final Logger log = LoggerFactory.getLogger(ReviewTask.class);
diff --git a/src/main/java/com/spring/aspect/dynamicflow/activity/Task.java b/src/main/java/com/spring/aspect/dynamicflow/activity/Task.java
index 3f1f9ce..93b3b73 100644
--- a/src/main/java/com/spring/aspect/dynamicflow/activity/Task.java
+++ b/src/main/java/com/spring/aspect/dynamicflow/activity/Task.java
@@ -6,9 +6,7 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-@Component
@Aspect
public abstract class Task {
private static final Logger log = LoggerFactory.getLogger(Task.class);
diff --git a/src/main/java/com/spring/aspect/dynamicflow/aspect/TaskAspects.java b/src/main/java/com/spring/aspect/dynamicflow/aspect/TaskAspects.java
index 3bff7b5..a09d9d6 100644
--- a/src/main/java/com/spring/aspect/dynamicflow/aspect/TaskAspects.java
+++ b/src/main/java/com/spring/aspect/dynamicflow/aspect/TaskAspects.java
@@ -5,9 +5,7 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-@Component
@Aspect
public class TaskAspects {
private static final Logger log = LoggerFactory.getLogger(TaskAspects.class);
diff --git a/src/main/resources/org/aspectj/aop.xml b/src/main/resources/org/aspectj/aop.xml
new file mode 100644
index 0000000..56342b4
--- /dev/null
+++ b/src/main/resources/org/aspectj/aop.xml
@@ -0,0 +1,15 @@
+<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
+<aspectj>
+
+ <weaver options="-verbose -showWeaveInfo">
+ <!-- only weave classes in our application-specific packages -->
+ <include within="com.spring.aspect.dynamicflow..*"/>
+ </weaver>
+
+ <aspects>
+ <aspect name="com.spring.aspect.dynamicflow.aspect.TaskAspects"/>
+ <aspect name="com.spring.aspect.dynamicflow.activity.AnnotationTask"/>
+ <aspect name="com.spring.aspect.dynamicflow.activity.ReviewTask"/>
+ </aspects>
+
+</aspectj>
BTW, I also quickly tried to get a combination of Spring AOP aspects (Task
subclasses) and AspectJ aspect (TaskAspects
, really a horrible name, why not TasksAspect
or TaskInterceptor
?). Even though the Spring manual and many users on mailing lists say, it is easy to combine both approaches even without extra configuration, I could not make it run the way I wanted. So for now I have no solution for that. Probably I just made a small mistake. I am an AspectJ expert, but actually never use Spring or Spring AOP, sorry.
Update: I forgot to mention that in my repository I also solved this problem I mentioned in my comment before:
If you really use AspectJ LTW scenario, your TaskAspects aspect gets triggered too often because within(com.spring.aspect.dynamicflow.activity.Task+)
in AspectJ not only intercepts method executions but also object and class initialisation, field access, method calls to other classes etc. So either you use AspectJ LTW and it prints too much or (...)
This is really true if you use that pointcut. The log output (time stamps, log channel info etc. cut off from log output) would be:
Handling the task aspects.
staticinitialization(com.spring.aspect.dynamicflow.activity.Task.<clinit>)
Handling the task aspects.
call(Logger org.slf4j.LoggerFactory.getLogger(Class))
Handling the task aspects.
set(Logger com.spring.aspect.dynamicflow.activity.Task.log)
Handling the task aspects.
staticinitialization(com.spring.aspect.dynamicflow.activity.AnnotationTask.<clinit>)
Handling the task aspects.
call(Logger org.slf4j.LoggerFactory.getLogger(Class))
Handling the task aspects.
set(Logger com.spring.aspect.dynamicflow.activity.AnnotationTask.log)
Handling the task aspects.
execution(com.spring.aspect.dynamicflow.activity.Task())
Handling the task aspects.
execution(com.spring.aspect.dynamicflow.activity.AnnotationTask())
Handling the task aspects.
execution(Object com.spring.aspect.dynamicflow.activity.AnnotationTask.task(ProceedingJoinPoint, JobContext))
Handling the task aspects.
get(Logger com.spring.aspect.dynamicflow.activity.AnnotationTask.log)
Handling the task aspects.
call(void org.slf4j.Logger.info(String))
AnnotationTask's task
Handling the task aspects.
get(Logger com.spring.aspect.dynamicflow.activity.AnnotationTask.log)
Handling the task aspects.
call(void org.slf4j.Logger.info(String))
Setting that the annotation is done.
Handling the task aspects.
get(TaskStatus com.spring.aspect.dynamicflow.entity.TaskStatus.COMPLETED)
Handling the task aspects.
call(void com.spring.aspect.dynamicflow.entity.JobContext.setAnnotationTaskStatus(TaskStatus))
Handling the task aspects.
call(Object org.aspectj.lang.ProceedingJoinPoint.proceed())
Handling the task aspects.
staticinitialization(com.spring.aspect.dynamicflow.activity.ReviewTask.<clinit>)
Handling the task aspects.
call(Logger org.slf4j.LoggerFactory.getLogger(Class))
Handling the task aspects.
set(Logger com.spring.aspect.dynamicflow.activity.ReviewTask.log)
Handling the task aspects.
execution(com.spring.aspect.dynamicflow.activity.Task())
Handling the task aspects.
execution(com.spring.aspect.dynamicflow.activity.ReviewTask())
Handling the task aspects.
execution(Object com.spring.aspect.dynamicflow.activity.ReviewTask.task(ProceedingJoinPoint, JobContext))
Handling the task aspects.
get(Logger com.spring.aspect.dynamicflow.activity.ReviewTask.log)
Handling the task aspects.
call(void org.slf4j.Logger.info(String))
ReviewTask's task
Handling the task aspects.
get(Logger com.spring.aspect.dynamicflow.activity.ReviewTask.log)
Handling the task aspects.
call(void org.slf4j.Logger.info(String))
Setting that the review is done.
Handling the task aspects.
get(TaskStatus com.spring.aspect.dynamicflow.entity.TaskStatus.IN_PROGRESS)
Handling the task aspects.
call(void com.spring.aspect.dynamicflow.entity.JobContext.setReviewTaskStatus(TaskStatus))
Handling the task aspects.
call(Object org.aspectj.lang.ProceedingJoinPoint.proceed())
Processing the job with jobid 11
I also cut out AspectJ weaver log messages (some of them errors) from in between the log lines. You see 29x "Handling the task aspects" instead of only 2x, which is why I changed the pointcut to within(com.spring.aspect.dynamicflow.activity.Task+) && execution(* task(..))
for you. Now the log output looks as expected:
Handling the task aspects.
execution(Object com.spring.aspect.dynamicflow.activity.AnnotationTask.task(ProceedingJoinPoint, JobContext))
AnnotationTask's task
Setting that the annotation is done.
Handling the task aspects.
execution(Object com.spring.aspect.dynamicflow.activity.ReviewTask.task(ProceedingJoinPoint, JobContext))
ReviewTask's task
Setting that the review is done.
Processing the job with jobid 11