12

I'm using Spring 4 with SpringBoot and Spring-Web with Java configuration.

To have my @PostConstruct annotated methods executed by Spring at launch, it is necessary to register CommonAnnotationBeanPostProcessor with the context, otherwise @PostConstruct is ignored.

In a XML-based Spring configuration, the docs say to use (under the beans element)

<context:annotation-config/>

I have also seen an example where registration is done on an individual bean basis, like so:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

I wish to avoid this if possible. My project does not include any XML file, and none is generated for me in my build folder.

Currently, my solution is to annotate my class with @ComponentScan, which I believe causes Spring to detect and register @Components and @Beans. Somehow, this causes CommonAnnotationBeanPostProcessor to be invoked, although I have no idea why, but it solves my problem!

(This class has one @Autowired property, which is null at startup - hence the need to do the initialization via @PostConstruct)

But again, my question, what is the proper way to achieve this using Java configuration? Thank you!

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
zkn
  • 121
  • 1
  • 1
  • 4
  • You need to tell the context that you want to use annotation, either manually by registerig all `BeanPostProcessor`s (not recommended) or by using `` (which is already implied when using ``. Or by using an `ApplicationContext` implementation that by default uses annotations like the `AnnotationConfigApplicationContext`. There is no single proper way to do it al the mentioned ways are valid. – M. Deinum Dec 08 '15 at 12:56
  • The fact that you have a `@Autowired` property that is null shouldn't be the case as spring should autowire. Generally this implies that you haven't told the context you want to use annotation . – M. Deinum Dec 08 '15 at 12:58
  • @M. Deinum Thank you. To clarify, the `@Autowired` property is injected but the value is not yet available at the time the static/instance constructors are running, hence the use of @PostConstruct. The context is aware of ***some*** annotations, (perhaps via `@SpringBootApplication`, `@Configuration` and `@Component` which I do use), but docs state that @PostConstruct is not one of them and so some way to enlist `CommonAnnotationBeanPostProcessor` is needed. I would like that way to be consistent with Java configuration, (without XML). – zkn Dec 08 '15 at 17:13
  • The `@PostConstruct` is already handled if you have enabled annotation, which is by default the case if you use java based config. – M. Deinum Dec 08 '15 at 18:51

2 Answers2

8

You can use InitializingBean as an alternate solution.

Simply extend this interface and override afterPropertiesSet method that will be called after setting all the properties of the bean just like post construct.

For example:

@Component
public class MyBean implements InitializingBean 
{
    @Override
    public void afterPropertiesSet()
    {
        // do whatever you want to do here
    }
}
Braj
  • 46,415
  • 5
  • 60
  • 76
  • 2
    Thank you. It works. Here's what I did: `code` @Component public class Example implements InitializingBean { @Autowired private MyThing myThing; @Override public void afterPropertiesSet() throws Exception { // make use of myThing here, after it has been injected. } } `code` @Braj I'll leave the question unanswered for the moment to gather more knowledge. Will close it in a few days. – zkn Dec 08 '15 at 12:17
  • The Spring documentation discourages to use this interface because it unnecessarily couples the code to Spring. [Initialization callbacks](https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-lifecycle-initializingbean) – Roeland Van Heddegem Sep 12 '17 at 14:50
  • @rvheddeg I agree with you. In another way we can use `@PostContruct` annotation or `init-method`. [Example](https://www.mkyong.com/spring/spring-postconstruct-and-predestroy-example/) – Braj Sep 13 '17 at 12:43
0

This is not an answer to my question as posed, but another alternative solution.

I could have implemented the Lifecycle interface and done my initialization in the start() method. At the time I was stumped what to return for the isRunning() method, although hindsight says return true would have been good enough as its lifetime is application-long. Any suggestions on that point would be welcome.

public interface Lifecycle {

  void start();

  void stop();

  boolean isRunning();

}

Other alternatives may be inferred from here, namely

<beans default-init-method="init">

which, I gather, allows every @Bean to have its optional init() method called. (I have not tried it).

Still, I'm hoping for an answer to my question that uses Java Configuration.

zkn
  • 121
  • 1
  • 1
  • 4