开发者

How do I update existing autowired properties when inserting a new bean?

We have component classes that autowire beans of a certain type:

@Component
public class MyComponent {
    @Autowire
    public IValidators[] validators;
}

Our application allows the creation of Groovy classes that get compiled at runtime and are registered with Spring using ScriptFactoryPostProcessor:

ConstructorArgumentValues args = new ConstructorArgumentValues();
args.addGenericArgumentValue(groovySourceLocation); //location is on the file system
RootBeanDefinition def = new RootBeanDefinition(GroovyScriptFactory.class, args, null);
BeanDefinitionRegistry r = (BeanDefinitionRegistry) this.applicationContext.getBeanFactory();
r.registerBeanDefinition(beanName, def); //beanName is the same as the class name

//scriptFactoryPostProcessor is autowired into class from applicationConfig
scriptFactoryPostProcessor.postProcessBeforeInstantiation(GroovyScriptFactory.class, beanName);

The groovy bean is created correctly as I can retrieve it from the applicationContext by the bean name or by开发者_StackOverflow社区 the type. But the already autowired properties of components do not have the added bean. When the groovy class implements IValidator, I'd like any component classes that autowire IValidator types to be updated with new groovy bean added to the collection. How do I do this?

UPDATE

After looking through the source, I don't see anyway that Spring supports my expectation. My last hope was that I could ask for dependent beans of a type (similar to getDependentBeans(String beanName)) but it does not exist and from the looks of things, Spring does not track dependencies based on type.


Really interesting question. The easiest approach: make MyComponent prototype and create new instance every time you need it. This way Spring will perform autowiring with most recent list of IValidator instances. Consider <lookup-method/>.

Less elegant way to do this is to have a factory (not a FactoryBean) that will retrieve all beans implementing IValidator on demand and simply call this factory whenever you need it. Sure, not in the Spring spirit at all.

Other approaches are much more cumbersome and error-prone. You might create your own post-processor to add newly discovered IValidator to all classes that require list of all of them. You might also develop your own implementation of List<IValidator> that will lookup ApplicationContext each time requested - a bit challenging, especially when concurrency is taken into account.

Finally there is a Composite design pattern: have only one IValidator that will delegate all calls to the list of target IValidators discovered manually in ApplicationContext.


You could implement InitializingBean. If you do Spring will call afterPropertiesSet() after wiring dependencies. You could add any special logic to override these dependencies.

http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans/factory/InitializingBean.html#afterPropertiesSet()

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