1. 依赖查找的今世前生: Spring IoC容器从Java标准中学到了什么?
-
单一类型依赖查找
-
JNDI - javax.naming.Context#lookup(javax.naming.Name)
-
JavaBeans - java.beans.beancontext.BeanContext
-
-
集合类型依赖查找
-
java.beans.beancontext.BeanContext
集合查找方法
-
-
层次性依赖查找
-
java.beans.beancontext.BeanContext
这里要集合 Java Beans Api
-
2. 单一类型依赖查找: 如何查找已知名称或类型的Bean对象?
-
单一类型依赖查找接口- BeanFactory
-
根据Bean名称查找
-
getBean(String)
-
Spring 2.5覆盖默认参数:getBean(String,Object…)
-
-
根据 Bean类型查找
-
Bean实时查找
-
Spring 3.0 getBean(Class)
-
Spring 4.1覆盖默认参数:getBean(Class,Object…)
返回一个实例, 这个实例可能是shared(单例)可能是independent(原生), 这里就会告诉你一个不好的特点, 如果是shared的话, 当你的整个一个BeanFactory实例里面, 这个容器里面包含了同样一个实例, 那么之后你每次调用一次就会覆盖它的方法, 这个方式实际上有点不可取的, 那么因此建议采用 BeanFactory 的方式只好是只读方法, 要不你就完全的覆盖相关定义, 比如说你吧以前的BeanDefinition把它进行删除, 后面做一个Override做一个覆盖
-
-
-
Spring 5.1 Bean延迟查找
-
pom.xml
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.2.RELEASE</version> </dependency>
-
getBeanProvider(Class)
package org.xiaoge.thinking.in.spring.dependency.lookup; import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; /** * * 通过{@link ObjectProvider} 进行依赖查找 * * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.dependency.lookup * @Classname ObjectProviderDemo * @Date 2022/11/23 11:23 * @Author zhangxiao * @Description TODO */ public class ObjectProviderDemo { // @Configuration 是非必须注解 public static void main(String[] args) { // 创建 ApplicationContext 容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 将当前类 ObjectProviderDemo 作为配置类 (Configuration class) applicationContext.register(ObjectProviderDemo.class); // 启动应用上下文 applicationContext.refresh(); // 依赖查找集合对象 lookupByObjectProvider(applicationContext); // 关闭应用上下文 applicationContext.close(); } @Bean public String helloWord() { // @Bean没有value的时候 方法名称就是 Bean 名称 == "helloWord" return "hello word"; } private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) { // 通常来说String类型的Bean Spring 上下文是不会定义的, 因此这个时候可以用 注意:只能查唯一Bean多个Bean会报错NoUniqueBeanDefinitionException ObjectProvider<String> beanProvider = applicationContext.getBeanProvider(String.class); System.out.println(beanProvider.getObject()); } } // 运行结果 hello word
-
getBeanProvider(ResolvableType)
后面写
-
-
根据Bean名称+类型查找: getBean(String,Class)
-
建议: 不要用覆盖默认参数的形式去查找
-
3. 集合类型依赖查找: 如何查找已知类型多个Bean集合?
-
集合类型依赖查找接口- ListableBeanFactory
-
根据Bean类型查找
-
获取同类型Bean名称列表
-
getBeanNamesForType(Class)
-
注意: 这个方法比较BeanDefinition里面的getBeanClassName和FactoryBean里面的getObjectType类型的匹配情况, 所以这个时候还没有涉及到Bean的初始化
-
-
Spring 4.2 getBeanNamesForType(ResolvableType)
-
-
获取同类型Bean 实例列表
- getBeansOfType(Class)以及重载方法
- 注意: 它会涉及到Bean的初始化, 这个方法可能 会提前把一些你的类进行初始化, 初始化之后会导致一些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>)
- Spring 3.0获取标注类型Bean名称列表
-
4. 层次性依赖查找: 依赖查找也有双亲委派?
-
层次性依赖查找接口– HierarchicalBeanFactory
-
双亲BeanFactory: getParentBeanFactory()
-
层次性查找
-
根据 Bean名称查找
-
基于containsLocalBean方法实现
package org.xiaoge.thinking.in.spring.dependency.lookup; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * * 层次性 依赖查找 示例 * * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.dependency.lookup * @Classname HierarchicalDependencyLookupDemo * @Date 2022/11/23 13:52 * @Author zhangxiao * @Description TODO */ public class HierarchicalDependencyLookupDemo { public static void main(String[] args) { // 创建 ApplicationContext 容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 讲当前类 HierarchicalDependencyLookupDemo 作为配置类 (Configuration Class) applicationContext.register(HierarchicalDependencyLookupDemo.class); // 1. 获取HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListableBeanFactory ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); System.out.println("当前 BeanFactory 的 Parent BeanFactory : " + beanFactory.getParentBeanFactory()); ConfigurableListableBeanFactory parentBeanFactory = createParentBeanFactory(); // 2. 设置 Parent BeanFactory beanFactory.setParentBeanFactory(parentBeanFactory); System.out.println("当前 BeanFactory 的 Parent BeanFactory : " + beanFactory.getParentBeanFactory()); // 启动应用上下文 applicationContext.refresh(); // 当前 Bean 是否在当前容器中 displayContainsLocalBean(beanFactory, "user"); displayContainsLocalBean(parentBeanFactory, "user"); // 当前 Bean 是否在容器中 实现双亲委派 displayContainsBean(beanFactory, "user"); displayContainsBean(parentBeanFactory, "user"); // 关闭应用上下文 applicationContext.close(); } /** * 查询 Bean 是否 在容器中 实现双亲委派 * @param beanFactory * @param beanName */ private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) { System.out.printf("当前 BeanFactory[%s] 是否包含 Bean[name : %s] : %s\n", beanFactory, beanName, containsBean(beanFactory, beanName)); } /** * 递归实现, 查找 Bean 这是 BeanFactoryUtils 没有实现的 * @param beanFactory * @param beanName * @return */ private static Boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) { if (beanFactory.containsLocalBean(beanName)) { return true; } // 获取父容器 BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory(); // 判断了类型也判断了它是否为空 if (parentBeanFactory instanceof HierarchicalBeanFactory) { // 转换类型 HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory); if (parentHierarchicalBeanFactory.containsLocalBean(beanName)) { return true; } containsBean(parentHierarchicalBeanFactory, beanName); } return false; } /** * 当前 bean 是否在 当前备本地(它自己的容器)容器中 * @param beanFactory * @param beanName */ private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) { System.out.printf("当前 BeanFactory[%s] 是否包含 Local Bean[name : %s] : %s\n", beanFactory, beanName, beanFactory.containsLocalBean(beanName)); } /** * * @return */ private static ConfigurableListableBeanFactory createParentBeanFactory() { // 创建BeanFactory容器 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); // XML 配置文件 ClassPath 路径 String location = "classpath:META-INF/dependency-lookup-context.xml"; // 加载配置 reader.loadBeanDefinitions(location); return beanFactory; } } // 运行结果 当前 BeanFactory 的 Parent BeanFactory : null 当前 BeanFactory 的 Parent BeanFactory : org.springframework.beans.factory.support.DefaultListableBeanFactory@3c09711b: defining beans [user,objectFactory,superUser]; root of factory hierarchy 当前 BeanFactory[org.springframework.beans.factory.support.DefaultListableBeanFactory@1e397ed7: 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@3c09711b] 是否包含 Local Bean[name : user] : false 当前 BeanFactory[org.springframework.beans.factory.support.DefaultListableBeanFactory@3c09711b: defining beans [user,objectFactory,superUser]; root of factory hierarchy] 是否包含 Local Bean[name : user] : true 当前 BeanFactory[org.springframework.beans.factory.support.DefaultListableBeanFactory@1e397ed7: 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@3c09711b] 是否包含 Bean[name : user] : true 当前 BeanFactory[org.springframework.beans.factory.support.DefaultListableBeanFactory@3c09711b: defining beans [user,objectFactory,superUser]; root of factory hierarchy] 是否包含 Bean[name : user] : true
-
-
根据 Bean类型查找实例列表
-
单一类型: BeanFactoryUtils#beanOfType
-
集合类型:BeanFactoryUtils#beansOfTypeIncludingAncestors
-
注意: 改方法实现了双亲委派的原则
-
-
-
根据Java 注解查找名称列表
- BeanFactoryUtils#beanNamesForTypeIncludingAncestors
-
-
5. 延迟依赖查找: 非延迟初始化Bean也能实现延迟查找?
-
Bean延迟依赖查找接口
-
org. springframework. beans.factory.ObjectFactory
-
org. springframework. beans.factory.ObjectProvider
-
Spring 5 对Java 8 特性扩展
-
函数式接口
- getIfAvailable (Supplier)
- ifAvailable (Consumer)
-
Stream扩展- stream ()
package org.xiaoge.thinking.in.spring.dependency.lookup; import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput; import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.xiaoge.thinking.in.spring.ioc.overview.domain.User; /** * * 通过{@link ObjectProvider} 进行依赖查找 * * @PACKAGE_NAME: org.xiaoge.thinking.in.spring.dependency.lookup * @Classname ObjectProviderDemo * @Date 2022/11/23 11:23 * @Author zhangxiao * @Description TODO */ public class ObjectProviderDemo { // @Configuration 是非必须注解 public static void main(String[] args) { // 创建 ApplicationContext 容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 将当前类 ObjectProviderDemo 作为配置类 (Configuration class) applicationContext.register(ObjectProviderDemo.class); // 启动应用上下文 applicationContext.refresh(); // 延迟加载依赖查找集合对象 lookupByObjectProvider(applicationContext); // 延迟加载 lookupIfAvailable(applicationContext); // 延迟加载(查找的是集合) lookupByStreamOps(applicationContext); // 关闭应用上下文 applicationContext.close(); } private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) { ObjectProvider<String> beanProvider = applicationContext.getBeanProvider(String.class); // Iterable<String> stringIterable = beanProvider; // for (String s : stringIterable) { // System.out.println(s); // } // Stream -> Method reference beanProvider.stream().forEach(System.out::println); } /** * 这是个兜底方案, 当没有User Bean 不在容器中时 使用 自己的 * @param applicationContext */ private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) { ObjectProvider<User> beanProvider = applicationContext.getBeanProvider(User.class); User user = beanProvider.getIfAvailable(User::createUser); System.out.println("当前 User 对象 : " + user); } @Bean @Primary public String helloWord() { // @Bean没有value的时候 方法名称就是 Bean 名称 == "helloWord" return "hello word"; } @Bean public String message() { // @Bean没有value的时候 方法名称就是 Bean 名称 == "helloWord" return "message"; } private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) { // 通常来说String类型的Bean Spring 上下文是不会定义的, 因此这个时候可以用 注意:只能查唯一Bean多个Bean会报错NoUniqueBeanDefinitionException ObjectProvider<String> beanProvider = applicationContext.getBeanProvider(String.class); System.out.println(beanProvider.getObject()); } } // 运行结果 hello word 当前 User 对象 : User{ id=1, name='xiaoge'} hello word message
-
-
-
6. 安全依赖查找
-
依赖查找安全性对比
注意:层次性依赖查找的安全性取决于其扩展的单一或集合类型的 BeanFactory 接口
package org.xiaoge.thinking.in.spring.dependency.lookup; import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput; import org.springframework.beans.BeansException; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.xiaoge.thinking.in.spring.ioc.overview.domain.User; /** * 类型安全 依赖查找 示例 * * @author <a href="mailto:[email protected]">Zhang Xiao</a> * @since */ public class TypeSafetyDependencyLookupDemo { public static void main(String[] args) { // 创建 ApplicationContext 容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 将当前类 TypeSafetyDependencyLookupDemo 作为配置类 (Configuration class) applicationContext.register(TypeSafetyDependencyLookupDemo.class); // 启动应用上下文 applicationContext.refresh(); // 演示 BeanFactory#getBean 方法的安全性 displayBeanFactoryGetBean(applicationContext); // 演示 ObjectFactory#getObject 方法的安全性 displayObjectFactoryGetObject(applicationContext); // 演示 ObjectProvider#ifAvailable 方法的安全性 displayObjectProviderIfAvailable(applicationContext) ; // 演示 ListableBeanFactory#getBeansOfType 方法的安全性 displayListableBeanFactoryGetBeansOfType(applicationContext); // 演示 ObjectProvider Stream 操作的安全性 displayObjectProviderStreamOps(applicationContext); // 关闭应用上下文 applicationContext.close(); } /** * ObjectProvider * @param applicationContext */ private static void displayObjectProviderStreamOps(AnnotationConfigApplicationContext applicationContext) { ObjectProvider<User> objectProvider = applicationContext.getBeanProvider(User.class); printBeansException("displayObjectProviderStreamOps", () -> objectProvider.forEach(System.out::println)); } /** * ListableBeanFactory#getBeansOfType 是否安全 * @param beanFactory */ private static void displayListableBeanFactoryGetBeansOfType(ListableBeanFactory beanFactory) { printBeansException("displayListableBeanFactoryGetBeansOfType", () -> beanFactory.getBeansOfType(User.class)); } /** * ObjectProvider#getIfAvailable 是否安全 * @param applicationContext */ private static void displayObjectProviderIfAvailable(AnnotationConfigApplicationContext applicationContext) { ObjectProvider<User> objectProvider = applicationContext.getBeanProvider(User.class); printBeansException("displayObjectProviderIfAvailable", () -> objectProvider.getIfAvailable()); } /** * ObjectFactory#getObject 是否安全 * @param applicationContext */ private static void displayObjectFactoryGetObject(AnnotationConfigApplicationContext applicationContext) { // ObjectProvider is ObjectFactory ObjectFactory<User> objectFactory = applicationContext.getBeanProvider(User.class); printBeansException("displayObjectFactoryGetObject", () -> objectFactory.getObject()); } /** * BeanFactory#getBean 是否安全 * @param applicationContext */ private static void displayBeanFactoryGetBean(AnnotationConfigApplicationContext applicationContext) { printBeansException("displayBeanFactoryGetBean", () -> applicationContext.getBean(User.class)); } /** * 打印异常信息 * @param source * @param runnable */ private static void printBeansException(String source, Runnable runnable) { System.err.println("==========================================="); System.err.println("Source from : " + source); try { runnable.run(); } catch (BeansException e) { e.printStackTrace(); } } } // 运行结果 =========================================== Source from : displayBeanFactoryGetBean org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.xiaoge.thinking.in.spring.ioc.overview.domain.User' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1126) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.lambda$displayBeanFactoryGetBean$4(TypeSafetyDependencyLookupDemo.java:90) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.printBeansException(TypeSafetyDependencyLookupDemo.java:103) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.displayBeanFactoryGetBean(TypeSafetyDependencyLookupDemo.java:90) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.main(TypeSafetyDependencyLookupDemo.java:30) =========================================== Source from : displayObjectFactoryGetObject org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.xiaoge.thinking.in.spring.ioc.overview.domain.User' available at org.springframework.beans.factory.support.DefaultListableBeanFactory$1.getObject(DefaultListableBeanFactory.java:370) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.lambda$displayObjectFactoryGetObject$3(TypeSafetyDependencyLookupDemo.java:82) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.printBeansException(TypeSafetyDependencyLookupDemo.java:103) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.displayObjectFactoryGetObject(TypeSafetyDependencyLookupDemo.java:82) at org.xiaoge.thinking.in.spring.dependency.lookup.TypeSafetyDependencyLookupDemo.main(TypeSafetyDependencyLookupDemo.java:33) =========================================== Source from : displayObjectProviderIfAvailable =========================================== Source from : displayListableBeanFactoryGetBeansOfType =========================================== Source from : displayObjectProviderStreamOps
由此可见建议使用ObjectProvider来进行依赖查找
7. 内建可查找的依赖: 那些Spring IoC容器内建依赖可供查找?
-
AbstractApplicationContext 内建可查找的依赖
-
注解驱动Spring 应用上下文内建可查找的依赖(部分)
其实也非常好记, 只需要关注AnnotationConfigUtils就知道了
8. 依赖查找中的经典异常: Bean找不到?Bean不唯一的?Bean创建失败?
-
BeansException子类型
-
NoSuchBeanDefinitionException不做演示, 上面案例有
-
NoUniqueBeanDefinitionException
package org.xiaoge.thinking.in.spring.dependency.lookup; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; /** * {@link NoUniqueBeanDefinitionException} 示例代码 * * @author <a href="mailto:[email protected]">Zhang Xiao</a> * @since */ public class NoUniqueBeanDefinitionExceptionDemo { public static void main(String[] args) { // 创建 ApplicationContext 容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 将当前类 NoUniqueBeanDefinitionExceptionDemo 作为配置类 (Configuration class) applicationContext.register(NoUniqueBeanDefinitionExceptionDemo.class); // 启动应用上下文 applicationContext.refresh(); // 由于 Spring 上下文存在两个String类型的 Bean, 通过单一类型查找会报错 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"; } } // 运行结果 Spring 应用上下文存在2个 java.lang.String 类型的Bean, 具体原因: No qualifying bean of type 'java.lang.String' available: expected single matching bean but found 2: bean1,bean2
-
BeanInstantiationException
package org.xiaoge.thinking.in.spring.dependency.lookup; import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * {@link BeanInstantiationException} 示例 * * @author <a href="mailto:[email protected]">Zhang Xiao</a> * @since */ public class BeanInstantiationExceptionDemo { public static void main(String[] args) { // 创建 ApplicationContext 容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 注册 BeanDefinition Bean Class 是一个 CharSequence 接口 BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CharSequence.class); // 注册Bean applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition()); // 启动应用上下文 applicationContext.refresh(); // 关闭应用上下文 applicationContext.close(); } } // 运行结果 十一月 23, 2022 5:56:42 下午 org.springframework.context.support.AbstractApplicationContext refresh 警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'errorBean': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.lang.CharSequence]: Specified class is an interface Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'errorBean': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.lang.CharSequence]: Specified class is an interface at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1320) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) at org.xiaoge.thinking.in.spring.dependency.lookup.BeanInstantiationExceptionDemo.main(BeanInstantiationExceptionDemo.java:28) Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.lang.CharSequence]: Specified class is an interface at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:70) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312) ... 11 more Process finished with exit code 1
-
BeanCreationException
package org.xiaoge.thinking.in.spring.dependency.lookup; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import javax.annotation.PostConstruct; /** * {@link BeanCreationException} 示例 * * @author <a href="mailto:[email protected]">Zhang Xiao</a> * @since */ public class BeanCreationExceptionDemo { public static void main(String[] args) { // 创建 ApplicationContext 容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); // 注册 BeanDefinition Bean Class 是一个 POJO 普通类,不过初始化方法回调时抛出异常 BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(POJO.class); // 注册Bean applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition()); // 启动应用上下文 applicationContext.refresh(); // 关闭应用上下文 applicationContext.close(); } static class POJO implements InitializingBean { @PostConstruct // CommonAnnotationBeanPostProcessor 实现的这个注解, 顺序很重要, 因为PostConstruct注解装饰的方法会先执行 public void init() throws Exception { throw new Exception("init() : For purposes..."); } @Override public void afterPropertiesSet() throws Exception { throw new Exception("afterPropertiesSet() : For purposes..."); } } } // 运行结果 十一月 23, 2022 5:57:12 下午 org.springframework.context.support.AbstractApplicationContext refresh 警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'errorBean': Invocation of init method failed; nested exception is java.lang.Exception: init() : For purposes... Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'errorBean': Invocation of init method failed; nested exception is java.lang.Exception: init() : For purposes... at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) at org.xiaoge.thinking.in.spring.dependency.lookup.BeanCreationExceptionDemo.main(BeanCreationExceptionDemo.java:28) Caused by: java.lang.Exception: init() : For purposes... at org.xiaoge.thinking.in.spring.dependency.lookup.BeanCreationExceptionDemo$POJO.init(BeanCreationExceptionDemo.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ... 12 more Process finished with exit code 1
9. 面试题精选
-
ObjectFactory 与BeanFactory 的区别?
答: 0bjectFactory 与 BeanFactory 均提供依赖查找的能力。
不过 ObjectFactory 仅关注一个 或一种类型的 Bean 依赖查找, 并且自身不具备依赖查找的能力,能力则由 BeanFactory 输出。
BeanFactory则提供了单一类型、集合类型以及层次性等多种依赖查找方式。
根据名称查找
根据类型查找
最终还是用了BeanFactory
可以通过改文章, 可以看出它是怎么通过ObjectFactoryCreatingFactoryBean创建ObjectFactory的
-
BeanFactory. getBean操作是否线程安全?
答: BeanFactory. getBean方法的执行是线程安全的,操作过程中会增加互斥锁。