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 IValidator
s 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()
精彩评论