目录
概览
一:单一类型查找(BeanFactory)
二:集合类型依赖查找 - ListableBeanFactory
三:层次性依赖查找 - HierarchicalBeanFactory
四:Bean 延迟依赖查找接口
五:安全依赖查找
六:内建可查找依赖
书接上回,IOC示例,在原有基础上详细罗列分析spring依赖查找的类型及范围,spring大致可以分为以下多种查找类型:
单一类型比较简单,这里举例延迟查找类型
public class ObjectProviderDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ObjectProviderDemo.class);
ctx.refresh();
ObjectProvider beanProvider = ctx.getBeanProvider(String.class);
String object = beanProvider.getObject();
System.out.println(object);
}
@Bean
@Primary
public String hello() {
return "hello";
}
@Bean
public String world() {
return "world";
}
}
这里最终输出字符串“hello”,因为hello上加了@Primary注解
而getBeanProvider()的实现也是对实时查找的一层封装,DefaultListableBeanFactory部分源码:
public ObjectProvider getBeanProvider(ResolvableType requiredType) {
return new BeanObjectProvider() {
@Override
public T getObject() throws BeansException {
T resolved = resolveBean(requiredType, null, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return resolved;
}
@Override
public T getObject(Object... args) throws BeansException {
T resolved = resolveBean(requiredType, args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return resolved;
}
@Override
@Nullable
public T getIfAvailable() throws BeansException {
return resolveBean(requiredType, null, false);
}
...
};
}
BeanObjectProvider的定义在DefaultListableBeanFactory中,而resolveBean()就是实时查找的方法,这里类似于Future体系中的Promise角色。
private interface BeanObjectProvider extends ObjectProvider, Serializable {
}
根据类型或则根据注解查找在平时开发中使用也是比较广泛,这里就不举例说明了。
双亲BeanFactory:getParentBeanFactory()
层次性查找
示例:
public class HierarchicalBeanFactoryDemo {
public static void main(String[] args) {
//parent
AnnotationConfigApplicationContext parentCtx = new AnnotationConfigApplicationContext();
parentCtx.register(ParentConf.class);
parentCtx.refresh();
//child
AnnotationConfigApplicationContext childCtx = new AnnotationConfigApplicationContext();
childCtx.setParent(parentCtx);
childCtx.register(ChildConf.class);
childCtx.refresh();
//test
Object hello = childCtx.getBean("hello");
Object world = childCtx.getBean("world");
System.out.println(hello); //hello-child
System.out.println(world); //world-parent
System.out.println(childCtx.containsLocalBean("hello"));//true
System.out.println(childCtx.containsLocalBean("world"));//false
//list 仅会在子类中查找
Map beansOfType = childCtx.getBeansOfType(String.class);//{hello=hello-child}
System.out.println(beansOfType);
Map pigs = childCtx.getBeansOfType(Pig.class);
System.out.println(pigs);//{}
//会包含父容器中bean 输出:{hello=hello-child, world=world-parent}
Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(childCtx, String.class);
System.out.println(beans);
//输出:[hello, world]
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(childCtx, String.class);
System.out.println(Arrays.toString(names));
//close
childCtx.close();
}
public static class ParentConf {
@Bean
public String hello() {
return "hello-parent";
}
@Bean
public String world() {
return "world-parent";
}
@Bean
public Pig pig() {
return new Pig();
}
}
public static class ChildConf {
@Bean
public String hello() {
return "hello-child";
}
}
}
可见当从子类中查找不到时,会继续迭代在父类容器中继续查找,在FeignClient中就用到了父子容器的实现方式。
同时需要留意的是ListableBeanFactory#beansOfType(Class)只会在当前容器中查找。
在单一类型查找中我们讨论了延迟查找的能力,这里仅列出,就不在赘述。
AbstractApplicationContext内建可查找依赖
注解驱动Spring应用上下文内建可查找依赖
依赖查找中的常见异常:BeansException的子类型