[英]How do I inject spring beans into non-managed beans in a Spring boot console application?
I've tried to follow the advice found here: https://www.baeldung.com/spring-inject-bean-into-unmanaged-objects我尝试遵循此处的建议: https : //www.baeldung.com/spring-inject-bean-into-unmanaged-objects
Only to find that it's compiling but not actually doing what it should.只是发现它正在编译但实际上并没有做它应该做的。 The autowired bean is not being set in the non-managed object.
未在非托管对象中设置自动装配的 bean。
@SpringBootApplication
@EnableSpringConfigured
public class SpringApp {
...
public class ApiClient {
private static String result = "not set";
//this would be called from another applicaiton written in a different language potentially.
public String apiInterface(String message) {
//This is where we're going to have to create Spring, where the languages 'join'.
SpringApplicationBuilder builder = new SpringApplicationBuilder(SpringApp.class);
builder.run();
System.out.println("Running legacy code...");
LegacyCode oldCode = new LegacyCode();
result = oldCode.doLegacyStuff("hello world");
return result;
}
}
...
@Configurable(preConstruction = true)
public class LegacyCode {
@Autowired
MessageSender sender; //let's pretend we Spring-fied this bit of code but not the Legacy code that uses it.
public String doLegacyStuff(String message) {
sender.send(message);
sender.close();
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
return "interupted";
}
return "ok";
}
}
That's the gist of the code.这就是代码的要点。 The full code is over at github here: https://github.com/AlexMakesSoftware/SpringConsoleApp3
完整代码在 github 上结束: https : //github.com/AlexMakesSoftware/SpringConsoleApp3
The output I get is:我得到的输出是:
Exception in thread "main" java.lang.NullPointerException
at demo.LegacyCode.doLegacyStuff(LegacyCode.java:13)
at demo.ApiClient.apiInterface(ApiClient.java:17)
at demo.DummyApplication.main(DummyApplication.java:7)
Which can only mean that the @Autowired MessageSender isn't getting injected.这只能意味着 @Autowired MessageSender 没有被注入。
Any ideas what I'm doing wrong?任何想法我做错了什么?
EDIT: I should point out that this is a simple example of a more complicated project to slowly integrate Spring into a legacy codebase.编辑:我应该指出,这是一个更复杂的项目的简单示例,用于将 Spring 慢慢集成到遗留代码库中。 I cannot simply 'make it all Spring', nor can I shift the location of Spring's initialisation because this legacy code gets called from another application (albeit a simpler one) written in another language but running in the JVM.
我不能简单地“全部使用 Spring”,也不能改变 Spring 初始化的位置,因为这个遗留代码是从另一个用另一种语言编写但在 JVM 中运行的应用程序(尽管是更简单的应用程序)调用的。 Yes, it's horrible, I know.
是的,这很可怕,我知道。
Problem is :问题是:
You are initializing your LegacyCode
using new
keyword.您正在使用
new
关键字初始化LegacyCode
。 Now problem is that LegacyCode
uses autowire
which works only for beans created using Spring.现在的问题是
LegacyCode
使用autowire
,它仅适用于使用 Spring 创建的 bean。 Hence NPE as @autowired
will not work with new
.因此,作为
@autowired
NPE @autowired
用于new
。
Solution :解决方案 :
You can mark your LegacyCode
with @Component
and then autowire
it in ApiClient
.您可以使用
@Component
标记您的LegacyCode
,然后在ApiClient
autowire
它。 This way MessageSender
bean will be created and will be available.这样
MessageSender
bean 将被创建并可用。
I hope this helps you and clears your doubt.我希望这可以帮助您并消除您的疑虑。 If not, let me know and I will help you solve it.
如果没有,请告诉我,我会帮助您解决。
Good luck and Happy coding!祝你好运,快乐编码!
@SpringBootApplication
annotation must be used in your main class. @SpringBootApplication
注解必须在你的主类中使用。 Thus move it from SpringApp
to DummyApplication
.因此将它从
SpringApp
移动到DummyApplication
。
Honestly, the easiest and cleanestway to solve this problem is to use ApplicationContextAware, like so:老实说,解决这个问题最简单、最干净的方法是使用 ApplicationContextAware,如下所示:
/** In a perfect world, this wouldn't exist. Maybe one day we can spring-ify everything and this won't need to. */
@Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
public static <T extends Object> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContext.context = applicationContext;
}
}
You can then call this in the constructor of your legacy code to retrieve what you need to like so:然后,您可以在遗留代码的构造函数中调用它来检索您需要的内容:
public LegacyCode() {
sender = SpringContext.getBean(MessageSender.class);
}
...and it works. ...它有效。
Ok, you now have a dependency on this SpringContext class but that will go in time if you Spring-ify the entire app and it's not so bad.好的,您现在依赖于这个 SpringContext 类,但是如果您对整个应用程序进行 Spring-ify 并且它不是那么糟糕,那么这将及时发生。
But if anyone has a better idea, please provide one and I'll review.但如果有人有更好的想法,请提供一个,我会审查。 Thanks.
谢谢。
I did not clone your project, just started to take a quick look at your POM in the browser.我没有克隆你的项目,只是开始在浏览器中快速查看你的 POM。 What immediately jumped at me was this:
立即跳到我身上的是这样的:
Your Maven POM is wrong.您的 Maven POM 是错误的。 You only preconfigure the AspectJ Maven Plugin in the
pluginManagement
section without ever actually declaring the plugin in the regular plugins
section.您只需在
pluginManagement
部分中预配置 AspectJ Maven 插件,而无需在常规plugins
部分中实际声明插件。 Ie, the plugin is not going to be used during your build.即,在您的构建期间不会使用该插件。
If after fixing that you are still having follow-up problems, I can take a second look.如果修复后你仍然有后续问题,我可以再看看。
Update: What I said before is true, but I also noticed some more oversights in your POM:更新:我之前说的是真的,但我也注意到你的 POM 中有更多的疏忽:
aspectjrt
on the classpath.aspectjrt
。spring-tx
on the dependency list, otherwise a class referred to by spring-aspects
will not be found.spring-tx
,否则找不到spring-aspects
引用的类。 Update 2: You can simply accept this pull request .更新 2:您可以简单地接受 此拉取请求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.