单一类型依赖查找
JNDI ——javax.naming.Context#lookup(javax.naming.Name)
JavaBeans—— java.beans.beancontext.BeanContext
集合类型依赖查找
java.beans.beancontext.BeanContext
层次依赖查找
java.beans.beancontext.BeanContext
public interface BeanContext extends BeanContextChild, Collection, DesignMode, Visibility { // ... }
java.beans.beancontext.BeanContext 针对 GUI 程序以及普通计算程序,Spring 的实现很大程度上参考了其实现,其实现了 Collection 接口,因此其内部所有成员都是 Bean,BeanContext 负责对其进行 crud 操作
Spring 中单一类型依赖查找依赖 BeanFactory 接口,可以根据名称、类型(实时和延迟查找)、名称+类型进行查找。
延迟查找举例如下:
public class ObjectProviderDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ObjectProviderDemo.class); lookupByObjectProvider(context); context.close(); } @Bean public String helloWorld() { return "Hello World"; } private static void lookupByObjectProvider(AnnotationConfigApplicationContext context) { ObjectProviderbeanProvider = context.getBeanProvider(String.class); System.out.println(beanProvider.getObject()); } }
Spring 中集合类型依赖查找依赖 ListableBeanFactory 接口,查找方式如下:
根据 Bean 类型查找
获取同类型 Bean 名称列表(BeanDefinition 中进行查找,Bean 还未实例化)
getBeanNamesForType(Class)
Spring 4.2 getBeanNamesForType(ResolvableType)
获取同类型 Bean 实例列表(Bean 已经实例化或者会触发 Bean 的实例化)
getBeanOfType(Class)以及重载方法
根据注解查找
Spring 3.0 获取标注类型 Bean 名称列表(BeanDefinition 中进行查找,Bean 还未实例化)
getBeanNamesForAnnotation(Class extends Annotation>)
Spring 3.0 获取标注类型 Bean 实例列表(Bean 已经实例化或者会触发 Bean 的实例化)
getBeansWithAnnotation(Class extends Annotation>)
Spring 3.0 获取指定名称+标注类型 Bean 实例(Bean 已经实例化或者会触发 Bean 的实例化)
findAnnotationOnBean(String, Class extends Annotation>)
层次型依赖查找依赖 HierarchicalBeanFactory 接口
父 BeanFactory:getParentBenaFactory
层次性查找
根据 Bean 名称查找
基于 containsLocalBean 方法实现(当前 BeanFactory 查找,不包含父类 BeanFactory)
根据 Bean 类型查找实例列表
单一类型:BeanFactoryUtils#beanOfType
集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
根据 Java 注解查找名称列表
BeanFactoryUtils#beanNamesForTypeIncludingAncestors
真正使用时通过使用 ConfigurableListableBeanFactory 来使用,接口间继承关系如下:
// 父子级联容器接口(类似双亲委派,优先在父容器中查找,找不到才在子容器中查找) public interface HierarchicalBeanFactory extends BeanFactory { /** * Return the parent bean factory, or {@code null} if there is none. */ @Nullable BeanFactory getParentBeanFactory(); /** * Return whether the local bean factory contains a bean of the given name, * ignoring beans defined in ancestor contexts. *This is an alternative to {@code containsBean}, ignoring a bean * of the given name from an ancestor bean factory. * @param name the name of the bean to query * @return whether a bean with the given name is defined in the local factory * @see BeanFactory#containsBean */ boolean containsLocalBean(String name); } // 可配置容器接口,包含父子级联功能以及单例注册功能,自己新增的功能有配置BeanFacory的属性,比如BeanPostProcessor、PropertyEditor等 public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry { // ... } // 可配置容器接口,包含集合容器功能、自动注入(非Spring管理的Bean实现依赖注入,被注入的对象必须是Spring容器内的对象)、可配置容器接口(父子级联、单例注册) public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory { // ... }
根据名称查找举例:
public class HierarchicalDependencyLookupDemo { public static void main(String[] args) { // 创建 BeanFactory 容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(HierarchicalDependencyLookupDemo.class); // 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListableBeanFactory ConfigurableListableBeanFactory factory = context.getBeanFactory(); System.out.println("当前 BeanFactory 的 parent :" + factory.getParentBeanFactory()); // 添加 parentBeanFactory HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory(); factory.setParentBeanFactory(parentBeanFactory); System.out.println("当前 BeanFactory 的 parent :" + factory.getParentBeanFactory()); displayContainsBean(factory, "user"); displayLocalBean(factory, "user"); displayLocalBean(parentBeanFactory, "user"); // 启动上下文 context.refresh(); // 关闭上下文 context.close(); } // 创建父容器 private static HierarchicalBeanFactory createParentBeanFactory() { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions("classpath:beans-ioc-lookup.xml"); return factory; } private static void displayLocalBean(HierarchicalBeanFactory factory, String beanName) { System.out.printf("当前 BeanFactory[%s] 是否包含 Local Bean[name: %s] : %s\n", factory, beanName, factory.containsLocalBean(beanName)); } private static void displayContainsBean(HierarchicalBeanFactory factory, String beanName) { System.out.printf("当前 BeanFactory[%s] 是否包含 Bean[name: %s] : %s\n", factory, beanName, containsBean(factory, beanName)); } // 类似双亲委派,优先从父容器中查找,递归查找 private static boolean containsBean(HierarchicalBeanFactory factory, String beanName) { BeanFactory parentBeanFactory = factory.getParentBeanFactory(); if (parentBeanFactory instanceof HierarchicalBeanFactory) { HierarchicalBeanFactory hierarchicalBeanFactory = (HierarchicalBeanFactory) parentBeanFactory; if (containsBean(hierarchicalBeanFactory, beanName)) { return true; } } return factory.containsLocalBean(beanName); } } // 输出结果: 当前 BeanFactory 的 parent :null 当前 BeanFactory 的 parent :org.springframework.beans.factory.support.DefaultListableBeanFactory@282003e1: defining beans [user,superUser,userRepository,objectFactory]; root of factory hierarchy 当前 BeanFactory[org.springframework.beans.factory.support.DefaultListableBeanFactory@25359ed8: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,hierarchicalDependencyLookupDemo]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@282003e1] 是否包含 Bean[name: user] : true 当前 BeanFactory[org.springframework.beans.factory.support.DefaultListableBeanFactory@25359ed8: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,hierarchicalDependencyLookupDemo]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@282003e1] 是否包含 Local Bean[name: user] : false 当前 BeanFactory[org.springframework.beans.factory.support.DefaultListableBeanFactory@282003e1: defining beans [user,superUser,userRepository,objectFactory]; root of factory hierarchy] 是否包含 Local Bean[name: user] : true
延迟查找依赖的接口:
org.springframework.beans.factory.ObjectFactory
org.springframework.beans.factory.ObjectProvider
Spring 5 对 Java 8 特性扩展
函数式接口
getIfAvailable(Supplier)
ifAvailable(Consumer)
Stream 扩展——stream()
思考:非延迟初始化的 bean 是否能够实现延迟查找?
public class ObjectProviderDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(ObjectProviderDemo.class); context.refresh(); lookupByObjectProvider(context); lookupIfAvailable(context); lookupByStreamOps(context); context.close(); } private static void lookupByStreamOps(AnnotationConfigApplicationContext context) { ObjectProviderprovider = context.getBeanProvider(String.class); provider.stream().forEach(System.out::println); } private static void lookupIfAvailable(AnnotationConfigApplicationContext context) { ObjectProvider beanProvider = context.getBeanProvider(User.class); User user = beanProvider.getIfAvailable(User::user); System.out.println("当前 User 对象:" + user); } @Bean @Primary public String helloWorld() { return "Hello World"; } @Bean public String message() { return "Message"; } private static void lookupByObjectProvider(AnnotationConfigApplicationContext context) { ObjectProvider beanProvider = context.getBeanProvider(String.class); System.out.println(beanProvider.getObject()); } }
依赖查找安全性对比:
依赖查找类型 | 代表实现 | 是否安全 |
---|---|---|
单一类型查找 | BeanFactory#getBean | 否 |
ObjectFactory#getObject | 否 | |
ObjectProvider#getIfAvailable | 是 | |
集合类型查找 | ListableBeanFactory#getBeansOfType | 是 |
ObjectProvider#stream | 是 |
安全与否在于调用方法进行依赖查找时是否会触发异常。
层次类型依赖查找安全性依赖于单一或者集合类型依赖查找安全性
推荐使用 ObjectProvider 进行依赖查找,因为可以实现单一和集合类型查找,并且查找是安全的
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 应用上下文内建可查找依赖(部分)(componentScan或者使用ApplicaitonContext激活这些内部 Bean)(名称很长也比较难记,可以在AnnotationConfigUtils类中进行查找)
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
org.springframework.context.annotation.internalConfigurationClassPostProcessor(BeanFactory生命周期) | ConfigurationClassPostProcessor对象 | 处理 Spring 配置类 |
org.springframework.context.annotation.internalAutoWiredAnnotationBeanPostProcessor | AutoWiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @ Value 注解 |
org.springframework.context.annotation.internalCommonAnnotationBeanPostProcessor | CommonAnnotationBeanPostProcessor 对象 | (条件激活)处理 JSR-250 注解,如 @PostConstructor 等 |
org.springframework.context.annotation.internalEventListenerMethodProcessor | EventListenerMethodProcessor 对象 | 处理标注 @EventListener 的 Spring 事件监听方法 |
org.springframework.context.annotation.internalDefaultEventListenerFactory | DefaultEventListenerFactory | @EventListener 事件监听方法适配为 ApplicationListener |
org.springframework.context.annotation.internalPersistenceAnnotationBeanPostProcessor | PersistenceAnnotationBeanPostProcessor | (条件激活)处理 JPA 注解场景 |
BeansException 子类型(非 check 异常,Runtime 异常)
异常类型 | 触发条件(举例) | 场景举例 |
---|---|---|
NoSuchBeanDefinitionException | 当查找 Bean 不存在于 IoC 容器时 | BeanFactory#getBean ObjectFactory#getObject |
NoUniqueBeanDefinitionException | 类型依赖查找时,IoC 容器存在多个 Bean 实例 | BeanFactory#getBean |
BeanInstantiationException | 当 Bean 所对应的类型非具体类型时 | BeanFactory#getBean |
BeanCreationException | 当 Bean 初始化过程出错 | Bean 初始化方法执行异常时 |
BeanDefinitionStoreException | 当 BeanDefinition 配置元信息非法时 | XML 配置资源无法打开时 |
5.9.1 ObjectFactory 和 BeanFactory 区别
ObjectFactory 是 Spring 比较早期的接口,ObjectFactory 和 BeanFactory 均提供依赖查找功能,不同点:
BeanFactory 仅关注一个或一种类型的 Bean 依赖查找,并且自身不具备依赖查找的能力,能力由 BeanFactory 支撑
BeanFactory 提供单一类型、集合类型以及层次性等多种依赖查找功能
从实用也可以看出:
public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean> { @Nullable private String targetBeanName; /** * Set the name of the target bean. * The target does not have to be a non-singleton bean, but realistically * always will be (because if the target bean were a singleton, then said singleton * bean could simply be injected straight into the dependent object, thus obviating * the need for the extra level of indirection afforded by this factory approach). */ public void setTargetBeanName(String targetBeanName) { this.targetBeanName = targetBeanName; } @Override public void afterPropertiesSet() throws Exception { Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required"); super.afterPropertiesSet(); } @Override public Class> getObjectType() { return ObjectFactory.class; } @Override protected ObjectFactory
5.9.2 BeanFactory#getBean 方法是否线程安全
是线程安全的,操作过程中会通过 synchronized 加锁,jdk 5 update 6 中新增偏向锁功能,该功能可以大大降低 synchronized 关键字的重量,在只有一个线程访问时,可以将只看为没有锁(只有加锁时会执行一个 CAS 操作将锁偏向当前线程,后续该线程运行到加锁位置只会比较偏向锁线程是否为当前线程,是的话就通过 CAS 替换一次 lock record,后续不再加锁),因此不建议将启动过程放在子线程执行,就在 main 主线程执行性能是最好的
5.9.4 Spring 的依赖查找和依赖注入在来源上有什么区别
依赖查找只能查询容器中有的 Bean(手动注入或者框架内建),但是依赖注入除了容器中有的 Bean 以外,还支持注入非 Bean 对象(内建依赖)