第五章:Spring IoC依赖查找(Dependency Lookup)
背景
传统 Java 技术中的依赖查找
- 单一类型
- JNDI - javax.naming.Context#lookup(javax.naming.Name)
- JavaBeans - java.beans.beancontext.BeanContext
- 集合类型
- java.beans.beancontext.BeanContext
- 层次性
- java.beans.beancontext.BeanContext
单一类型依赖查找
- 根据 Bean 名称查找
- getBean(String)
- Spring 2.5 覆盖默认参数:getBean(String,Object…)
- 根据 Bean 类型查找
- Bean 实时查找
- Spring 3.0 : getBean(Class)
- Spring 4.1 覆盖默认参数: getBean(Class,Object…)
- Spring 5.1 Bean 延迟查找
- getBeanProvider(Class)
- getBeanProvider(ResolvableType)
- Bean 实时查找
- 根据 Bean 名称 + 类型查找
- getBean(String,Class)
public class ObjectProviderDemo { // @Configuration 是非必须注解
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 ObjectProviderDemo 作为配置类(Configuration Class)
applicationContext.register(ObjectProviderDemo.class);
// 启动应用上下文
applicationContext.refresh();
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
System.out.println(objectProvider.getObject());
// 关闭应用上下文
applicationContext.close();
}
@Bean
@Primary
public String helloWorld() { // 方法名就是 Bean 名称 = "helloWorld"
return "Hello,World";
}
}
集合类型依赖查找
- 集合类型依赖查找接口 - ListableBeanFactory
- 根据 Bean 类型查找
- 获取同类型 Bean 名称列表
- getBeanNamesForType(Class)
- Spring 4.2 : getBeanNamesForType(ResolvableType)
- 获取同类型 Bean 实例列表
- getBeansOfType(Class) 以及重载方法
- 获取同类型 Bean 名称列表
- 通过注解类型查找
- Spring 3.0 获取标注类型 Bean 名称列表
- getBeanNamesForAnnotation(Class<? extends Annotation>)
- Spring 3.0 获取标注类型 Bean 实例列表
- getBeansWithAnnotation(Class<? extends Annotation>)
- Spring 3.0 获取指定名称 + 标注类型
- findAnnotationOnBean(String ,Class<? extends Annotation>)
- Spring 3.0 获取标注类型 Bean 名称列表
- 根据 Bean 类型查找
层次性依赖查找
- 层次性依赖查找接口 - HierarchicalBeanFactory
- 双亲 BeanFactory : getParentBeanFactory()
- 层次性查找
- 根据 Bean 名称查找
- 基于 containsLocalBean 方法实现
- 根据 Bean 类型查找实例列表
- 单一类型: BeanFactoryUtils#beanOfType
- 集合类型: BeanFactoryUtils#beansOfTypeIncludingAncestors
- 根据 Java 注解查找名称列表
- BeanFactoryUtils#beanNamesForTypeIncludingAncestors
- 根据 Bean 名称查找
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 ObjectProviderDemo 作为配置类(Configuration Class)
applicationContext.register(ObjectProviderDemo.class);
// 1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListableBeanFactory
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
// 2. 设置 Parent BeanFactory
HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
beanFactory.setParentBeanFactory(parentBeanFactory);
}
private static ConfigurableListableBeanFactory createParentBeanFactory() {
// 创建 BeanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// XML 配置文件 ClassPath 路径
String location = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载配置
reader.loadBeanDefinitions(location);
return beanFactory;
}
public interface ConfigurableListableBeanFactory
extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {}
public interface ListableBeanFactory extends BeanFactory {
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();
}
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
}
public interface HierarchicalBeanFactory extends BeanFactory {
BeanFactory getParentBeanFactory();
boolean containsLocalBean(String name);
}
// 依赖查找也有双亲委派
private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) {
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
if (parentBeanFactory instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
if (containsBean(parentHierarchicalBeanFactory, beanName)) {
return true;
}
}
return beanFactory.containsLocalBean(beanName);
}
延迟依赖查找
- Bean 延迟依赖查找接口
- org.springframework.beans.factory.ObjectFactory
- org.springframework.beans.factory.ObjectProvider
- ObjectFactory 的子类
- Spring 5 对 Java 8 的特性扩展
- 函数式接口
- T getIfAvailable(Supplier )
- void ifAvailable(Consumer )
- Stream 扩展
- Stream stream()
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
User user = userObjectProvider.getIfAvailable(User::createUser);
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
objectProvider.stream().forEach(System.out::println);
安全依赖查找
依赖查找类型 | 代表实现 | 是否安全 |
---|---|---|
单一类型查找 | BeanFactory#getBean | 否 |
单一类型查找 | ObjectFactory#getObject | 否 |
单一类型查找 | ObjectProvider #getIfAvailable | 是 |
集合类型查找 | LisableBeanFactory#getBeansOfType | 是 |
集合类型查找 | ObjectProvider#stream | 是 |
层次性依赖查找的安全性取决于其扩展的单一类型或集合类型的 BeanFactory 接口
public class TypeSafetyDependencyLookupDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 TypeSafetyDependencyLookupDemo 作为配置类(Configuration Class)
applicationContext.register(TypeSafetyDependencyLookupDemo.class);
// 启动应用上下文
applicationContext.refresh();
// 演示 BeanFactory#getBean 方法的安全性
displayBeanFactoryGetBean(applicationContext);
// 演示 ObjectFactory#getObject 方法的安全性
displayObjectFactoryGetObject(applicationContext);
// 演示 ObjectProvider#getIfAvaiable 方法的安全性
displayObjectProviderIfAvailable(applicationContext);
// 演示 ListableBeanFactory#getBeansOfType 方法的安全性
displayListableBeanFactoryGetBeansOfType(applicationContext);
// 演示 ObjectProvider Stream 操作的安全性
displayObjectProviderStreamOps(applicationContext);
// 关闭应用上下文
applicationContext.close();
}
private static void displayObjectProviderStreamOps(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
printBeansException("displayObjectProviderStreamOps", () -> userObjectProvider.forEach(System.out::println));
}
private static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory beanFactory) {
printBeansException("displayListableBeanFactoryGetBeansOfType", () -> beanFactory.getBeansOfType(User.class));
}
private static void displayObjectProviderIfAvailable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
printBeansException("displayObjectProviderIfAvailable", () -> userObjectProvider.getIfAvailable());
}
private static void displayObjectFactoryGetObject(AnnotationConfigApplicationContext applicationContext) {
// ObjectProvider is ObjectFactory
ObjectFactory<User> userObjectFactory = applicationContext.getBeanProvider(User.class);
printBeansException("displayObjectFactoryGetObject", () -> userObjectFactory.getObject());
}
public static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
printBeansException("displayBeanFactoryGetBean", () -> beanFactory.getBean(User.class));
}
private static void printBeansException(String source, Runnable runnable) {
System.err.println("==========================================");
System.err.println("Source from :" + source);
try {
runnable.run();
} catch (BeansException exception) {
exception.printStackTrace();
}
}
}
内建可查找的依赖
AbstractApplicationContext 内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
environment | Environment 对象 | 外部化配置以及 Profiles |
systemProperties | java.util.Properties 对象 | Java 系统属性 |
systemEnvironment | java.util.Map 对象 | 操作系统环境变量 |
messageSource | MessageSource 对象 | 国际化文案 |
lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 |
applicationEventMulticaster | ApplicationEventMulticaster 对象 | Spring 事件广播器 |
注解驱动 Spring 应用上下文内建可查找的依赖
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
org.springframework.context.annotation.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcessor 对象 | 处理 Spring 配置类 |
org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @Value 注解 |
org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanProcessor 对象 | (条件激活)处理 JSR-250 注解 ,如 @PostContruct |
org.springframework.context.event.internalEventListenerProcessor | EventListenerMethodProcessor 对象 | 处理标注 @EventListener 的 Spring 事件监听方法 |
org.springframework.context.event.internalEventListenerFactory | DefaultEventListenerFactory 对象 | @EventListener 事件监听方法适配为 ApplicationListener |
org.springframework.context.annotation.internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解 |
org.springframework.context.annotation.AnnotationConfigUtils
依赖查找中的常见异常
BeansException 子类型
异常类型 | 触发条件(部分) | 场景举例 |
---|---|---|
NoSuchBeanDefinitionException | 当查找 Bean 不存在于 IoC 容器时 | BeanFactory#getBean ObjectFactory#getObject |
NoUniqueBeanDefinitionException | 类型依赖查找时,IoC 容器存在多个 Bean 实例 | BeanFactory#getBean(Class) |
BeanInstantiationException | 当 Bean 所对应的类型非具体类时 | BeanFactory#getBean |
BeanCreationException | 当 Bean 初始化过程中 | Bean 初始化方法执行异常时 |
BeanDefinitionStoreException | 当 BeanDifinition 配置元信息非法时 | XML 配置资源无法打开时 |
// BeanInstantiationException
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 BeanDefinition Bean Class 是一个 CharSequence 接口
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CharSequence.class);
applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());
// 启动应用上下文
applicationContext.refresh();
// 关闭应用上下文
applicationContext.close();
}
// BeanCreationException
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 BeanDefinition Bean Class 是一个 POJO 普通类,不过初始化方法回调时抛出异常
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(POJO.class);
applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());
// 启动应用上下文
applicationContext.refresh();
// 关闭应用上下文
applicationContext.close();
}
static class POJO implements InitializingBean {
@PostConstruct // CommonAnnotationBeanPostProcessor
public void init() throws Throwable {
throw new Throwable("init() : For purposes...");
}
@Override
public void afterPropertiesSet() throws Exception {
throw new Exception("afterPropertiesSet() : For purposes...");
}
}
总结
- ObjectFactory 与 BeanFactory 的区别?
BeanFactory 是 Spring 底层的 IoC 容器,提供了单一类型、集合类型、层次性等多种依赖查找方式;
ObjectFactory 仅关注一种类型的 Bean 的依赖查找,并且底层依然是使用 ioc 容器进行依赖查找然后输出;
ObjectProvider 继承 ObjectFactory ;
- BeanFactory.getBean 操作是否线程安全?
是线程安全的,操作过程中会增加互斥锁;
// DefaultListableBeanFactory
private void updateManualSingletonNames(Consumer<Set<String>> action, Predicate<Set<String>> condition) {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
if (condition.test(this.manualSingletonNames)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
action.accept(updatedSingletons);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
if (condition.test(this.manualSingletonNames)) {
action.accept(this.manualSingletonNames);
}
}
}
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames);
updatedDefinitions.remove(beanName);
this.beanDefinitionNames = updatedDefinitions;
}
}