【问题标题】:@Autowired service from Spring Boot is null in WAR来自 Spring Boot 的 @Autowired 服务在 WAR 中为空
【发布时间】:2021-01-31 08:02:37
【问题描述】:

首先,对于给您带来的不便,我深表歉意,我进行此咨询是因为我已经花了几天时间来解决这个问题,但我没有找到正确的解决方案。我有一个使用 swagger codegen 设计的名为 fact-electronica-api 的项目,通过它我有执行 REST 调用的路径。一旦用户进行这种类型的调用,api 项目就会与另一个项目进行通信,该项目具有使用 Spring Boot 的核心并使用数据库执行查询。我遇到的问题是,当我从 api 自动连接到核心中定义的服务时,这是 null。

对不起,我来自乌拉圭,希望你能理解我所面临的问题。为了进一步理解,我附上了图片。

  • Fact electronica API

  • Factelec 核心

我通过它接收其余调用并与核心通信的服务。

核心服务

对核心的依赖api

Spring Boot初始化器,当你在wildfly中启动ear时,这个项目会自动启动并进行相关设置。

如果有人能指导我解决这个问题,我将不胜感激,提前谢谢你。

【问题讨论】:

    标签: java spring spring-boot rest swagger


    【解决方案1】:

    似乎SolicitudApiServicelmpl 不是 Spring bean,因此 Spring 不会考虑使用 @Auowired 注释的所有类字段进行依赖注入。尝试将此类注释为 @Service 以将该类的实例添加到 Spring 上下文或为 SolicitudApiServicelmpl 生成 Spring 代理而不是简单对象。

    【讨论】:

    • 您好,非常感谢您的回复。尝试使用注解@Service,但还是检测不到,能否再帮我一点忙?
    • 您的SolicitudApiServicelmpl 带有@RequestScoped 注释。我不是 JEE 方面的专家,但我可以假设对象生命周期是 per request。 .此外,它不是一个对象,它是一个代理(可能是 JDK 代理)。您使用此注释对服务进行注释的目的是什么?
    • 是的,它有那个符号,但为了证明你的建议,我把它拿出来了。实际上,注释是在创建服务器存根时由 swagger 插入的,我怀疑是留下还是取出。
    • 它是否可以同时使用@Service 和不使用@RequestScoped?
    • 不,我调试它,solInfServ 为空。
    【解决方案2】:

    您没有创建SolicitudApiServicelmpl spring 实例。

    Spring 上下文(女巫使 @Autowired 工作)需要您创建考虑到 Spring 的实例,而不是使用 java 本机 new SolicitudApiServicelmpl()。

    您可以使用很多技术来创建该实例,这里有一些:

    带有“手动接线”的静态上下文(不推荐)

    public class Main {
    
       private static ConfigurableApplicationContext context;
    
       public static void main(String[] args) {
          context = SpringApplication.run(MyApplication.class, args);
       }
    
       public static ConfigurableApplicationContext getContext() {
          return context;
       }
    
    }
    
    public class SolicitudApiServicelmpl {
    
       private ConfigurableApplicationContext context = Main.getContext();
    
       private SolicitudInformacionService solInfServ = context.getBean(SolicitudInformacionService.class);
    
       // Now `solInfServ` is not null anymore.
       // ...
    }
    

    在 Spring 上下文中创建 SolicitudApiServicelmpl 实例

    @Component
    public class SomeClassWithSpringContext {
    
       @Autowired private SolicitudApiServicelmpl solicitudService;
       // with this @Autowired should work in the `service` instance.
    
    }
    

    或使用上下文实例:

    @Component
    public class SomeClassWithSpringContext {
    
       @Autowired private WebApplicationContext context;
    
       public void someMethodOrSomewhere() {
          SolicitudApiServicelmpl service = context.getBean(SolicitudApiServicelmpl.class);
          // with this @Autowired should work in the `service` instance.
       }
    
    }
    

    【讨论】:

    • 您好,非常感谢您的回复,我尝试了两种解决方案。第二种,实例的一种,因为核心不依赖api我无法导入类 SolicitudApiServicelmpl。在第一个中,由于某种原因,上下文为空。难道是因为core延伸到了SpringBootServletInitializer?
    【解决方案3】:

    在 Nurio Fernández 和 Andrei Kovrov 给予我的帮助后,我找到了完成我想做的事情的正确方法。

    首先我将Spring集成到了api中,而不仅仅是进入了核心,将spring boot从核心移动到了api中,从而在api中产生了这个类。

    Api - ApplicationInitializer.java

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @SpringBootApplication(scanBasePackages = {"com.factelcore.*","uy.com.antel.fact.*"})
    @EnableJpaRepositories("com.factelcore.repository")
    public class ApplicationInitializer extends SpringBootServletInitializer {
        
        public static void main(String[] args){
            SpringApplication.run(ApplicationInitializer.class,args);
        }
        
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
            return application.sources(applicationClass);
        }
     
        private static Class<ApplicationInitializer> applicationClass = ApplicationInitializer.class;
        
    }
    

    通过这样做,我确保我在 api 中有一个 spring 上下文,我可以使用它。当我从这里启动 Spring 时,我会扫描所有 api 和 core 文件,对 bean 执行适当的配置。

    完成此操作后,我需要捕获上下文以恢复核心中定义的 bean,因此我可以使用核心中定义的 @Service 类。为此,我创建了以下类:

    Api - AppContextUtil.java

    @Component
    public class AppContextUtil implements ApplicationContextAware {
        
        @Autowired 
        private WebApplicationContext context;
    
        private static ApplicationContext appContext;
        
        @PostConstruct
        public void init() {
            if (context != null) {
                setApplicationContext(context);         
            }
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            AppContextUtil.appContext = applicationContext;
        }
    
        public static ApplicationContext getContext() {
            return appContext;
        }
    }
    

    完成后,使用 SolicitudApiServiceImpl 我可以执行以下操作来调用我在特定时间需要的 bean:

    Api - SolicitudApiServiceImpl.java

    ApplicationContext cont = AppContextUtil.getContext();
    SolicitudInformacionService solInfServ = cont.getBean(SolicitudInformacionService.class);
    

    我不知道这是否是执行此操作的理想方法,但就我而言,它对我有用,如果有人有更好的方法,请随时告诉我,以便我改进代码.非常感谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-08
      • 1970-01-01
      • 1970-01-01
      • 2020-10-11
      • 2018-06-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多