依赖查找的前生
单一类型依赖查找
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);
层级性依赖查找
单一类型依赖查找
用到了 BeanFactory 接口
根据 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)
相关代码:
public class ObjectProviderDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ObjectProviderDemo.class);
applicationContext.refresh();
lookupByObjectProvider(applicationContext);
applicationContext.close();
}
@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 名称+类型查找
getBean(String,Class)
集合类型依赖查找
用到了ListableBeanFactory 接口,推荐使用 bean 名称判断 bean 是否存在。
根据 Bean 类型查找
Bean 名称可以先定义,但是实例必须得初始化
获取同类型 Bean 名称列表
getBeanNamesForType(Class)
Spring 4.2 getBeanNameForType(ResolvableType)
获取同类型的 Bean 实例列表
getBeansOfType(Class) 及其重载方法
根据注解类型查找
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 名称查找
基于 containsLocalBean() 实现
根据 Bean 类型查找实例列表
单一类型:使用BeanFactoryUtils#beanOfTypeIncludingAncestors
集合类型:使用BeanFactoryUtils#beansOfTypelncludingAncestors
相关代码:
HierarchicalDependencyLookupDemo.class
public class HierarchicalDependencyLookupDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(HierarchicalDependencyLookupDemo.class);
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
System.out.println("当前 BeanFactory 的 parent BeanFactory:" + beanFactory.getParentBeanFactory());
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() {
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
public class ObjectProviderDemo {
public static void main(String[] args) {
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);
objectProvider.stream().forEach(System.out::println);
}
private static void lookupIfAvaiable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
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
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) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(TypeSafetyDependencyLookupDemo.class);
applicationContext.refresh();
displayBeanFactoryGetBean(applicationContext);
displayObjectFactoryGetBean(applicationContext);
displayObjectProviderIfAvailable(applicationContext);
displayListableBeanFactoryGetBeansOfType(applicationContext);
displayObjectProviderStreamOps(applicationContext);
applicationContext.close();
}
private static void displayObjectProviderStreamOps(BeanFactory beanFactory) {
ObjectProvider<User> userObjectProvider = beanFactory.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(BeanFactory beanFactory) {
ObjectProvider<User> userObjectProvider = beanFactory.getBeanProvider(User.class);
printBeansException("displayObjectProviderIfAvailable", () -> userObjectProvider.getIfAvailable());
}
private static void displayObjectFactoryGetBean(BeanFactory beanFactory) {
ObjectProvider<User> userObjectProvider = beanFactory.getBeanProvider(User.class);
printBeansException("displayObjectFactoryGetBean", userObjectProvider::getObject);
}
public static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
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.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcessor 对象 | 用来处理 Spring 配置类 | org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 对象 | 处理 @Autowired 以及 @Value注解(构造器代码里 add 了上述两个注解) | org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanPostProcessor 对象 | (条件激活)处理 JSR-250 注解,如 @PostConstruct 等 | org.springframework.context.event.internalEventListenerProcessor | EventListenerMethodProcessor 对象 | 处理标注 @EventListener 的Spring 事件监听方法(直接标注在方法上就行,无需实现 ApplicationListener 接口) | org.springframework.context.event.internalEventListenerFactory | DefaultEventListenerFactory 对象 | @EventListener 事件监听方法适配为 ApplicationListener | org.springframework.context.annotation.internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解场景 |
依赖查找中的经典异常
异常类型 | 触发条件 | 场景举例 |
---|
NoSuchBeanDefinitionException | 当查找 Bean 不存在于 IoC 容器时 | BeanFactory#getBeanObjectFactory#getObject | NoUniqueBeanDefinitionException | 类型依赖查找时,IoC 容器存在多个 Bean 实例 | BeanFactory#getBean(Class | BeanInstantiationException | 当 Bean 所对应的类型非具体类时 | BeanFactory#getBean | BeanCreationException | 当 Bean 初始化过程中 | Bean 初始化方法执行异常时 | BeanDefinitionStoreException | 当 BeanDefinition 配置元信息非法时 | XML 配置资源无法打开时 |
相关代码:
NoUniqueBeanDefinitionExceptionDemo.class
public class NoUniqueBeanDefinitionExceptionDemo {
public static void main(String[] args) {
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
public class BeanInstantiationExceptionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Character.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) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(POJO.class);
applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());
applicationContext.refresh();
applicationContext.close();
}
static class POJO implements InitializingBean {
@PostConstruct
public void init() throws Throwable {
throw new Throwable("init() : For purposes...");
}
@Override
public void afterPropertiesSet() throws Exception {
throw new Exception("afterPropertiesSet() : For purposes...");
}
}
}
|