依赖查找的前生
单一类型依赖查找
JNDI- javax.naming.Context#lookup(javax.naming.Name);
JNDI- javax.naming.Context#lookup(String);
JavaBeans - java.beans.beancontext.BeanContext
BeanContext 继承了 Collection 接口,BeanContext 中的所有成员都是 bean
集合类型依赖查找
通过一个 key,找到对应的多个实例
java.beans.beancontext.BeanContextServices 的 Iterator getCurrentServiceSelectors(Class serviceClass);
层级性依赖查找
单一类型依赖查找
根据 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)
相关代码:
/*** 通过 ObjectProvider 依赖查找** @author mindartisan.blog.csdn.net* @date** @commet @Bean 定义的类在当前类,当前类默认就是配置类,不用写 「@Configuration」注解,** @Configuration 非必需注解:https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/context/annotation/Bean.html*/public class ObjectProviderDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 将当前类作为配置类applicationContext.register(ObjectProviderDemo.class);// 启动应用上下文applicationContext.refresh();lookupByObjectProvider(applicationContext);applicationContext.close();}@Bean// 此时的 Bean 名称就是方法名称public String helloWorld() {return "Hello,World";}private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);System.out.println(objectProvider.getObject());}}
根据 Bean 名称+类型查找
集合类型依赖查找
用到了ListableBeanFactory 接口,推荐使用 bean 名称判断 bean 是否存在。
根据 Bean 类型查找
Bean 名称可以先定义,但是实例必须得初始化
获取同类型 Bean 名称列表
getBeanNamesForType(Class)
Spring 4.2 getBeanNameForType(ResolvableType)
获取同类型的 Bean 实例列表
根据注解类型查找
Spring 3.0 获取标注类型 Bean 名称列表
getBeanNamesForAnnotation(Class<?extends Annotation>)
Spring 3.0 获取标注类型 Bean 实例列表
getBeansWithAnnotation(Class<?extends Annotation>)
Spring 3.0 获取指定名称+标注类型 Bean 实例
findAnnotationOnBean(String,Class<?extends Annotation>)
层次性依赖查找
用到了HierarchicalBeanFactory接口,方法为 getParentBeanFactory()
注意下图中 ConfigurableListBeanFactory 继承 ConfigurableBeanFactory 以及 ListableBeanFactory 接口。
根据 Bean 名称查找
根据 Bean 类型查找实例列表
单一类型:使用BeanFactoryUtils#beanOfTypeIncludingAncestors
集合类型:使用BeanFactoryUtils#beansOfTypelncludingAncestors
相关代码:
HierarchicalDependencyLookupDemo.class
/*** 层次性依赖查找示例** @author mindartisan.blog.csdn.net* @date*/public class HierarchicalDependencyLookupDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 将当前类作为配置类,此处不用也行,因为当前类里没有 @BeanapplicationContext.register(HierarchicalDependencyLookupDemo.class);// 1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListBeanFactoryConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();System.out.println("当前 BeanFactory 的 parent BeanFactory:" + beanFactory.getParentBeanFactory());// 2. 设置 parent BeanFactoryConfigurableListableBeanFactory parentBeanFactory = createParentBeanFactory();beanFactory.setParentBeanFactory(parentBeanFactory);System.out.println("当前 BeanFactory 的 parent BeanFactory:" + beanFactory.getParentBeanFactory());System.out.println("------------------------");displayContainsLocalBean(beanFactory,"user");displayContainsLocalBean(parentBeanFactory,"user");displayContainsBean(beanFactory,"user");displayContainsBean(parentBeanFactory,"user");// 启动应用上下文applicationContext.refresh();applicationContext.close();}private static void displayContainsBean(HierarchicalBeanFactory beanFactory,String beanName) {System.out.printf("当前 BeanFactory[%s] 是否包含 Bean[name: %s] : %s\n", beanFactory, beanName,containsBean(beanFactory, beanName));}private static boolean containsBean(HierarchicalBeanFactory beanFactory,String beanName) {BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();if (parentBeanFactory instanceof HierarchicalBeanFactory) {HierarchicalBeanFactory hierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);if (containsBean(hierarchicalBeanFactory, beanName)) {return true;}}return beanFactory.containsLocalBean(beanName);}private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {System.out.printf("当前 BeanFactory[%s] 是否包含 LocalBean[name: %s] : %s\n", beanFactory, beanName,beanFactory.containsLocalBean(beanName));}private static ConfigurableListableBeanFactory createParentBeanFactory() {// 创建 BeanFactory 容器DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(defaultListableBeanFactory);String location = "classpath:/META-INF/dependency-lookup-context.xml";// 加载配置reader.loadBeanDefinitions(location);return defaultListableBeanFactory;}}
注意 pom.xml 的依赖要「 复用 ioc-container-overview 」
根据 Java 注解查找名称列表
使用 BeanFactoryUtils#beanNamesForTypeIncludingAncestors
延迟依赖查找
通过 org.springframework.beans.factory.ObjectFactory接口以及org.springframework.beans.factory.ObjectProvider接口实现,后者继承了前者,可以调用前者的getObject()获取当前关联的 bean。
其中使用到了 Java 8 的新特性:
- 函数式接口
- Stream
相关代码:
ObjectProviderDemo.class
/*** 通过 ObjectProvider 依赖查找** @author mindartisan.blog.csdn.net* @date** @commet @Bean 定义的类在当前类,当前类默认就是配置类,不用写 「@Configuration」注解,** @Configuration 非必需注解:https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/context/annotation/Bean.html*/public class ObjectProviderDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 将当前类作为配置类applicationContext.register(ObjectProviderDemo.class);// 启动应用上下文applicationContext.refresh();lookupByObjectProvider(applicationContext);lookupIfAvaiable(applicationContext);lookupByStreamOps(applicationContext);applicationContext.close();}private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) {ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);// Iterable<String> stringIterable = objectProvider;// for (String string : stringIterable) {// System.out.println(string);// }objectProvider.stream().forEach(System.out::println);}private static void lookupIfAvaiable(AnnotationConfigApplicationContext applicationContext) {ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);// 这里演示的是如果 User 不存在的话,进行兜底:// 此时「getIfAvailable(User::createUser)」会创建一个新的 User,如果是 getIfAvailable(),则会输出 nullUser user = userObjectProvider.getIfAvailable(User::createUser);System.out.println("当前 User 对象:" + user);}private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);System.out.println(objectProvider.getObject());}@Bean@Primary// 此时的 Bean 名称就是方法名称public String helloWorld() {return "Hello,World";}@Beanpublic String message() {return "Message";}}
安全依赖查找
此处的安全是指是否抛出异常
单一类型查找
BeanFactory#getBean -> 不安全
ObjectFactory#getObject -> 不安全
ObjectProvider#getIfAvailable -> 安全
集合类型查找
ListableBeanFactory#getBeansOfType -> 安全
ObjectProvider#stream -> 安全
层级类型依赖
相关代码
TypeSafetyDependencyLookupDemo.class:
*** 类型安全依赖查找示例** @author mindartisan.blog.csdn.net* @date*/public class TypeSafetyDependencyLookupDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 将当前类作为配置类applicationContext.register(TypeSafetyDependencyLookupDemo.class);// 启动应用上下文applicationContext.refresh();// 演示 beanFactory#getBean 安全性displayBeanFactoryGetBean(applicationContext);// 演示 ObjectFactory#getObject 安全性displayObjectFactoryGetBean(applicationContext);// 演示 ObjectProvider#getIfAvaiable 方法的安全性displayObjectProviderIfAvailable(applicationContext);// 演示 ListableBeanFactory#getBeansOfType 方法的安全性displayListableBeanFactoryGetBeansOfType(applicationContext);// 演示 ObjectProvider Stream 操作的安全性displayObjectProviderStreamOps(applicationContext);// 关闭应用上下文applicationContext.close();}/*** 演示 ObjectProvider Stream 操作的安全性** @param beanFactory bean工厂*/private static void displayObjectProviderStreamOps(BeanFactory beanFactory) {// 不抛异常ObjectProvider<User> userObjectProvider = beanFactory.getBeanProvider(User.class);printBeansException("displayObjectProviderStreamOps", () -> userObjectProvider.forEach(System.out::println));}/*** 演示 ListableBeanFactory#getBeansOfType 方法的安全性** @param beanFactory bean工厂*/private static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory beanFactory) {// 不抛异常printBeansException("displayListableBeanFactoryGetBeansOfType", () -> beanFactory.getBeansOfType(User.class));}/*** 演示 ObjectProvider#getIfAvaiable 方法的安全性** @param beanFactory bean工厂*/private static void displayObjectProviderIfAvailable(BeanFactory beanFactory) {// 不抛异常ObjectProvider<User> userObjectProvider = beanFactory.getBeanProvider(User.class);printBeansException("displayObjectProviderIfAvailable", () -> userObjectProvider.getIfAvailable());}/*** 演示 ObjectFactory#getObject 安全性** @param beanFactory bean工厂*/private static void displayObjectFactoryGetBean(BeanFactory beanFactory) {// 抛出「org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com// .mindartisan.spring.geek.ioc.overview.domain.User' 」异常ObjectProvider<User> userObjectProvider = beanFactory.getBeanProvider(User.class);printBeansException("displayObjectFactoryGetBean", userObjectProvider::getObject);}/*** 演示 beanFactory#getBean 安全性** @param beanFactory bean工厂*/public static void displayBeanFactoryGetBean(BeanFactory beanFactory) {// 此时并无 User 对应的 bean,抛出「org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mindartisan.spring.geek.ioc.overview.domain.User' available」异常printBeansException("displayBeanFactoryGetBean", () -> beanFactory.getBean(User.class));}public 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此抽象类实现,会在上下文启动的过程中会初始化一些内部的依赖,称为内建的可查询依赖。
AbstractApplicationContext 内建可查找的依赖
| Bean 名称 | Bean 实例 | 使用场景 |
|---|---|---|
| environment | Environment 对象 | 外部化配置:Java 系统的属性,比如 -D 参数 Profiles:比如 dev、test |
| systemProperties | java.util.Properties 对象 | Java 系统属性、系统路径或目录 |
| systemEnvironment | java.util.Map 对象 | 操作系统的环境变量(主要指当前用户环境变量) |
| messageSource | MessageSource 对象 | 国际化文案 |
| lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器(Bean 生命周期) |
| applicationEventMulticaster | ApplicationEventMulticaster 对象 | 事件广播 |
注解驱动 Spring 应用上下文内建可查找的依赖
AnnotationConfigUtils 里的常量
| Bean 名称 | Bean 实例 | 使用场景 |
|---|---|---|
| org.springframework.context. annotation.internalConfigur ationAnnotationProcessor |
ConfigurationClassPostProcessor 对象 | 用来处理 Spring 配置类 |
| org.springframework.context. annotation.internalAutowire dAnnotationProcessor |
AutowiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @Value 注解(构造器代码里 add 了上述两个注解) |
| org.springframework.context. annotation.internalCommonAn notationProcessor |
CommonAnnotationBeanPostProcessor 对象 | (条件激活)处理 JSR-250 注解, 如 @PostConstruct 等 |
| org.springframework.context. event.internalEventListener Processor |
EventListenerMethodProcessor 对象 | 处理标注 @EventListener 的 Spring 事件监听方法(直接标注在方法上就行,无需实现 ApplicationListener 接口) |
| org.springframework.context. event.internalEventListener Factory |
DefaultEventListenerFactory 对 象 |
@EventListener 事件监听方法适 配为 ApplicationListener |
| org.springframework.context. annotation.internalPersiste nceAnnotationProcessor |
PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解场景 |
依赖查找中的经典异常
| 异常类型 | 触发条件 | 场景举例 |
|---|---|---|
| NoSuchBeanDefinitionException | 当查找 Bean 不存在于 IoC 容器时 | BeanFactory#getBean ObjectFactory#getObject |
| NoUniqueBeanDefinitionException | 类型依赖查找时,IoC 容器存在多 个 Bean 实例 |
BeanFactory#getBean(Clas s |
| BeanInstantiationException | 当 Bean 所对应的类型非具体类时 | BeanFactory#getBean |
| BeanCreationException | 当 Bean 初始化过程中 | Bean 初始化方法执行异常 时 |
| BeanDefinitionStoreException | 当 BeanDefinition 配置元信息非 法时 |
XML 配置资源无法打开时 |
相关代码:
NoUniqueBeanDefinitionExceptionDemo.class
/*** 没有具体的 bean 定义异常示例** @author mindartisan.blog.csdn.net* @date*/public class NoUniqueBeanDefinitionExceptionDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 将当前类作为配置类applicationContext.register(NoUniqueBeanDefinitionExceptionDemo.class);// 启动应用上下文applicationContext.refresh();try {applicationContext.getBean(String.class);} catch (NoUniqueBeanDefinitionException e) {System.err.printf("Spring 应用上下文当前存在 %d 个 %s 类型的 Bean,具体原因:%s",e.getNumberOfBeansFound(),String.class.getName(),e.getMessage());}// 关闭应用上下文applicationContext.close();}@Beanpublic String bean1() {return "bean1";}@Beanpublic String bean2() {return "bean2";}}
BeanInstantiationException.class
/*** bean 实例化异常示例** @author mindartisan.blog.csdn.net* @date*/public class BeanInstantiationExceptionDemo {public static void main(String[] args) {// 创建 BeanFactory 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Character.class);// 下面的不会有异常// BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(String.class);applicationContext.registerBeanDefinition("errorBean",beanDefinitionBuilder.getBeanDefinition());// 启动应用上下文applicationContext.refresh();// 关闭应用上下文applicationContext.close();}}
BeanCreationExceptionDemo.class
*** bean 创建异常示例** @author mindartisan.blog.csdn.net* @date*/public class BeanCreationExceptionDemo {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 // CommonAnnotationBeanPostProcessorpublic void init() throws Throwable {throw new Throwable("init() : For purposes...");}@Overridepublic void afterPropertiesSet() throws Exception {throw new Exception("afterPropertiesSet() : For purposes...");}}}
