20

I wish to perform a couple of setup methods within my Spring Context.

I currently have the following code but it doesn't work as I am saying they are beans and have no return type.

@Configuration
@Component
public class MyServerContext {

    ...

    // Works
    @Bean
    public UserData userData() {
        UserData userData = new AWSUserDataFetcher(urlUtil()).fetchUserData();
        return userData;
    }   

    // Doesn't work
    @Bean
    public void setupKeyTrustStores() {
        // Setup TrustStore & KeyStore
        System.setProperty(SYS_TRUST_STORE, userData().get(TRUST_STORE_PATH));
        System.setProperty(SYS_TRUST_STORE_PASSWORD, userData().get(TRUST_STORE_PASSWORD));
        System.setProperty(SYS_KEY_STORE, userData().get(KEY_STORE_PATH));
        System.setProperty(SYS_KEY_STORE_PASSWORD, userData().get(KEY_STORE_PASSWORD));

        // Prevents handshake alert: unrecognized_name
        System.setProperty(ENABLE_SNI_EXTENSION, "false");
    }

    ...

}

How can I run this method automatically by the @Configuration context without the @Bean annotation?

ptimson
  • 5,533
  • 8
  • 35
  • 53

2 Answers2

23

You can use the @PostConstruct annotation instead of @Bean:

@Configuration
@Component
public class MyServerContext {

    @Autowired
    private UserData userData; // autowire the result of userData() bean method

    @Bean
    public UserData userData() {
        UserData userData = new AWSUserDataFetcher(urlUtil()).fetchUserData();
        return userData;
    }   

    @PostConstruct
    public void setupKeyTrustStores() {
        // Setup TrustStore & KeyStore
        System.setProperty(SYS_TRUST_STORE, userData.get(TRUST_STORE_PATH));
        System.setProperty(SYS_TRUST_STORE_PASSWORD, userData.get(TRUST_STORE_PASSWORD));
        System.setProperty(SYS_KEY_STORE, userData.get(KEY_STORE_PATH));
        System.setProperty(SYS_KEY_STORE_PASSWORD, userData.get(KEY_STORE_PASSWORD));

        // Prevents handshake alert: unrecognized_name
        System.setProperty(ENABLE_SNI_EXTENSION, "false");
    }

    ...

}
Miloš Milivojević
  • 5,219
  • 3
  • 26
  • 39
3

Use @PostConstruct instead of @bean

@PostConstruct

Due to the Weld Reference injection and initialization happens in this order;

  1. First, the container calls the bean constructor (the default constructor or the one annotated @Inject), to obtain an instance of the bean.
  2. Next, the container initializes the values of all injected fields of the bean.
  3. Next, the container calls all initializer methods of bean (the call order is not portable, don’t rely on it).
  4. Finally, the @PostConstruct method, if any, is called.

So, the purpose of using @PostConstruct is clear; it gives you a chance to initialize injected beans, resources etc.

public class Person {

    // you may have injected beans, resources etc.

    public Person() {
        System.out.println("Constructor is called...");
    }

    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct is called...");
    } }

So, the output by injecting a Person bean will be;

Constructor is called...

@PostConstruct is called...

One important point about @PostConstruct is, it won't be invoked if you try to inject and initialize bean through producer methods. Because using a producer method means that you are programmatically creating, initializing, and injecting your bean with new keyword.

Resource Link:

  1. CDI Dependency Injection @PostConstruct and @PreDestroy Example
  2. Why use @PostConstruct?
Community
  • 1
  • 1
SkyWalker
  • 28,384
  • 14
  • 74
  • 132