我正在尝试从我的主要方法创建一个 spring bean。
我已将此 bean 配置为具有特定属性。这些值是在 @Configuration 注释的 SpringConfig 类中指定的。
该 bean 是使用 Spring 应用程序上下文在我的 main() 方法中创建的。该 bean 成功启动,但它没有我在 SpringConfig 类中指定的属性。我不明白为什么?
我可能已经确定了问题的原因:该 bean 的 POJO 类使用 @Autowired 和 @Qualifier 来现场注入(inject)一组不同的属性,并且当我这些值时,这些值仍然存在。创建 bean(使用我的 main 方法中的 Spring Context)。
我不明白为什么我不能通过从 SpringConfig 类调用参数化构造函数来覆盖这些字段注入(inject)。
奇怪的是,我可以从我的主方法中显式地将属性更改为我需要的属性(即myBean.setproperty(NewVal)
有效)。为什么它可以工作,但是 new MyBean(OtherVal)
失败?这毫无意义!
这是我的代码
应用程序.java:
package com.qa;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.qa.beans.AutoWiredBean;
import com.qa.beans.Book;
import com.qa.beans.Owner;
public class App {
private ApplicationContext context;
// Constructor...
public App() {
context = new AnnotationConfigApplicationContext(SpringConfig.class);
Owner owner1 = (Owner) context.getBean("ownerBean");
Book myBook = (Book) context.getBean("bookBean");
AutoWiredBean myAWBean = (AutoWiredBean) context.getBean("autoWiredBean_Bean");
AutoWiredBean myAWBean2 = (AutoWiredBean) context.getBean("autoWiredBean_Bean2");
System.out.println("\n" + owner1);
System.out.println("\n" + myBook);
System.out.println("\n" + myAWBean);
System.out.println("\n" + myAWBean2); //Observe: Spring fails to accept property parameters specified in the SpringConfig class. Yet Spring WILL accept a mutation request (eg: myAWBean2.setName="Tessa") as done so below.
myAWBean2.setName("Tessa"); myAWBean2.setId(27); //This works, but line 25 above does not. Line 25 uses SpringConfig class to set properties via constructor. WEIRD!!!!
System.out.println("\n" + myAWBean2);
}
public static void main(String[] args) {
new App();
}
}
这是 SpringConfig 类:
package com.qa;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.qa.beans.AutoWiredBean;
import com.qa.beans.Book;
import com.qa.beans.Owner;
import com.qa.beans.Pet;
@Configuration
@PropertySource("classpath:Bean.properties")
public class SpringConfig {
@Bean
public AutoWiredBean autoWiredBean_Bean(){
return new AutoWiredBean();
}
@Bean
public AutoWiredBean autoWiredBean_Bean2(){
return new AutoWiredBean(nameBean(), idBean());
}
@Bean
public String nameBean(){
return "Iqbal Hamid";
}
@Bean
public String name2Bean(){
return "Elouise McDermot";
}
@Bean
public String name3Bean(){
return "Tony Apsley";
}
@Bean
public String name4Bean(){
return "Luke Skywalker";
}
@Bean
public int idBean() {
return 50;
}
@Bean
public int id2Bean() {
return 37;
}
@Bean
public int id3Bean() {
return 33;
}
@Bean
public int id4Bean() {
return 44;
}
@Value("${book.author}") String name;
@Value("${book.title}") String title;
@Bean
public Book bookBean () {
return new Book (title, name);
}
@Bean
public Pet pet1Bean() {
Pet pet = new Pet();
pet.setName("Daisy");
return pet;
}
@Bean
Pet pet2Bean() {
return new Pet("Lola");
}
@Bean
Pet pet3Bean() {
return new Pet("Fido");
}
@Bean
public Owner ownerBean(){
ArrayList<Pet> petList = new ArrayList<Pet>();
petList.add(pet1Bean());
petList.add(pet2Bean());
petList.add(pet3Bean());
return new Owner("Lina", petList);
}
}
这是有问题的 POJO:
package com.qa.beans;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
@Scope("prototype")
public class AutoWiredBean implements InitializingBean, DisposableBean {
@Autowired
@Qualifier("name2Bean")
private String name;
@Autowired
@Qualifier ("id2Bean")
private int id;
// No arg constructor...
public AutoWiredBean() {
super();
}
// Parameterised constructor...
@Autowired
public AutoWiredBean(String name, int id) {
super();
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "AutoWiredBean Details: Name = '" + name + "', ID = " + id;
}
@Override
public void destroy() throws Exception {
System.out.println("Destroying AWBbean!");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Set Property of AWBbean!");
}
}
最佳答案
这是因为当实例化 Spring bean 时,它会按照一定的顺序组装:
- 首先:构造函数执行;
- 第二:注入(inject)依赖项;
- 第三:执行初始化 Hook ;
通常,在类中,您会将类初始化代码放在构造函数内。
但是,如果您的类依赖于任何字段注入(inject)的属性,并且您希望使用这些属性来初始化您的类,则无法在构造函数内执行此操作。这是因为这些注入(inject)只有在构造函数执行之后才会发生!
例如,您可能有一些类范围变量,这些变量已被注入(inject)属性文件中的值(通过@Value),或者可能已被注入(inject)bean(通过@Autowired),并且您希望填充数组,您必须在初始化 Hook 内执行此操作,而不是在构造函数内执行此操作。
因此,我认为由于 Spring 容器管理的 bean 生命周期阶段的顺序,上面的构造函数注入(inject)被字段注入(inject)覆盖。
package SpringDemo_Annotations;
import java.util.ArrayList;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;
@Component("fortuneService_FileProperties")
public class FortuneService_FileProperties implements IFortuneService {
@Value("${fortune1}")
private String fortune1;
@Value("${fortune2}")
private String fortune2;
@Value("${fortune3}")
private String fortune3;
@Value("${fortune4}")
private String fortune4;
@Value("${fortune5}")
private String fortune5;
private ArrayList<String> arrFortunes;
// Constructor...
public FortuneService_FileProperties() {
System.out.println("\nOBSERVE: Order of the lifestages of a bean:\tFIRST we enter the constructor:\t\t INSIDE FortuneService_FileProperties Constructor!");
//
// NOTE:
// YOU CANNOT PLACE CODE INSIDE THE CONSTRUCTOR WHICH REFERENCES FIELD INJECTED BEANS (via @Autowired) OR FIELD INJECTED VALUES (via @Value)
// BECAUSE THEY DO NOT GET INJECTED UNTIL AFTER THE CONSTRUCTOR HAS EXECUTED!!!
// THEREFORE CODE BELOW HAS BEEN SHIFTED OVER TO HOOKOBJECT_INITIALISE...
//
// arrFortunes = new ArrayList<String>();
//
// arrFortunes.add(this.fortune1);
// arrFortunes.add(this.fortune2);
// arrFortunes.add(this.fortune3);
// arrFortunes.add(this.fortune4);
// arrFortunes.add(this.fortune5);
System.out.println("OBSERVE: Order of the lifestages of a bean:\tSECOND Field injections take place:");
}
// Getter...
@Override
public String getFortune() {
return arrFortunes.get((int) (Math.random() * arrFortunes.size()));
}
@PostConstruct
public void hookObject_Initialise() {
System.out.println("OBSERVE: Order of the lifestages of a bean:\tTHIRD we enter the initialisation hook. Fields have now been injected, so if we need to use field-injected beans or field-injected values, to conduct any initialisation (eg to populate an array), we do this here!:\tINSIDE FortuneService_FileProperties @PostConstruct!");
//
// THIS IS THE CORRECT PLACE TO INITIALISE ANY CLASS-SCOPE VARIABLES
// WHICH ACCESS FIELD INJECTED PROPERTIES...
//
arrFortunes = new ArrayList<String>();
arrFortunes.add(this.fortune1);
arrFortunes.add(this.fortune2);
arrFortunes.add(this.fortune3);
arrFortunes.add(this.fortune4);
arrFortunes.add(this.fortune5);
}
@PreDestroy
public void hookObject_Destroy() {
System.out.println("\nOBSERVE: Order of the lifestages of a bean:\tFOURTH at destruction-time, we enter the destruction hook:\tINSIDE FortuneService_FileProperties() @PreDestoy!");
}
}
关于java - Spring Bean 构造函数无法设置 POJO 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49556541/