【问题标题】:Spring AOP not working in main class with Spring Boot Project?Spring AOP 不能在 Spring Boot Project 的主类中工作?
【发布时间】:2017-10-12 13:09:20
【问题描述】:

我正在尝试在 spring boot 项目中使用 spring aop。我不知道为什么我没有在主课的连接点得到建议。 AOP 在服务类中运行良好。代码如下。

SpringBootWithAOP.java

package com.example.demo;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.example.demo.services.SayHelloService;

@SpringBootApplication
public class SpringBootWithAOP {

    @Autowired
    SayHelloService service;

    String message;
    static String name;

    public static void main(String[] args) {
        name="George";
        SpringApplication.run(SpringBootWithAOP.class, args);
    }

    @PostConstruct
    public void init() {
        service.message(name);
    }
}

SayHelloService.java

package com.example.demo.services;
import org.springframework.stereotype.Service;

@Service
public class SayHelloService {
    public String message(String name) {
        System.out.println("Hello Dear User - " + name );
        return "Hello Dear User - " + name ;
    }
}

MasterLoggerAspect.java

package com.example.demo.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MasterLoggerAspect {
    @Before("execution(* com.example.demo.services.*.*(..) )")
    public void doForEveryServicesMethod(JoinPoint jp){
        System.out.println("hurray! In class: " + jp.getSignature().getDeclaringTypeName() + " - before method: " + jp.getSignature().getName());
    }
    //this advice is not getting weaved
    @Before("execution(* com.example.demo.*.*(..)) " )
    public void doForEveryMainClassMethod(JoinPoint jp){
        System.out.println("hurray! In class: " + jp.getClass() + " - before method: " + jp.getSignature().getName());
    }
}

pom.xml 在依赖项中有 spring-boot-starter-aop

有人能指出问题出在哪里吗?

输出 -

hurray! In class: com.example.demo.services.SayHelloService - before method: message
Hello Dear User - George

此处提供代码:https://github.com/samshers/46692518/

【问题讨论】:

    标签: spring spring-boot aop aspectj spring-aop


    【解决方案1】:

    您需要在服务包之后使用两个点表示法 (..) 以包含子包。一旦你开始使用* com.example.demo..*.*(..),除了main 和带有@PostConstruct 标记的方法之外的所有Spring 托管bean 都将被记录。根据PostConstruct JavaDoc,此方法必须在类投入使用之前调用。

    @Component
    @Aspect
    public class MasterLoggerAspect {
    
        @Pointcut("execution(* com.example.demo..*.*(..))")
        public void logForAllMethods(){}
    
        @Before("execution(* com.example.demo.services.*.*(..) )")
        public void doForEveryServicesMethod(JoinPoint jp){
            System.out.println("hurray! In class: " + jp.getSignature().getDeclaringTypeName() + " - before method: " + jp.getSignature().getName());
        }
    
        @Before("execution(* com.example.demo..*.*(..) )" )
        public void doForEveryMainClassMethod(JoinPoint jp){
            System.out.println("hurray! In class: " + jp.getClass() + " - before method: " + jp.getSignature().getName());
        }
    }
    

    如果在 Spring Boot 主类中添加 @Component 注释并将其自动装配到另一个类,那么在 SpringBootWithAOP 类中调用的任何方法都将被记录。例如,

    @SpringBootApplication
    @Component
    public class SpringBootWithAOP {
    
        @Autowired
        SayHelloService service;
    
        String message;
        static String name;
    
        public static void main(String[] args) {
            name="George";
            SpringApplication.run(SpringBootWithAOP.class, args);
        }
    
        public void sayHello() {
            System.out.println("888888");
        }
    
        @PostConstruct
        public void init() {
            service.message(name);
        }
    }
    

    更改为SayHelloService 类,

    @Service
    public class SayHelloService {
    
        @Autowired
        SpringBootWithAOP aop;
    
        public String message(String name) {
            System.out.println("Hello Dear User - " + name );
            aop.sayHello();
            return "Hello Dear User - " + name ;
        }
    }
    

    这是记录的消息,

    hurray! In class: class org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint - before method: message
    hurray! In class: com.example.demo.services.SayHelloService - before method: message
    Hello Dear User - George
    hurray! In class: class org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint - before method: sayHello
    888888
    

    【讨论】:

    • 很好的答案因陀罗
    • "并将其自动连接到另一个类,然后在 SpringBootWithAOP 类中调用的任何方法都将被记录" - 这听起来不错。但是main 方法和@PostConstruct 方法(init)仍然不是连接点。我想知道如何实现这一目标。我想记录调用这些方法的时间。
    • 你完全正确!我应该使用这两种方法不是联合点的限定词。如果您查看 PostConstruct 的 Java 文档,您会注意到在调用此方法之前类不会投入使用。
    • gr8。为您的回复欢呼。同样,即使public static void main(String[] args) {...} 也无法通过 AOP 进行跟踪。对吗?
    • 根本不常见。在我看来,应该避免。
    【解决方案2】:

    “Spring AOP 当前仅支持方法执行连接点(建议在 Spring beans 上执行方法)。”

    我不相信应用程序入口点是一个 bean。

    查看CommandLineRunner 接口并实现您自己的覆盖run 的类。一旦bean 初始化,命令行运行程序就会运行。

    【讨论】:

    • Gr8 答案。我尝试在主课上添加@Component anno。希望它会奏效。但没有运气。这是一个限制还是我需要做更多的事情。我也想在主类上进行 AOP 日志记录。
    • 编辑了答案。尝试创建一个实现上述接口的新类,如果测试有效,则应执行切入点。
    • gr8。谢谢回复。我更担心通过 AOP 跟踪 public static void main(String[] args) {...}。有什么方法可以实现吗?
    猜你喜欢
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    • 2017-03-23
    相关资源
    最近更新 更多