目录
概览
一:单一类型查找(BeanFactory)
二:集合类型依赖查找 - ListableBeanFactory
三:层次性依赖查找 - HierarchicalBeanFactory
四:Bean 延迟依赖查找接口
五:安全依赖查找
六:内建可查找依赖
概览
书接上回,IOC示例,在原有基础上详细罗列分析spring依赖查找的类型及范围,spring大致可以分为以下多种查找类型:
- 单一类型的依赖查找
- 集合类型的依赖查找
- 层次性依赖查找
- 延迟依赖查找
- 安全依赖查找
- 内建可查找的依赖
一:单一类型查找(BeanFactory)
- 根据名称:
- getBean(String)
- getBean(String,Object...) 2.5-
- 根据Bean类型:
- 事实查找
- getBean(Class) --- 3.0
- getBean(Class,Object...) --- 4.1
- 延迟查找 --- 5.1
- getBeanProvider(Class)
- ResolvableType)
- 根据 Bean 名称 + 类型查找:
- getBean(String,Class)
单一类型比较简单,这里举例延迟查找类型
public class ObjectProviderDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ObjectProviderDemo.class);
ctx.refresh();
ObjectProvider<String> 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 <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType) {
return new BeanObjectProvider<T>() {
@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<T> extends ObjectProvider<T>, Serializable {
}
二:集合类型依赖查找 - ListableBeanFactory
- 根据 Bean 类型查找
- 根据类型查找名称列表
- getBeanNamesForType(Class)
- getBeanNamesForType(ResolveType)
- 根据类型查找Bean列表
- getBeansOfType(Class)
- 通过注解类型查找 -- 3.0(jdk5)
- getBeanNamesForAnnotation(Class<? extends Annotation>)
- getBeansWithAnnotation(Class<? extends Annotation>)
- findAnnotationOnBean(String beanName,Class<? extends Annotation>)
根据类型或则根据注解查找在平时开发中使用也是比较广泛,这里就不举例说明了。
三:层次性依赖查找 - HierarchicalBeanFactory
双亲BeanFactory:getParentBeanFactory()
层次性查找
- containsLocalBean()方法实现
- 单一类型:BeanFactoryUtils#beanOfType()
- 集合类型:BeanFactoryUtils#beansOfTypeIncloudingAncestors()
- BeanUitls#beanNamesForTypeIncludingAncestors()
示例:
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<String, String> beansOfType = childCtx.getBeansOfType(String.class);//{hello=hello-child}
System.out.println(beansOfType);
Map<String, Pig> pigs = childCtx.getBeansOfType(Pig.class);
System.out.println(pigs);//{}
//会包含父容器中bean 输出:{hello=hello-child, world=world-parent}
Map<String, String> 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)只会在当前容器中查找。
四:Bean 延迟依赖查找接口
- org.springframework.beans.factory.ObjectFactory
- org.springframework.beans.factory.ObjectProvider
- Spring 5 对 Java 8 特性扩展
- 函数式接口
getIfAvailable(Supplier)
ifAvailable(Consumer)
Stream 扩展 - stream()
在单一类型查找中我们讨论了延迟查找的能力,这里仅列出,就不在赘述。
五:安全依赖查找
六:内建可查找依赖
AbstractApplicationContext内建可查找依赖
注解驱动Spring应用上下文内建可查找依赖
依赖查找中的常见异常:BeansException的子类型