registerResolvableDependency

115 阅读4分钟

registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);

/**
 * Register a special dependency type with corresponding autowired value.
 * <p>This is intended for factory/context references that are supposed
 * to be autowirable but are not defined as beans in the factory:
 * e.g. a dependency of type ApplicationContext resolved to the
 * ApplicationContext instance that the bean is living in.
 * <p>Note: There are no such default types registered in a plain BeanFactory,
 * not even for the BeanFactory interface itself.
 * @param dependencyType the dependency type to register. This will typically
 * be a base interface such as BeanFactory, with extensions of it resolved
 * as well if declared as an autowiring dependency (e.g. ListableBeanFactory),
 * as long as the given value actually implements the extended interface.
 * @param autowiredValue the corresponding autowired value. This may also be an
 * implementation of the {@link org.springframework.beans.factory.ObjectFactory}
 * interface, which allows for lazy resolution of the actual target value.
 */

译文解释:

  1. 用相应的autowired值注册一个特殊的依赖类型。
  2. 用于预期的工厂/上下文引用可自动调用,但不能在工厂中定义为bean:
  3. 例如:ApplicationContext类型的依赖解析为bean所在的ApplicationContext实例。
  4. 注意:在普通的BeanFactory中没有注册这样的默认类型,即使是BeanFactory接口本身。
  5. @param dependencyType要注册的依赖类型。这通常会成为一个基础接口,如BeanFactory,并解析它的扩展如果声明为自动装配依赖(例如ListableBeanFactory),只要给定的值实际实现了扩展接口。
  6. @param autowiredValue对应的autowired值。这也可能是一个实现{@link org.springframework.beans.factory.ObjectFactory}接口,它允许延迟解析实际目标值。

该方法的实际意义是:

  1. 该方法较为简单,给指定类型的依赖注入项一个特定的值,什么意思呢?
  2. 比如:现在我要往A中注入一个了C,而C由两个实现D和E,那么你可以通过该方法给依赖类型为C的注入项指定一个固定的对象,D或者E。
  3. 这样就可以避免由于出现多实例而造成程序错误的问题了。
  4. Tips:这里并没有说自动注入,也就是说@AutoWrite也可以。

我们现在模拟一个场景来还原这个问题:

  1. 我们有个类完成例子示意:A类,C类,D类型,E类
@Component
public class A {
	@Autowired
	C c;

	public void printInfo() {
		System.out.println("beanPrintInfo:" + c);
	}

}
@Component
public interface C {
}
@Component
public class D implements C{
}
@Component
public class E implements C {
}
  1. 可以想一下在主启动类中获取A对象的这个Bean,肯定会报错,原因是:你使用@Autowired来进行依赖注入,并且这个时候有两个C类的接口子实现类,那么spring就不知道到底是拿那个来完成当前的依赖注入任务了。
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type 'com.lukp.beanFactoryPostProcessor.registerResolvableDependency.C' available: 
expected single matching bean but found 2: d,e
  1. 但是这个时候假如说你指定了beanName就不会报错。
@Component
public class A {
	@Autowired
	C d;

	public void printInfo() {
		System.out.println("beanPrintInfo:" + d);
	}

}
  1. ok,上面的解决方案是可行的,但其实原理是给他指定了接口下的子实现类,所以spring在完成DI的时候也就不会报错,那本章节讨论的方法和作用其实是和这个道理是一样的。
@Component
public class TestRegisterResolvableDependency implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		E e = new E();
		beanFactory.registerResolvableDependency(C.class, e);
	}
}
  1. 可见上面的代码的含义是:
  • 当我的被依赖注入的Bean是C时,我要选定的是C类的子实现类E。
  1. 最后项目也成功构建。
  2. 当然我们最后还是要讨论到这个方法在spring中的应用:
  3. 我们还是回到refresh()当中,进入到prepareBeanFactory方法:
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  1. 那么根据对当前讨论的方法的理解,挑第一个来讲解:beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  2. 假设我当前注入的BeanFactory.class,那么他默认是后面传进来的beanFactory。
  3. 什么意思呢?
  4. 可以看到BeanFactory.class其实是一个接口,那么对应的他下面会有很多的实现子类,回到这个方法解决啥问题的本质,其实就是指定在使用这个接口Bean的时候到底要使用的是这个接口下面的那个实现子类。
  5. 追到源码里面去看看。
  6. 在refresh方法中prepareBeanFactory(beanFactory);中会塞一个beanFactory。
  7. 这个beanFactory是上面的obtainFreshBeanFactory()方法生成的。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		return getBeanFactory();
	}
  1. 再进到getBeanFactory()方法中。
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
  1. 发现他是一个接口方法,那他会也会对应的有很多子实现,我们现在就进入到AbstractRefreshableApplicationContext这个子实现中。
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
    DefaultListableBeanFactory beanFactory = this.beanFactory;
    if (beanFactory == null) {
        throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                "call 'refresh' before accessing beans via the ApplicationContext");
    }
    return beanFactory;
}
  1. 发现在第一行将this.Factory赋值给了当前的DefaultListableBeanFactory类型的beanFactory。我ctrl加左键可以查看到beanFactory在AbstractRefreshableApplicationContext中的定义是:
@Nullable
private volatile DefaultListableBeanFactory beanFactory;
  1. 我们现在再回过头来去看在springFactory初始化之初的时候是怎么样的。
  2. 我们进入到梦开始的地方:AnnotationConfigApplicationContext中。
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
    super(beanFactory);
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}
  1. 可以看到他是调用了父类的构造器完成的=>GenericApplicationContext的无参构造器
/**
 * Create a new GenericApplicationContext.
 * @see #registerBeanDefinition
 * @see #refresh
 */
public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}
  1. 在这里是直接初始化了DefaultListableBeanFactory。