简体   繁体   English

如何在 Spring boot 控制台应用程序中将 spring bean 注入非托管 bean?

[英]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 中有更多的疏忽:

  • You use a non-existent AspectJ Maven Plugin version.您使用了一个不存在的 AspectJ Maven 插件版本。
  • For compile-time weaving, you need the AspectJ runtime aspectjrt on the classpath.对于编译时编织,您需要类路径上的 AspectJ 运行时aspectjrt
  • You need spring-tx on the dependency list, otherwise a class referred to by spring-aspects will not be found.依赖列表中需要spring-tx ,否则找不到spring-aspects引用的类。
  • Your test expects a result different from the actual "ok".您的测试期望结果与实际的“ok”不同。

Update 2: You can simply accept this pull request .更新 2:您可以简单地接受 此拉取请求

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM