Java SpringAOP:为子类定义了切入点,但只调用了一个子类

Java SpringAOP:为子类定义了切入点,但只调用了一个子类,java,spring,aspectj,spring-aop,Java,Spring,Aspectj,Spring Aop,我使用方法对象进程(JobContext-JobContext)定义一个JobProcess使用名为JobProcessImpl的impl。 每当执行此JobProcessImpl.process方法时,我都希望使用多个子类进行监视。 我希望所有这些子类都被执行 spy类被定义为基类Task,用于查找JobProcessImpl.process调用 在输出中,我总是看到只有来自AnnotationTask的日志,而不是来自ReviewTask的日志 请让我知道,如果可能的话,问题是什么 我花了两

我使用方法
对象进程(JobContext-JobContext)定义一个JobProcess使用名为JobProcessImpl的impl。
每当执行此JobProcessImpl.process方法时,我都希望使用多个子类进行监视。
我希望所有这些子类都被执行

spy类被定义为基类
Task
,用于查找JobProcessImpl.process调用

在输出中,我总是看到只有来自AnnotationTask的日志,而不是来自ReviewTask的日志

请让我知道,如果可能的话,问题是什么

我花了两天时间试图通过以下各种帖子来解决这个问题

package com.spring.aspect.dynamicflow.activity;

import com.spring.aspect.dynamicflow.entity.JobContext;
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 );

    @Around ( "execution(public java.lang.Object com.spring.aspect.dynamicflow.process.JobProcessImpl.process(..)) " + "&& args(context)" )
    public Object task( JobContext context ) {
        log.info( "This is the base task and needs to overridden by the derived task for the job id: {} ", context.getJobId() );

        return  context;
    }
}
基类: 注释任务

package com.spring.aspect.dynamicflow.activity;

