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.
*/
译文解释:
- 用相应的autowired值注册一个特殊的依赖类型。
- 用于预期的工厂/上下文引用可自动调用,但不能在工厂中定义为bean:
- 例如:ApplicationContext类型的依赖解析为bean所在的ApplicationContext实例。
- 注意:在普通的BeanFactory中没有注册这样的默认类型,即使是BeanFactory接口本身。
- @param dependencyType要注册的依赖类型。这通常会成为一个基础接口,如BeanFactory,并解析它的扩展如果声明为自动装配依赖(例如ListableBeanFactory),只要给定的值实际实现了扩展接口。
- @param autowiredValue对应的autowired值。这也可能是一个实现{@link org.springframework.beans.factory.ObjectFactory}接口,它允许延迟解析实际目标值。
该方法的实际意义是:
- 该方法较为简单,给指定类型的依赖注入项一个特定的值,什么意思呢?
- 比如:现在我要往A中注入一个了C,而C由两个实现D和E,那么你可以通过该方法给依赖类型为C的注入项指定一个固定的对象,D或者E。
- 这样就可以避免由于出现多实例而造成程序错误的问题了。
- Tips:这里并没有说自动注入,也就是说@AutoWrite也可以。
我们现在模拟一个场景来还原这个问题:
- 我们有个类完成例子示意: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 {
}
- 可以想一下在主启动类中获取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
- 但是这个时候假如说你指定了beanName就不会报错。
@Component
public class A {
@Autowired
C d;
public void printInfo() {
System.out.println("beanPrintInfo:" + d);
}
}
- 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);
}
}
- 可见上面的代码的含义是:
- 当我的被依赖注入的Bean是C时,我要选定的是C类的子实现类E。
- 最后项目也成功构建。
- 当然我们最后还是要讨论到这个方法在spring中的应用:
- 我们还是回到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);
- 那么根据对当前讨论的方法的理解,挑第一个来讲解:beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
- 假设我当前注入的BeanFactory.class,那么他默认是后面传进来的beanFactory。
- 什么意思呢?
- 可以看到BeanFactory.class其实是一个接口,那么对应的他下面会有很多的实现子类,回到这个方法解决啥问题的本质,其实就是指定在使用这个接口Bean的时候到底要使用的是这个接口下面的那个实现子类。
- 追到源码里面去看看。
- 在refresh方法中prepareBeanFactory(beanFactory);中会塞一个beanFactory。
- 这个beanFactory是上面的obtainFreshBeanFactory()方法生成的。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
- 再进到getBeanFactory()方法中。
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
- 发现他是一个接口方法,那他会也会对应的有很多子实现,我们现在就进入到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;
}
- 发现在第一行将this.Factory赋值给了当前的DefaultListableBeanFactory类型的beanFactory。我ctrl加左键可以查看到beanFactory在AbstractRefreshableApplicationContext中的定义是:
@Nullable
private volatile DefaultListableBeanFactory beanFactory;
- 我们现在再回过头来去看在springFactory初始化之初的时候是怎么样的。
- 我们进入到梦开始的地方:AnnotationConfigApplicationContext中。
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
- 可以看到他是调用了父类的构造器完成的=>GenericApplicationContext的无参构造器
/**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
- 在这里是直接初始化了DefaultListableBeanFactory。