对于单例Bean:Spring容器实例化单例bean并解析注入其依赖项时,该注入只发生一次。
如果您需要在运行时多次使用原型bean的新实例。即:假设单例的bean A在方法调用中使用了非单例的bean B。容器只会创建bean A一次,而只有一个机会来配置属性。 那么容器就无法为每一次创建bean A时都提供新的bean B实例。
1:使用@Lookup注解。
2:使用查找方法注入。
3.放弃IOC,实现ApplicationContextAware接口,引入ApplicationContext,在调用时获取原型实例。

实现示例

  1. package fiona.apple;
  2. // Spring-API imports
  3. import org.springframework.beans.BeansException;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.ApplicationContextAware;
  6. public class CommandManager implements ApplicationContextAware {
  7. private ApplicationContext applicationContext;
  8. public Object process(Map commandState) {
  9. // grab a new instance of the appropriate Command
  10. Command command = createCommand();
  11. // set the state on the (hopefully brand new) Command instance
  12. command.setState(commandState);
  13. return command.execute();
  14. }
  15. protected Command createCommand() {
  16. // notice the Spring API dependency!
  17. return this.applicationContext.getBean("command", Command.class);
  18. }
  19. public void setApplicationContext(
  20. ApplicationContext applicationContext) throws BeansException {
  21. this.applicationContext = applicationContext;
  22. }
  23. }
  1. package fiona.apple;
  2. // no more Spring imports!
  3. public abstract class CommandManager {
  4. public Object process(Object commandState) {
  5. // grab a new instance of the appropriate Command interface
  6. Command command = createCommand();
  7. // set the state on the (hopefully brand new) Command instance
  8. command.setState(commandState);
  9. return command.execute();
  10. }
  11. // okay... but where is the implementation of this method?
  12. protected abstract Command createCommand();
  13. }
  14. 配置xml
  15. <!-- a stateful bean deployed as a prototype (non-singleton) -->
  16. <bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
  17. <!-- inject dependencies here as required -->
  18. </bean>
  19. <!-- commandProcessor uses statefulCommandHelper -->
  20. <bean id="commandManager" class="fiona.apple.CommandManager">
  21. <lookup-method name="createCommand" bean="myCommand"/>
  22. </bean>
  23. Spring容器动态地覆盖createCommand()方法的实现。
  24. 如果方法是abstract的, 那么动态生成的子类会实现该方法。否则,动态生成的子类将覆盖原始类定义的具体方法
  1. public abstract class CommandManager {
  2. public Object process(Object commandState) {
  3. MyCommand command = createCommand();
  4. command.setState(commandState);
  5. return command.execute();
  6. }
  7. @Lookup
  8. protected abstract MyCommand createCommand();
  9. }

Lookup注解处理源码

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors

  1. public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
  2. throws BeanCreationException {
  3. // Let's check for lookup methods here...
  4. if (!this.lookupMethodsChecked.contains(beanName)) {
  5. if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
  6. try {
  7. Class<?> targetClass = beanClass;
  8. do {
  9. ReflectionUtils.doWithLocalMethods(targetClass, method -> {
  10. Lookup lookup = method.getAnnotation(Lookup.class);
  11. if (lookup != null) {
  12. Assert.state(this.beanFactory != null, "No BeanFactory available");
  13. LookupOverride override = new LookupOverride(method, lookup.value());
  14. try {
  15. RootBeanDefinition mbd = (RootBeanDefinition)
  16. this.beanFactory.getMergedBeanDefinition(beanName);
  17. mbd.getMethodOverrides().addOverride(override);
  18. }
  19. catch (NoSuchBeanDefinitionException ex) {
  20. throw new BeanCreationException(beanName,
  21. "Cannot apply @Lookup to beans without corresponding bean definition");
  22. }
  23. }
  24. });
  25. targetClass = targetClass.getSuperclass();
  26. }
  27. while (targetClass != null && targetClass != Object.class);
  28. }
  29. catch (IllegalStateException ex) {
  30. throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
  31. }
  32. }
  33. this.lookupMethodsChecked.add(beanName);
  34. }