非Spring管理的类中,Spring自动装配无法工作

44

我有一个类(Class ABC),通过调用构造函数来实例化。Class ABC又有一个帮助类(Class XYZ),使用自动装配进行注入。

我们的应用程序是基于Spring MVC构建的,在服务器启动时没有看到任何异常。

但是我仍然发现Class XYZ为null。这是否是因为Class ABC没有由Spring容器实例化?

在这种情况下,我该如何使用自动装配?

谢谢。


我相信你不能自动装配不由Spring管理的bean。你需要通过其他方式获得XYZ实例的引用。如果它是一个辅助类,可以使XYZ的方法静态化并使用类名调用它们。这就是我所做的。 - dharam
请参考 https://github.com/ahmedbhaila/non-managed-beans,我已经尝试过并且它可以工作。 - Sam
11个回答

53

您可以使用此方法在非Spring Bean类中使用Spring Bean。

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextUtils implements ApplicationContextAware {
     
      private static ApplicationContext ctx;
     
      @Override
      public void setApplicationContext(ApplicationContext appContext) {
        ctx = appContext;
      }
     
      public static ApplicationContext getApplicationContext() {
        return ctx;
      }
}

现在你可以通过调用getApplicationContext()方法来获取applicationcontext对象。

通过applicationcontext,你可以像这样获取Spring Bean对象:

ApplicationContext appCtx = ApplicationContextUtils.getApplicationContext();
String strFromContext = appCtx.getBean(beanName, String.class);

Spring容器将注入该对象。 - Ashish Chaurasia
15
在我的情况下,我需要在 ApplicationContextUtils 上添加 @Component 注解,否则在调用 ApplicationContextUtils .getApplicationContext() 方法时会返回 null。 - bluearrow
太棒了的解决方案! - rvit34
这个解决方案提出了OP的问题。ApplicationContextAware仅适用于Spring Bean本身的类(因此带有@Component注释)。但是OP明确要求不是Spring Bean即不受Spring管理的类! - Peter Wippermann
1
@PeterWippermann 不确定您的评论是否仍然适用,但这里的想法是,不受Spring管理的类ABC将使用此答案提出的类来获取依赖项。因此,原始类ABC不需要是ApplicationContextAware。 - seveneights
显示剩余2条评论

12
因为类ABC未被Spring管理,所以自动装配不起作用。您可以使用其中一个@Component注释(@Component、@Service、@Controller等)在类定义上方进行标注,然后在应用程序上下文XML中使用context:component-scan,或者老派一些,在应用程序上下文中直接定义bean,这样Spring就可以管理类ABC了。
如果由于某种原因无法让Spring管理ABC类,则可以在ABC中加载应用程序上下文,例如:

ApplicationContext context = new ClassPathXmlApplicationContext("path/to/applicationContext.xml");

然后使用以下内容手动设置Bean值:

XYZ someXyz = (XYZ) context.getBean("MyXYZ");


5

正确的做法是:你不能只是在一个类上调用new方法然后期望所有的依赖注入都能够自动完成;Spring必须管理这个bean才能发挥其全部魔力。

如果您能提供更多有关您使用情况的详细信息,我们可能会建议一些有用的选项。


https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/AutowireCapableBeanFactory.html - meadlai

4

对于像我这样只会基本Spring Boot并不熟悉行话的新手:

  • 您的服务、存储库等都是Bean
  • 您可以从ApplicationContext中获取您的Bean

Ashish的答案对我有用,但是这篇文章提供了更详细的解释。

如果您不知道所需的bean的名称,请尝试查看此数组:

String[] names = context.getBeanDefinitionNames();

如果您对“组件扫描”和配置文件感到困惑,了解 @SpringBootApplication 注释(可能在 main() 方法附近找到)隐式地调用 @Configuration 和 @ComponentScan 可能会有所帮助。
这意味着主类顶部声明的包中的所有文件都会被 Spring 获取,并且您想要添加的任何 bean 都可以写在 main() 方法旁边。

4
您可以在想要自动装配其他bean的类中使用Spring的@Configurable注释。 此外,您需要使用@EnableSpringConfigured注释任何配置bean,以便Spring知道您的可配置bean。
@EnableSpringConfigured文档:@EnableSpringConfigured documentation public @interface EnableSpringConfigured Signals the current application context to apply dependency injection to non-managed classes that are instantiated outside of the Spring bean factory (typically classes annotated with the @Configurable annotation). Similar to functionality found in Spring's XML element. Often used in conjunction with @EnableLoadTimeWeaving.
@Configurable(autowire = Autowire.BY_TYPE)
public class ABC {
    @Autowire private XYZ xyz;
    ...
}

@Configuration
@EnableSpringConfigured
public class Application {
    ...
}

public class MyClass {
    public void doSomething() {
        ABC abc = new ABC(); // XYZ is successfully autowired
        ...
    }
}

你好ibai, MyClass是用来做什么的?它也是一个非Spring管理的对象。 我们能在应用程序类中new ABC()吗?谢谢。 - Sam

3
简而言之,是的,ABC没有被注入XYZ,因为Spring没有管理ABC。Spring无法配置它不知道的对象。
您可以使用@Service或@Component对ABC进行注释来管理它。请注意,为了让Spring识别这些注释,必须启用自动扫描:
<context:component-scan base-package="com.mypackage.awesomeproject" />

1

0
另一个选项可能是在启动类(通常是Application)中获取上下文并将其保存在那里。
public class Application {
    public static ApplicationContext context;
    public static void main(String[] args) {
        context = SpringApplication.run(Application.class, args);
    }
}

然后你可以使用Application.context.getBean("MyXYZ")或类似的方式从任何地方获取一个bean。

0

您可以使用@Configurable注释来注释ABC类。然后,Spring IOC将向ABC类注入XYZ实例。通常与AspectJ的AnnotationBeanConfigurerAspect一起使用。


0

请注意,这些方法使用无参数构造函数实例化类。如果没有找到主/默认构造函数,则可能会出现BeanInstantiationException。 - Diego Souza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接