单一类型依赖查找
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)
Spring 3.0 获取标注类型 Bean 实例列表(Bean 已经实例化或者会触发 Bean 的实例化)
getBeansWithAnnotation(Class)
Spring 3.0 获取指定名称+标注类型 Bean 实例(Bean 已经实例化或者会触发 Bean 的实例化)
findAnnotationOnBean(String, Class)
层次型依赖查找依赖 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 对象(内建依赖)