问题抛出:
当别人问你 你所知道Spring中创建Bean到Spring容器的方式你知道你哪些方式嘛?
- 最常用方式 通过反射机制创建Bean对象 如@Service @Component 等等
- FactoryBean方式
- InstationAwareBeanPostProcessor
- 工厂方法(静态工厂和实例工程)
- 还有一个比较偏门的就是Supplier
说明:
①说实话Supplier这个功能 我自己在开发中从来没有使用过、在工作中也从没见别人那么用过、但是这里为什么要说一下呢 是因为看Spring源码过程中 在实例化Bean的时候obtailFromSupplier方法不知道是干么的 所以学习了一下
②虽然开发可能不会用 但是不见得面试官不问、Spring既然提供了这样的一个方式 你可以不用,但是你要知道、当别人问的话 你可以向面试官展示一下自己技术的深度和完整度
源码跟踪:
- 在createBeanInstance有这样一个方法 叫obtainFromSupplier 跟踪进去代码如下图所示:
这里正常开发过程中 你所定义Bean的都是空的 , 所以正常都是无法执行obtainFromSupplier方法的
- 我们思考一下 如何让这个instanceSupplier 这个对象不为空呢? 这里观察一下 是从Bean的定义信息中获取instanceSupplier对象、那我是不是可以修改Bean的定义让其不是空呢? 但是我又如何修改Bean的定义信息呢? 熟悉Spring的BeanFactoryPostProcessor知道这个类型Bean会提前加入spring的管理、 并且里面有postProcessBeanFactory方法, 能够拿到BeanFactory对象 之后修改Bean的定义信息还就很简单了嘛
- 那么我们简单实现一下 代码如下:
- 上面的代码你必须思考一下问题?上面的代码凭什么我要转为GenericBeanDefinition呢?
①如下图Bean定义信息的集成结构图(部分)
② 我们通过getBeanDefinition方法获取到的是一个BeanDefinition对象 通过寻找里面的方法没有能找到设置Supplier的方法
③那我是不是可以转成AbstractBeanDefinition呢 因为里面有setInstanceSupplier方法 这里肯定是可以的 但是还可以再精确一点嘛?
④这里大家要思考初始化放到容器中BeanDefinitionMap中对象是什么类型呢? 是GenericBeanDefinition类型 所有这里转成GenericBeanDefinition最精准的。但是又为什么不强转成RootBeanDefinition呢? 这时候还没合并Bean的定义信息 所以转一定会报错
- obtainFromSupplier 会回调自己写的函数是接口方法 获取Bean的实例化对象
案例:
- 配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:zhangfuyin="http://www.zhangfuyin.org/schema/zhangfuyin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.zhangfuyin.org/schema/zhangfuyin http://www.zhangfuyin.org/schema/zhangfuyin.xsd "> <bean id="supplierBean" class="com.zhangfuyin.supplier.SupplierBean"></bean> <bean id="supplierBeanFactoryPostProcessor" class="com.zhangfuyin.supplier.SupplierBeanFactoryPostProcessor"/> </beans>
- java
public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { BeanDefinition beanDefinition = beanFactory.getBeanDefinition("supplierBean"); if(beanDefinition != null){ GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition)beanDefinition; SupplierBean supplierBean = new SupplierBean(); genericBeanDefinition.setInstanceSupplier(supplierBean :: getSupplierBean); } } } ========================================================================================= public class SupplierBean { public SupplierBean() { } private String name; public SupplierBean(String name) { this.name = name; } public SupplierBean getSupplierBean(){ return new SupplierBean("supplierBean"); } }
- 测试类
public static void main(String agrs[]){ ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:supplierBean.xml"); SupplierBean supplierBean = (SupplierBean)ac.getBean("supplierBean"); String s = (String)ac.getBean("supplierBean"); System.out.println(supplierBean); }