Spring @Autowired and Singletons

skyman

I have a Spring application that uses various configuration parameters that are persisted in a database. In order to minimize database access cycles, I have created a Singleton class that holds the parameters in a Properties object. There are occasions when the Properties object needs to be refreshed during the running of the application, so to this end I have a load() method and a reload() method. To access the database, I have an @Autowired service object. Simplifying a little:

public class AppConfig {
    private static AppConfig instance = null;
    private Properties appProperties;

    @Autowired ConfiguraitonService configService;

    protected AppConfig() {
        load();
    }

    public static AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }

    public void reload() {
        load();
    }

    private void load() {
        List<Configuration> configList configService.findAll()

        for (Configuration myConfiguration : configList) {
          if (myConfiguration != null && myConfiguration.getAttribute() != null) {
                appProperties.setProperty(myConfiguration.getAttribute(),myConfiguration.getValue());
            }
        }
    }

public String getValue(String key) {
    return appProperties.getProperty(key);
}

In the Spring configuration file, I have:

<bean id="appConfigBean" class="foo.bar.AppConfig"></bean>

Calling 'getValue' against this Singleton generates a null pointer exception. I understand that this is in someway connected to @Autowired and a failure to initialise correctly, although I don't understand why. I guess my question relates to the best approach for resolving this issue.

For others, this is the modified code that worked:

public class AppConfig {
    private static Properties myProperties = new Properties();

    @Autowired
    private ConfigurationService configService;
    private static AppConfig instance = null;

    protected AppConfig() {
    }

    public static AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }

    @PostConstruct
    public void load() {        
        List<Configuration> configList = configService.findAll();

        for (Configuration myConfiguration : configList) {
            if (myConfiguration != null && myConfiguration.getAttribute() != null) {
                myProperties.setProperty(myConfiguration.getAttribute(), myConfiguration.getValue());
            }
        }
    }
Dirk Lachowski

When you constructor calls load() the Autowired dependencies are still unwired. The wiring takes place after the constructor has finished. Either make configService final and use constructor autowiring or remove load() from your constructor but annotate load() with @PostConstruct.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related