我正在尝试通过使用以下方式从现有的Spring应用程序解除依赖关系 在配置类中使用Spring @Bean,在使用它的类中使用@Autowired。
以下是主要配置类:
@Configuration
@ComponentScan(basePackages = {"com.example"})
@EnableWebMvc
public class DataLoadConfig extends WebMvcConfigurerAdapter {
@Bean
ActivitiesFeed activityFeed() {
HashMap<Integer, Object> temp = new HashMap<Integer, Object>();
return new ActivitiesFeed(temp);
}
...
以下是依赖项的使用方式:
public class ActivitiesLoad {
// ADDED
@Autowired
ActivitiesFeed activityFeed;
public ActivitiesLoad(String loadType, int personCode, String outputFilter, int outputNumber) {
...
// REMOVED - this approach didn't throw any errors though
// HashMap<Integer, Object> temp = new HashMap<Integer, Object>();
// ActivitiesFeed activityFeed = new ActivitiesFeed(temp);
// This dependency is now @Autowired in
feed = activityFeed.getActivities();
...
但是,我现在遇到以下错误:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/DataLoads] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at ac.uk.strath.t4.dataload.pure.activities.ActivitiesLoad.<init>(ActivitiesLoad.java:66)
at ac.uk.strath.t4.dataload.controller.DataLoadController.pureActivities(DataLoadController.java:149)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
...
请参阅原始的初始化代码,此运行没有任何问题,因此我知道依赖项有效,但想知道我是否实现了注入错误。
顺便说一句,我不拥有ActivitiesFeed源,因此我无法将任何@Components诸如注释附加到该类,因此选择将其作为@Bean放入应用程序配置类(DataLoadConfig)中。
注意:我还尝试将ActivitiesLoad构造函数代码放入run(...)方法中,只是为了解决这个问题,因为我试图从构造函数中访问依赖项,但这给了我同样的错误。理想情况下,我现在宁愿将代码保留在构造函数中,因为它是别人的代码,并且在此阶段不想冒险破坏太多:)
更新
我试图添加一个@PostConstruct方法,但是只是一个问题。然后,如示例所示,我将activityFeed属性设为私有,但还是一样。
public class ActivitiesLoad {
@Autowired
private ActivitiesFeed activityFeed;
private String loadType;
private int personCode;
private String outputFilter;
private int outputNumber;
public ActivitiesLoad(String loadType, int personCode, String outputFilter, int outputNumber) {
log.debug("Starting pure activities data load");
this.loadType = loadType;
this.personCode = personCode;
this.outputFilter = outputFilter;
this.outputNumber = outputNumber;
}
@PostConstruct
public void init() {
log.debug("Starting pure activities data load @PostConstruct");
log.debug(activityFeed); // outputs: null
...
更新2
在这里,我将依赖项从构造函数中排除,而是将其放入自己的init方法中,并在创建ActivityLoad实例后调用它。但是,我仍然看到NullPointerException的问题。
ActivityLoad的实例化(现在使用创建实例后调用的init
方法进行实例化):
...
ActivitiesLoad activitiesLoad = new ActivitiesLoad();
activitiesLoad.init(loadType, personCode, typeFilter, outputLimit);
...
这是包含新方法的ActivityLoad类
@Component
public class ActivitiesLoad {
@Autowired
private ActivitiesFeed activityFeed;
public void init(String loadType, int personCode, String outputFilter, int outputNumber) {
log.debug(activityFeed); // outputs: null
答案 0 :(得分:2)
您需要牢记两件事。
i)如果您使用new
关键字创建一个类实例,则该特定实例将不会由Spring 管理,这意味着它将不会自动装配您所请求的bean。在链中。因此,从头开始,ActivitiesFeed activityFeed
总是在ActivitiesLoad
实例内为null,这些实例是通过使用new ActivitiesLoad(...)
ii)第二点是关于您的更新。正如其他答案所建议的那样,您试图通过类构造函数中的注入Bean调用方法。这在任何DI框架中均不起作用,因为构造函数仅用于初始化字段引用,而不能调用它们。这就是为什么需要@PostConstruct
的原因,它在bean初始化/构造函数成功完成后由Spring容器调用,因此bean引用将获得适当的实例。
因此,您有2种可能的选择:
a。,通过将ActivitiesLoad
正确地自动布线为原型并传递所需的状态来维护上下文。
b。重构ActivitiesLoad
以完全不保留上下文,更改构造函数以保留默认值,并在其中实现所有逻辑以及所需的params(context)方法。然后,您可以使用@Autowire
答案 1 :(得分:1)
ActivitiesLoad
应该是Spring组件,以便能够在其中自动装配bean。
尝试使它成为其中一个弹簧组件,即@Component
@Service
您仍然需要使用@PostConstruct
,因为它是直接为此类情况设计的。
答案 2 :(得分:0)
之所以会这样,是因为您没有在上下文中加载组件。
您的问题缺少一些信息,但是如果您运行的是独立应用程序或Spring Boot Web应用程序,则应包含一部分逻辑,该逻辑在上下文中明确表示“请加载DataLoadConfig”。
我将引用一个链接以避免重新编写您的代码:https://www.tutorialspoint.com/spring/spring_java_based_configuration.htm
我认为您缺少第四个代码段,这实际上会导致您面临的问题。该组件不在上下文中,因此在自动装配时会得到一个空指针。
通过遵循以下示例,确保您的主机中的组件在那里。
答案 3 :(得分:0)
这已经得到回答,但是我发现本文也很好地解释了为什么自动装配的依赖项为空:
https://www.moreofless.co.uk/spring-mvc-java-autowired-component-null-repository-service/