【问题标题】:AOP using Spring Boot使用 Spring Boot 的 AOP
【发布时间】:2015-06-26 08:59:44
【问题描述】:

我在 STS 的 Spring Boot 启动项目中使用这个 Spring AOP 代码。在调试了一段时间后,我没有看到 AspectJ 语法有任何问题。 Maven 依赖项由 STS 为 AOP 启动项目生成。这段代码中是否有明显的遗漏,比如注释?另一个问题可能与 AOP 入门项目有关,也可能与我尝试在 @PostConstruct 方法中测试代码的方式有关。

我安装了 AJDT,但 STS 似乎应该在 IDE 中自己显示 AspectJ 标记。正确的 ?我没有看到标记。 STS 中包含哪些其他 AspectJ 调试选项? -Xlint 是我在 Eclipse/AJDT 中使用的。

StateHandler.java

public class StateHandler<EVENTTYPE extends EventType> {


private State<EVENTTYPE> state;

private Event<EVENTTYPE> event;

public StateHandler(State<EVENTTYPE> state, Event<EVENTTYPE> event) {
    this.state = state;
    this.event = event;
}


public void handle( Event<EVENTTYPE> event ){

    state = state.handle( event );

}

public State<EVENTTYPE> getState() {
    return state;
}

}

DeviceLogger .java

    @Aspect
    @Component
    public class DeviceLogger {

    private static Logger logger = Logger.getLogger("Device");


        @Around("execution(* com.devicemachine.StateHandler.*(..))")
        public void log() {
            logger.info( "Logger" );
        }
}

LoggerApplication.java

@SpringBootApplication
public class LoggerApplication {

    private static Logger logger = Logger.getLogger("Device");


    public static void main(String[] args) {

        SpringApplication.run(LoggerApplication.class, args);

    }

    @PostConstruct
    public void log(){
        DeviceState s = DeviceState.BLOCKED;
        StateHandler<DeviceEvent> sh = new StateHandler<DeviceEvent>( s,
                                            Event.block(DeviceEvent.BLOCKED, "AuditMessage") );
        sh.handle(Event.block(DeviceEvent.UNBLOCKED, "AuditMessage"));
    }
}

【问题讨论】:

    标签: spring-boot spring-aop


    【解决方案1】:

    有 3 个明显的错误和 1 个不那么明显的错误。

    1. 您的方面有误,破坏了正确的方法执行。使用环绕方面时,您必须始终返回 Object 并使用 ProceedingJoinPoint 并在其上调用 proceed()
    2. 您正在自己创建类的新实例,Spring 默认使用基于代理的 AOP,并且只会代理它知道的 bean。
    3. @PostConstruct 方法中,可能还没有创建代理并且没有任何内容被拦截
    4. 您需要使用基于类的代理才能启用,将spring.aop.proxy-target-class=true 添加到您的application.properties。默认情况下使用基于接口的 JDK 动态代理。

    修复方面

    您当前的方面不使用ProceedingJoinPoint,因此从不使用实际的方法调用。接下来,如果您现在有一个返回值的方法,它会突然返回null。因为您没有在ProceedingJoinPoint 上调用proceed

    @Around("execution(* com.devicemachine.StateHandler.*(..))")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        logger.info( "Logger" );
        return pjp.proceed();
    }
    

    创建一个bean来修复代理和@PostConstruct

    @SpringBootApplication
    public class LoggerApplication {
    
        private static Logger logger = Logger.getLogger("Device");
    
        public static void main(String[] args) {
            ApplicationContext context = SpringApplication.run(LoggerApplication.class, args);
            StateHandler<DeviceEvent> sh = context.getBean(StateHandler<DeviceEvent>.class);
            sh.handle(Event.block(DeviceEvent.UNBLOCKED, "AuditMessage"));
        }
    
        @Bean
        public StateHandler<DeviceEvent> auditMessageStateHandler() {
            return new StateHandler<DeviceEvent>(DeviceState.BLOCKED, Event.block(DeviceEvent.BLOCKED, "AuditMessage") );
        }
    
    }
    

    添加属性以启用类代理

    src\main\resources 中的application.properties 中添加以下属性,其值为true

    spring.aop.proxy-target-class=true
    

    【讨论】:

    • 我已经改变了外观,但像@Before 这样的东西也不起作用。此外,我正在考虑使用 AspectJ 进行编译时编织。不代理。这不可能吗?
    • 这是您的问题中的一个遗漏,您没有提及任何相关内容。如果你想使用编译时编织,你不需要@Component。您需要添加一个aop.xml 并在 maven(或 gradle)中正确设置编译时间编织。否则什么都不会编织。
    • 我已对代理进行了所有更改,但没有任何效果。
    • 那么您一定没有完成所有操作或没有使用最新的 Spring Boot 版本。你的类路径中确实有 AspectJ(或应该启用它的 spring-boot-starter-aop)。还要确保LoggerApplication 位于超级包中或与@Component 注释方面相同的包中,否则它不会被检测到并且什么也不做。 (或者您只需将其作为 @Bean 添加到您的配置中)。
    • 我不得不把它移到同一个包里。它工作。有@Bean 和包限制,我不得不更改代码以应用方面。
    猜你喜欢
    • 1970-01-01
    • 2018-10-27
    • 2016-08-15
    • 2017-12-26
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多