import com.spring.aspect.dynamicflow.entity.JobContext;
import com.spring.aspect.dynamicflow.entity.TaskStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class AnnotationTask extends Task {

    private static final Logger log = LoggerFactory.getLogger( AnnotationTask.class );

    @Override
    public Object task( JobContext context ) {
        log.info( "AnnotationTask's task" );

        /*
         * do some validation if annotation is completed or not
         */

        log.info( "Setting that the annotation is done." );
        context.setAnnotationTaskStatus( TaskStatus.COMPLETED );
        return "AnnotationTask Completed";
    }

复习任务

package com.spring.aspect.dynamicflow.activity;

import com.spring.aspect.dynamicflow.entity.JobContext;
import com.spring.aspect.dynamicflow.entity.TaskStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class ReviewTask extends Task {

    private static final Logger log = LoggerFactory.getLogger( ReviewTask.class );

    @Override
    public Object task( JobContext context ) {
        log.info( "ReviewTask's task" );

        /*
         * do some validation if annotation is completed or not
         */
        log.info( "not completing the review task due to some reason" );
        context.setReviewTaskStatus( TaskStatus.IN_PROGRESS );
        return "ReviewTask Not Completed";
    }
}
我希望通过TaskAspect监视这些任务的执行

package com.spring.aspect.dynamicflow.aspect;

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;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class TaskAspects {

    private static final Logger log = LoggerFactory.getLogger( TaskAspects.class );

    @Around( "within(com.spring.aspect.dynamicflow.activity.Task+) ")
    public Object handleTask( ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info( "Handling the task aspects." );
        log.info( "" + proceedingJoinPoint.getThis() );

        return proceedingJoinPoint.proceed();
    }

}
我也有一个枚举类(给出代码完成)

作业流程

package com.spring.aspect.dynamicflow.process;

import com.spring.aspect.dynamicflow.entity.JobContext;

public interface JobProcess {

    Object process( JobContext jobContext );
}
JobProcessImpl

package com.spring.aspect.dynamicflow.process;

import com.spring.aspect.dynamicflow.entity.JobContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class JobProcessImpl implements JobProcess {

    Logger logger = LoggerFactory.getLogger( JobProcessImpl.class );
    @Override
    public Object process( JobContext jobContext ) {
        logger.info( "Shouldn't get printed Processing the job with jobid {}", jobContext.getJobId() );
        return null;
    }
}


我一发布这篇文章,就试图用修改ReviewTask和AnnotationTask

@Override
    public Object task( ProceedingJoinPoint proceedingJoinPoint, JobContext context ) throws Throwable {
        log.info( "ReviewTask's task" );

        /*
         * do some validation if annotation is completed or not
         */
        log.info( "not completing the review task due to some reason" );
        context.setReviewTaskStatus( TaskStatus.IN_PROGRESS );
        return proceedingJoinPoint.proceed();
    }
这就解决了我的问题

你是对的,我只是注意到TaskAspect根本不会被触发。我没有看到来自TaskAspects的任何日志。我可以在没有任何spring aop的情况下在spring boot中使用AspectJ吗?感谢您的关注和通知。非常感激

基本上,您只需从希望通过AspectJ使用的方面中删除
@组件
注释,并将这些方面添加到文件src/main/resources/org/AspectJ/aop.xml中(假设您使用Maven构建项目):


. 有一个又一个。这些分支之间的差异如下所示:

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>
我还从日志行之间剪切AspectJ weaver日志消息(其中一些是错误)。您看到的是29x“处理任务方面”,而不是只有2x,这就是为什么我在(com.spring.aspect.dynamicflow.activity.task+)&&execution(*task(..)中为您将切入点更改为
。现在,日志输出看起来与预期的一样:

处理任务方面。
执行(对象com.spring.aspect.dynamicflow.activity.AnnotationTask.task(ProceedingJoinPoint,JobContext))
注释任务的任务
设置注释是否已完成。
处理任务方面的问题。
执行(对象com.spring.aspect.dynamicflow.activity.ReviewTask.task(ProceedingJoinPoint,JobContext))
回顾任务的任务
设置完成审查。
正在处理作业ID为11的作业

即使你说你已经解决了你的问题,让我问一下:你的
任务
是一个方面,
任务方面
(为什么复数?)也是一个方面。这有什么意义?此外,在SpringAOP中,一个方面不能拦截另一方面的方法。这仅在使用AspectJ时有效。那么,你能解释一下你在这里做什么,为什么你说这是有效的,让大家都能读到吗?您标记了问题
springaop
,您实际使用的是AspectJ吗?应该重新标记它
AspectJ
?Task是带有aspect on JobProcess的基类。TaskAspects是任务的第二级方面。我在TaskAspects中定义了更多切入点,为了简洁起见将其删除。希望它现在有意义。我不确定您的说法,“在SpringAOP中,一个方面不能截取另一个方面的方法。”因为这正是我在这里使用SpringAOP(使用SpringBootStarterAOP)所做的。通过使用spring boot starter aop,spring aop标签应该可以工作。另外,我使用的是spring boot版本2.1.8.RELEASE,这是截至今天的最新版本。这可能是它成功的原因吗?嗯,我复制了你所有的代码,让它编译,根据你的答案和我的评论添加了修复程序。现在当然
AnnotationTask
ReviewTask
与SpringAOP一起按预期工作。但是,
TaskAspects
肯定不会运行,因为正如我所说的,aspects无法在SpringAOP中拦截其他方面。我检查了日志输出以便确认。很抱歉重复我的话,但如果它对您有效,您必须使用AspectJ而不是SpringAOP。你是吗?您知道,对于加载时编织和aop.xml,而且,
JobProcessImpl.process(…)
中的“不应该打印”没有意义,因为日志行当然会被打印,因为您的(固定)方面建议调用
contrace()
。您忘了提到您还需要相应地更改抽象基本方面的方法签名,以使其成为公共对象任务(ProceedingJoinPoint ProceedingJoinPoint,JobContext context)抛出的Throwable
。否则,这两个具体的子方面无法正确覆盖advice方法,代码将无法编译。非常感谢。我拿出了git回购协议并在本地运行。非常感谢。现在我可以看到
处理任务方面。
正在打印。非常感谢你的帮助+1我刚刚更新了我的答案,解释了为什么以及如何在
taskapects
中更改切入点,并显示了前后控制台日志。
-javaagent:"c:\Users\me\.m2\repository\org\aspectj\aspectjweaver\1.9.4\aspectjweaver-1.9.4.jar"
-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"
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>