英文:
@Autowired service from Spring Boot is null in WAR
问题
首先,我为给您带来不便道歉,我提供这个咨询是因为我已经花了好几天时间来解决这个问题,但是我找不到正确的解决方案。我有一个名为"fact-electronica-api"的项目,使用Swagger Codegen进行设计,通过它我可以得到执行REST调用的路径。一旦用户进行了这种调用,API项目会与另一个使用Spring Boot的核心项目进行通信,后者会与数据库执行查询。我的问题是,当我在API中对核心中定义的服务进行自动装配(Autowired)时,该服务始终为null。
请原谅我的英语,我来自乌拉圭,我希望您能理解我所面临的问题。为了更好地理解,我已经附上了一些图片。
- Fact electronica Api
- Factelec-core
通过该服务接收REST调用,并与核心进行通信。
核心中的服务
API对核心的依赖关系
Spring Boot初始化器,在您启动Wildfly中的EAR文件时,该项目会自动启动并进行相关设置。
如果有人能够指导我解决这个问题,我将不胜感激,提前感谢您。
英文:
first of all I apologize for the inconvenience, I make this consultation because I have spent days with this problem and I do not find the right solution. I have a project called fact-electronica-api designed using swagger codegen, through this I have the paths to perform REST calles. Once the user makes a call of this type the api project communicates with another project that has the core which use Spring Boot and performs the query with the database. The problem I have is that when I make from the api an autowired to the service defined in the core this is null.
Excuse my English, I am from Uruguay, I hope you understand the problem I am facing.For further understanding, I have attached images.
- Fact electronica Api
- Factelec-core
Service through which I receive the rest call and communicate with the core.
Service in core
Dependence on the api to the core
Spring Boot initializer, when you start the ear in wildfly, this project starts automatically and makes the relevant settings.
I would be grateful if someone could guide me in solving this problem, thank you in advance.
答案1
得分: 2
似乎 SolicitudApiServicelmpl
不是一个 Spring bean,因此 Spring 不会考虑对所有使用 @Autowired
注解的类字段进行依赖注入。尝试将该类标注为 @Service
,将类的实例添加到 Spring 上下文中,或者为 SolicitudApiServicelmpl
创建一个工厂,在其中生成 Spring 代理而不是一个简单的对象。
英文:
Seems like SolicitudApiServicelmpl
isn't a Spring bean, so Spring wouldn't consider all class's fields annotated with @Auowired
for dependency injection. Try to annotate this class as @Service
to add the class's instance to Spring context or create a factory for
SolicitudApiServicelmpl
which generates Spring proxy instead of a simple object.
答案2
得分: 1
你没有在创建 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);
// 现在 `solInfServ` 不再为空。
// ...
}
在 Spring 上下文中创建 SolicitudApiServicelmpl 实例
@Component
public class SomeClassWithSpringContext {
@Autowired private SolicitudApiServicelmpl solicitudService;
// 这样,@Autowired 应该在 `solicitudService` 实例中起作用。
}
或者使用上下文实例:
@Component
public class SomeClassWithSpringContext {
@Autowired private WebApplicationContext context;
public void someMethodOrSomewhere() {
SolicitudApiServicelmpl service = context.getBean(SolicitudApiServicelmpl.class);
// 这样,@Autowired 应该在 `service` 实例中起作用。
}
}
英文:
You are not creating SolicitudApiServicelmpl
spring instance.
Spring context (witch makes @Autowired
work) needs you to create that instance thought to Spring and not with a java native new SolicitudApiServicelmpl()
.
You can create that instance with a lot of techniques, here you have some of them:
Static context with "manual wired" (not recommended)
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.
// ...
}
Creating a SolicitudApiServicelmpl instance within the Spring context
@Component
public class SomeClassWithSpringContext {
@Autowired private SolicitudApiServicelmpl solicitudService;
// with this @Autowired should work in the `service` instance.
}
or with the context 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.
}
}
答案3
得分: 0
经过 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 和核心文件,并对 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);
我不知道这是否是理想的方法,但在我的情况下对我起作用,如果有人知道更好的方法,请随意告诉我,以便我可以改进代码。非常感谢!
英文:
after the help that was given to me by Nurio Fernández and Andrei Kovrov i was able to find out the right way to accomplish what i wanted to do.
First of all I integrate Spring into the api, and not only into the core, moving spring boot from the core to the api, resulting in this class in the 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;
}
By doing this I made sure I had a spring context in the api, which I could work with. When I start Spring from here I scan all the api and core files, performing the appropriate configuration of the beans.
After doing this, I needed to capture the context to recover the beans that are defined in the core, so I could work with the @Service class defined in the core. For this I created the following class:
> 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;
}
}
Once this was done, using the SolicitudApiServiceImpl I was able to do the following to invoke the bean I needed at a certain time:
Api - SolicitudApiServiceImpl.java
ApplicationContext cont = AppContextUtil.getContext();
SolicitudInformacionService solInfServ = cont.getBean(SolicitudInformacionService.class);
I don't know if this is the ideal way to do this, but in my case it worked for me, if there is someone who has a better way to do it feel free to tell me so I can improve the code. Thank you very much!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论