当前位置: 首页 > 知识库问答 >
问题:

Spring Bean构造函数无法设置POJO属性

裴欣荣
2023-03-14

我正在尝试从我的主方法创建一个Spring bean。

我已将此bean配置为具有特定属性。这些值是在由@Configuration注释的SpringConfig类中指定的。

bean是使用Spring Application Context在我的main()方法中创建的。bean成功启动,但它没有我在SpringConfig类中指定的属性。我不明白为什么?

我可能已经确定了问题的原因:这个bean的POJO类使用@Autowired和@Qualifier来字段注入不同的属性集,并且这些值在我创建bean时(使用我的main方法中的Spring上下文)会一直存在。

我无法理解为什么不能通过从SpringConfig类调用参数化构造函数来覆盖这些字段注入。

奇怪的是,我可以从我的主方法中显式地将属性修改为我需要的属性(即myBean.setproperty(NewVal)工作)。为什么这行得通,但new MyBean(其他人)失败了?这毫无意义!

这是我的代码应用程序。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!");     
    }
}

共有1个答案

安奇
2023-03-14

这是因为在实例化Springbean时,它是按特定顺序组装的:

  1. 第一:构造函数执行
  2. 第二:注入依赖项
  3. 第三:执行初始化挂钩

通常,在类中,您会将类初始化代码放在构造函数中。

但是,如果您的类依赖于任何字段注入的属性并且您希望使用这些属性来初始化您的类,则不能在构造函数中这样做。这是因为这些注入直到构造函数执行后才会发生!

因此,例如,您可能有一些类作用域变量,这些变量已从属性文件(通过@value)中注入值,或者它可能已被注入bean(通过@Autowired),并且您希望填充数组,您必须在初始化挂钩内而不是在构造函数内进行此操作。

因此,我假设构造函数注入在上面被字段注入覆盖,这是由Spring容器管理的bean生命周期阶段顺序的结果。

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中设置变量值的方法。有时使用带有参数的构造函数,而其他setter方法则用于设置每个变量的值。 我知道,一旦使用“新”关键字实例化了一个类,构造函数就会在类内部初始化一个实例变量。 但是,什么时候使用构造函数,何时使用setter? 问题答案: 当您要创建对象的新实例时,应使用构造函数方法,该实例的值已填充(准备使用的对象中已填充值)。这样,您无需

  • 我正在构建一个API并使用swagger测试endpoint。我有一个产品: 在这个DTO中,我想使用在我的代码中使用的Price类。价格类如下所示: 但是由于私有设置器在类中使用,我无法使用swagger设置这些值(它在这些上具有属性)。我真的很喜欢这种拥有私有设置器并使用构造函数设置值的方法,顺便说一句,这是公共的。有没有办法我可以使用swagger为类设置值,并且仍然在属性上使用私有设置器?

  • 1.如何通过参数化构造函数设置这些属性?? 类文件 > 我想通过传递参数构造函数的setter设置这些属性,但它没有设置这些属性 在这里,我想通过toString方法显示属性 }对象文件 为什么我无法通过构造函数设置这些属性?? public class Runnable{public static void main(String[]args){Product p1=新产品(“pc”,“Grey

  • 我刚刚迁移到spring JPA技术,并设法将我的简单jersey hibernate项目更改为具有自定义crudrepository的spring JPA。但我不能处理自动配置EntityManagerFactorybean。下面是我的代码: application.properties: 应用程序: 错误日志报告: LogHandler: 错误日志: pom。xml 最后是我的堆栈跟踪: 谢谢

  • 问题内容: 大家好,我正在尝试在选项卡中列出文本数据,这是我的方法 无法解析构造函数ArrayAdapter 的方法,这是我的主要活动。任何帮助将不胜感激,我仍然是一个noobie 。 问题答案: 更改 至 你可以在使用。

  • 我的代码中出现了这个错误。 org.springframework.beans.factory.BeanCreationException:创建名为“roleRepository”的bean时出错:设置bean属性“entityManager”时,无法创建[org.springframework.orm.jpa.SharedEntityManagerCreator]类型的内部bean(内部bean