我有一个使用Process
annotation定义的过程。该注释具有称为name
的属性。流程中包含任务。任务由另一个名为annotation的Task
定义。该注释具有属性processName
。我有一个generic process,其中name
为Generic。此过程的任务是Task1,Task2和Task3,所有这三个任务的processName
为Generic。我可以使用aspectj来将所有具有相同processName
的任务归为“''进程”''下吗?同样,在调用GenericProcess.execute时,也需要触发其中的所有任务。我正在尝试的代码当前在github中。感谢您的帮助。
也许您应该提到您的应用程序甚至没有运行,它退出并出现错误。通常,这几乎是一团糟。也许在将它发布到GitHub之前,您应该已经对其进行了测试并查看了日志。您还应该发布显示错误的日志输出,而不仅仅是说“它不起作用”。我不得不解决很多问题:
首先我删除(或重命名)了application.yml和logback.xml,因为我既没有您的H2数据库,您的项目也没有创建数据库,也没有看到任何日志输出控制台。当然,这些设置可能对您有用,对我而言它们却无效。
然后Application
中没有Process process = context.getBean(Process.class);
,这没有意义,因为Process
不是bean类,而是注释。您从other answer中获取了我的代码,进行了许多更改,然后再也无法解决。现在您的应用程序如下所示:
package com.spring.aspect.interfaces;
import com.spring.aspect.interfaces.process.GenericProcess;
import org.modelmapper.ModelMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
GenericProcess process = context.getBean(GenericProcess.class);
log.info("Generic process = {}", process);
process.execute();
}
}
在您的任务方面Task{1,2,3}
,切入点execution(public com.spring.aspect.interfaces.entity.Job com.spring.aspect.interfaces.process.GenericProcessImpl.process(..)) && args(context)
无效,因为既没有GenericProcessImpl.process(..)
方法也没有Context
参数。相反,您拥有的是没有参数的void execute()
方法。
此外,该方法仅来自已实现的GenericProcess
接口,即我们可以使用该接口代替特定的实现作为切入点。
如果您只想记录某些内容,我也看不到需要使用昂贵的@Around
建议,@Before
就足够了。那呢?
package com.spring.aspect.interfaces.task;
import com.spring.aspect.interfaces.annotation.Provided;
import com.spring.aspect.interfaces.annotation.Required;
import com.spring.aspect.interfaces.annotation.Task;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Task(name = "Task1", processName = "Generic")
@Required(values = { "param1" })
@Provided(values = { "param2" })
@Aspect
public class Task1 {
Logger logger = LoggerFactory.getLogger(Task1.class.getName());
@Before("execution(public void com.spring.aspect.interfaces.process.GenericProcess+.execute())")
public void task(JoinPoint thisJoinPoint) {
logger.info("{}", thisJoinPoint);
}
}
package com.spring.aspect.interfaces.task;
import com.spring.aspect.interfaces.annotation.Provided;
import com.spring.aspect.interfaces.annotation.Required;
import com.spring.aspect.interfaces.annotation.Task;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Task(name = "Task2", processName = "Generic")
@Required(values = { "param2" })
@Provided(values = { "param3" })
@Aspect
public class Task2 {
Logger logger = LoggerFactory.getLogger(Task2.class.getName());
@Before("execution(public void com.spring.aspect.interfaces.process.GenericProcess+.execute())")
public void task(JoinPoint thisJoinPoint) {
logger.info("{}", thisJoinPoint);
}
}
package com.spring.aspect.interfaces.task;
import com.spring.aspect.interfaces.annotation.Required;
import com.spring.aspect.interfaces.annotation.Task;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Task(name = "Task3", processName = "Generic")
@Required(values = { "param1", "param2" })
@Aspect
public class Task3 {
Logger logger = LoggerFactory.getLogger(Task3.class.getName());
@Before("execution(public void com.spring.aspect.interfaces.process.GenericProcess+.execute())")
public void task(JoinPoint thisJoinPoint) {
logger.info("{}", thisJoinPoint);
}
}
最后但并非最不重要的一点,在TaskAspect
中使用@annotation(com.spring.aspect.interfaces.annotation.Task)
,它将与带有@Task
批注的方法匹配。但是您有带有该批注的类,因此应改用@within(com.spring.aspect.interfaces.annotation.Task)
。
比通过Task
尝试将target(task)
注释绑定到参数要容易得多,而是只使用@within(task)
,即可同时获得注释匹配和参数绑定。
还记得我们将任务切入点从上面的@Around
更改为@Before
吗?对于@Before
,AspectJ不会生成方法,而是将代码直接编织到目标类中。您也不能依靠它来执行@Around
建议,因此我对上一个问题的回答是有效的,但有点不干净。但是,有一个特殊的切入点指示符adviceexecution()
。其目的是拦截其他方面(甚至同一方面)的执行建议。这更干净,更通用。在这种情况下,它甚至是唯一有效的方法。
最后,您使用的是args(proceedingJoinPoint)
,我不知道为什么。您是否尝试将截取点从截获的Task{1,2,3}
建议绑定到TaskAspect
建议?因为AspectJ将执行建议的联接点绑定到类型为JoinPoint
或ProceedingJoinPoint
的现有第一个参数,所以它将无法正常工作。也许它将绑定到第二个连接点参数。无论如何,我们不需要它,所以让我们将其删除。这真的是人为的,哇。
还有一件事,为什么要使用task.getClass().getName()
而不是新引入的@Task
批注属性来记录信息?
package com.spring.aspect.interfaces.aspect;
import com.spring.aspect.interfaces.annotation.Task;
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;
@Aspect
public class TaskAspect {
private static final Logger logger = LoggerFactory.getLogger(TaskAspect.class.getName());
@Around("@within(task) && adviceexecution()")
public Object groupTasks(ProceedingJoinPoint proceedingJoinPoint, Task task) throws Throwable {
logger.info("Generalizing the task aspects");
logger.info(" " + proceedingJoinPoint);
logger.info(" Task is {}", task.name());
logger.info(" Process name is {}", task.processName());
return proceedingJoinPoint.proceed();
}
}
现在终于,至少在使用-javaagent:"/path/to/aspectjweaver.jar"
参数启动应用程序的情况下,应用程序和方面才能再次正常工作。现在您应该看到这样的日志输出(删除AspectJ weaver输出和一些主要的记录器列):
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.3.RELEASE)
(...)
o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
c.spring.aspect.interfaces.Application : Started Application in 2.948 seconds (JVM running for 4.934)
c.spring.aspect.interfaces.Application : Generic process = com.spring.aspect.interfaces.process.GenericProcessImpl@25d0cb3a
c.s.aspect.interfaces.aspect.TaskAspect : Generalizing the task aspects
c.s.aspect.interfaces.aspect.TaskAspect : adviceexecution(void com.spring.aspect.interfaces.task.Task3.task(JoinPoint))
c.s.aspect.interfaces.aspect.TaskAspect : Task is Task3
c.s.aspect.interfaces.aspect.TaskAspect : Process name is Generic
com.spring.aspect.interfaces.task.Task3 : execution(void com.spring.aspect.interfaces.process.GenericProcessImpl.execute())
c.s.aspect.interfaces.aspect.TaskAspect : Generalizing the task aspects
c.s.aspect.interfaces.aspect.TaskAspect : adviceexecution(void com.spring.aspect.interfaces.task.Task1.task(JoinPoint))
c.s.aspect.interfaces.aspect.TaskAspect : Task is Task1
c.s.aspect.interfaces.aspect.TaskAspect : Process name is Generic
com.spring.aspect.interfaces.task.Task1 : execution(void com.spring.aspect.interfaces.process.GenericProcessImpl.execute())
c.s.aspect.interfaces.aspect.TaskAspect : Generalizing the task aspects
c.s.aspect.interfaces.aspect.TaskAspect : adviceexecution(void com.spring.aspect.interfaces.task.Task2.task(JoinPoint))
c.s.aspect.interfaces.aspect.TaskAspect : Task is Task2
c.s.aspect.interfaces.aspect.TaskAspect : Process name is Generic
com.spring.aspect.interfaces.task.Task2 : execution(void com.spring.aspect.interfaces.process.GenericProcessImpl.execute())
c.s.a.i.process.GenericProcessImpl : Generic Process execution is invoked