Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Autowired and Singletons

Tags:

spring

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());
            }
        }
    }
like image 866
skyman Avatar asked Mar 04 '14 22:03

skyman


People also ask

Is @autowired a singleton?

You can simply put @Autowired annotation, followed by visibility tag and object, to can use every object managed by Spring context. But beware, all of these objects are a kind of Spring-managed singleton.

What is difference between @autowired and @resource in Spring?

@Autowired in combination with @Qualifier also autowires by name. The main difference is is that @Autowired is a spring annotation whereas @Resource is specified by the JSR-250. So the latter is part of normal java where as @Autowired is only available by spring.

Are Spring components singletons?

Yes, that is correct, @Component is a Spring bean and a Singleton. About singletons - spring beans are all in singleton scope by default. The only thing you have to have in mind is that you should not store state in field variables (they should only hold dependencies).

What is difference between @autowired and @inject?

@Inject and @Autowired both annotations are used for autowiring in your application. @Inject annotation is part of Java CDI which was introduced in Java 6, whereas @Autowire annotation is part of spring framework. Both annotations fulfill same purpose therefore, anything of these we can use in our application.


1 Answers

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.

like image 78
Dirk Lachowski Avatar answered Oct 12 '22 11:10

Dirk Lachowski