5

I have code with lazy initialized beans:

@Component @Lazy
class Resource {...}

@Component @Lazy @CustomProcessor
class ResourceProcessorFoo{
    @Autowired
    public ResourceProcessor(Resource resource) {...}
}
@Component @Lazy @CustomProcessor
class ResourceProcessorBar{
    @Autowired
    public ResourceProcessor(Resource resource) {...}
}

After initialize application context, there's no instances of this beans. When bean Resource is created by application context (as example, applicationContext.getBean(Resource.class)), no instances of @CustomProcessor marked beans.

It's need to create beans with @CustomProcessor when created Resource bean. How to do it?

Updated: One of ugly solution found - use empty autowired setter:

@Autowired
public void setProcessors(List<ResourceProcessor> processor){}

Another ugly solution with bean BeanPostProcessor (so magic!)

@Component
class CustomProcessor implements BeanPostProcessor{
    public postProcessBeforeInitialization(Object bean, String beanName) {
        if(bean instanceof Resource){
            applicationContext.getBeansWithAnnotation(CustomProcessor.class);
        }
    }
}

Maybe there's a more elegant way?

mitallast
  • 183
  • 2
  • 8
  • Form java docs of @Lazy `If present and set to true, the @Bean or @Component will not be initialized until referenced by another bean or explicitly retrieved from the enclosing BeanFactory`. I think that you should remove @Lazy from processor or put a reference inside Resource bean. – Xstian Nov 06 '14 at 13:54
  • No, it's does not work because ResourceProcessor is not a dependency for Resource. When all components is not lazy, of course, it's works correctly, but I need do it with lazy initialization – mitallast Nov 06 '14 at 14:41
  • You could add a `@PostConstruct` within Resource to initialize all `Processor`. – Xstian Nov 06 '14 at 14:55
  • 1
    If you need to instantiate a bean at startup, then you should not mark it as @Lazy – DwB Nov 06 '14 at 15:08
  • @DwB If ResourceProcessor not marked Lazy, it's means that resource not Lazy too. But I need lazy behavior for all this components. – mitallast Nov 06 '14 at 20:27
  • @Xstian: How do it with `PostConstruct`? It's need have reference for **all** ResourceProcessors at Resource, but it doesn't have. – mitallast Nov 06 '14 at 20:38
  • I was thinking that `Resource` should implements `ApplicationContextAware` , and within its `@PostConsturct` you could use `applicationContext.getBeansOfType(ResourceProcessor.class)`. Yes is a twisted thought but i think that works fine :) – Xstian Nov 06 '14 at 21:07

1 Answers1

3

You must create a marker interface like CustomProcessor

public interface CustomProcessor{

}

later each ResourceProcessor must be implements above interface

@Component @Lazy 
class ResourceProcessorFoo implements CustomProcessor{
    @Autowired
    public ResourceProcessor(Resource resource) {...}
}
@Component @Lazy 
class ResourceProcessorBar implements CustomProcessor{
    @Autowired
    public ResourceProcessor(Resource resource) {...}
}

Resource must implements ApplicationContextAware

@Component
@Lazy
public class Resource implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    @PostConstruct
    public void post(){
        applicationContext.getBeansOfType(CustomProcessor.class);
    }

    public void setApplicationContext(ApplicationContext applicationContext)throws BeansException {
        this.applicationContext = applicationContext;   
    }

}

When Resource bean will be referenced starts the postconstruct that initialize all bean that implements CustomProcessor interface.

Xstian
  • 8,184
  • 10
  • 42
  • 72
  • Unfortunately, it's a hard Spring Framework vendor lock. Also, it's better to use `@Autowired` for `ApplicationContext` without `ApplicationContextAware` – mitallast Nov 07 '14 at 12:20