You need to enable JavaScript to run this app. Spring调用指定业务方法后创建Bean并触发AOP前置通知的实现咨询
优惠活动
大模型
产品
解决方案
定价
更多

Spring调用指定业务方法后创建Bean并触发AOP前置通知的实现咨询

问题根因

  1. 类内部调用方法不触发AOP:Spring AOP基于动态代理实现,只有通过代理对象调用被切方法时才会触发切面逻辑,同一个类内部直接调用方法走的是原对象this,绕过了代理,因此切面不生效。
  2. @Bean注解不符合时序要求:@Bean用于向Spring容器注册Bean实例,标注在方法上时Spring容器初始化阶段就会执行该方法获取返回值注册为Bean,和业务逻辑执行完成后再调用方法的需求冲突。

解决方案

不需要动态注册Bean,调整现有代码即可满足需求:

1. 调整业务服务类代码

移除generateSimulation方法上的@Bean注解,通过代理对象调用该方法触发AOP:

@RequiredArgsConstructor
@Service
public class Simulation_service {
    private final SimulationRepository simulationRepository;
    private final SimulationsValuesRepository simulationsValuesRepository;
    // 懒注入自身代理,避免循环依赖
    @Lazy
    private final Simulation_service selfProxy;

    public void Simulation(String N, Long P, Long I, Double R, Double M, Long Ti, Long Tm, Long Ts) {
        var simulation = Simulation.builder()
                .simulation_Name(N)
                .population_Size(P)
                .initial_infected_number(I)
                .how_many_one_infects(R)
                .mortality_Rate(M)
                .number_of_days_to_recovery(Ti)
                .number_of_days_to_Death(Tm)
                .simulation_time(Ts)
                .build();
        simulationRepository.save(simulation);
        // 调用代理对象方法触发AOP
        selfProxy.generateSimulation();
    }

    @MyAnnotation
    public void generateSimulation() {
        for (int i = 2; i <= simulationRepository.getById(1L).getSimulation_time(); i++) {
            var simulation_values = SimulationsValues.builder()
                    .healthy_prone_to_infection(simulationsValuesRepository.getById((long) i - 1)
                            .getHealthy_prone_to_infection() - simulationsValuesRepository.getById((long) i - 1)
                            .getNumber_of_infected() - simulationsValuesRepository.getById((long) i - 1)
                            .getRegained_health_and_immunity() - simulationsValuesRepository.getById((long) i - 1).getDead())
                    .regained_health_and_immunity(0L)
                    .number_of_infected((long) (simulationsValuesRepository.getById((long) i - 1)
                            .getNumber_of_infected() * simulationRepository.getById((long) i - 1).getHow_many_one_infects()))
                    .dead(0L)
                    .build();
            simulationsValuesRepository.save(simulation_values);
        }
    }
}

可选方案:通过AopContext获取代理

如果不想注入自身代理,可以修改启动类的@EnableAspectJAutoProxy注解开启代理暴露:

@EnableAspectJAutoProxy(exposeProxy = true)
@EntityScan("Terative.Entity")
@EnableJpaRepositories("Terative.Repositories")
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

然后把Simulation方法里的调用逻辑替换为:

((Simulation_service) AopContext.currentProxy()).generateSimulation();

验证逻辑

调整后业务执行时序完全符合要求:控制器调用Simulation方法 → 保存模拟数据到数据库 → 调用代理对象的generateSimulation方法 → 触发@Before切面写入第一天的模拟参数 → 执行generateSimulation循环写入后续天数的模拟数据。


内容的提问来源于stack exchange,提问作者Krzysiek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 09:36:02