依赖查找的前生
单一类型依赖查找
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();
// 将当前类作为配置类,此处不用也行,因为当前类里没有 @Bean
applicationContext.register(HierarchicalDependencyLookupDemo.class);
// 1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListBeanFactory
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
System.out.println("当前 BeanFactory 的 parent BeanFactory:" + beanFactory.getParentBeanFactory());
// 2. 设置 parent BeanFactory
ConfigurableListableBeanFactory 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(),则会输出 null
User 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";
}
@Bean
public 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();
}
@Bean
public String bean1() {
return "bean1";
}
@Bean
public 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 // CommonAnnotationBeanPostProcessor
public void init() throws Throwable {
throw new Throwable("init() : For purposes...");
}
@Override
public void afterPropertiesSet() throws Exception {
throw new Exception("afterPropertiesSet() : For purposes...");
}
}
}