springaspectjconfigurablepostconstructcompile-time-weaving

@Configurable doesn't work for objects initialized in @PostConstruct methods


I'm using Spring with AspectJ via compile-time weaving to use @Configurable spring annotation for objects non-managed by container.

Here is an example @Configurable-annotated object:

@Configurable(autowire = Autowire.BY_TYPE)
public class TestConfigurable {

    private TestComponent component;

    public TestComponent getComponent() {
        return component;
    }

    @Autowired
    public void setComponent(TestComponent component) {
        this.component = component;
    }
}

Component that I'm injecting into this object:

@Component
public class TestComponent {}

When I create TestConfigurable after context is created TestComponent injected there fine but when I'm doing so from @PostConstruct-annotated method it autowiring doesn't happen.

Component with @PostConstruct:

@Component
public class TestPostConstruct {

    @PostConstruct
    public void initialize() {
        TestConfigurable configurable = new TestConfigurable();
        System.out.println("In post construct: " + configurable.getComponent());
    }
}

Application that I'm executing:

public class TestApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");
        applicationContext.registerShutdownHook();

        TestConfigurable configurable = new TestConfigurable();
        System.out.println("After context is loaded: " + configurable.getComponent());
    }
}

Here is an output this application produces:

In post construct: null
After context is loaded: paulenka.aleh.roguelike.sandbox.TestComponent@fe18270

So is there any workaround to inject dependencies into @Configurable objects that are created inside @PostConstruct methods? All @Component-annotated beans are already in the context and autowiring is already done for them in time when @PostConstruct is called. Why Spring doesn't do autowiring here?..

Can post other configuration files (context and pom.xml) if they will help to resolve the problem.

Update 1: Looks like I found the cause of the problem. Objects annotated with @Configurable are initialized by AnnotationBeanConfigurerAspect which implements BeanFactoryAware. This aspect uses BeanFactory to initialize beans. Looks like @PostConstruct method of the TestPostConstruct object is executed before BeanFactory is set to AnnotationBeanConfigurerAspect. If logger set to debug the following message is printed to console: "BeanFactory has not been set on ...: Make sure this configurer runs in a Spring container. Unable to configure bean of type [...]. Proceeding without injection."

The question if there is any workaround is still open for me...


Solution

  • I found one workaround to this. To initialize AnnotationBeanConfigurerAspect aspect before @PostConstruct is executed you can add the following annotation to class with such @PostConstruct method:

    @DependsOn("org.springframework.context.config.internalBeanConfigurerAspect")
    

    Hope this information will be useful for someone.