需求
FactoryBean 直接配置FactoryBean 获取FactoryBean中的Bean对象
FactoryBean的getObject方法通过反射获取Bean对象 由此省去对实体Dao类的定义
解决方法
对外提供一个可以二次从 FactoryBean 的 getObject 方法中获取对象的功能即可
整体架构
整个的实现过程包括了两部分,一个解决单例还是原型对象,另外一个处理 FactoryBean 类型对象创建过程中关于获取具体调用对象的 getObject 操作。
COPE_SINGLETON、SCOPE_PROTOTYPE,对象类型的创建获取方式,主要区分在于 AbstractAutowireCapableBeanFactory#createBean 创建完成对象后是否放入到内存中,如果不放入则每次获取都会重新创建。
createBean 执行对象创建、属性填充、依赖加载、前置后置处理、初始化等操作后,就要开始做执行判断整个对象是否是一个 FactoryBean 对象,如果是这样的对象,就需要再继续执行获取 FactoryBean 具体对象中的 getObject 对象了。整个 getBean 过程中都会新增一个单例类型的判断factory.isSingleton(),用于决定是否使用内存存放对象信息。
实现
工程结构和类图
src
├── main
│ └── java
│ └── cn.bugstack.springframework
│ ├── beans
│ │ ├── factory
│ │ │ ├── factory
│ │ │ │ ├── AutowireCapableBeanFactory.java
│ │ │ │ ├── BeanDefinition.java(实体类)
初始化和销毁
│ │ │ │ ├── BeanFactoryPostProcessor.java
│ │ │ │ ├── BeanPostProcessor.java
│ │ │ │ ├── BeanReference.java
│ │ │ │ ├── ConfigurableBeanFactory.java(接口) 定义了 destroySingletons 销毁方法
│ │ │ │ └── SingletonBeanRegistry.java
│ │ │ ├── support
│ │ │ │ ├── AbstractAutowireCapableBeanFactory.java(抽象类)
主要作用:
继承关系:继承AbstractBeanFactory
实现AutowireCapableBeanFactory接口
主要方法:
CreateBean():创建Bean 调用registerDisposableBeanIfNecessary
initializeBean():初始化Bean,调用PostProcessor Before 处理,执行初始化方法invokeInitMethods,执行 BeanPostProcessor After 处理
│ │ │ │ ├── AbstractBeanDefinitionReader.java
│ │ │ │ ├── AbstractBeanFactory.java
│ │ │ │ ├── BeanDefinitionReader.java
│ │ │ │ ├── BeanDefinitionRegistry.java
│ │ │ │ ├── CglibSubclassingInstantiationStrategy.java
│ │ │ │ ├── DefaultListableBeanFactory.java
│ │ │ │ ├── DefaultSingletonBeanRegistry.java
实现destroySingletons 销毁方法( AbstractBeanFactory.java的父类)
│ │ │ │ ├── DisposableBeanAdapter.java
描述:销毁方法适配器
继承关系: 实现DisposableBean接口
│ │ │ │ ├── FactoryBeanRegistrySupport.java(继承 DefaultSingletonBeanRegistry)
作用:实现一个 FactoryBean 注册服务
维护一个存放FactoryBean对象的缓存 factoryBeanObjectCache
处理的就是关于 FactoryBean 此类对象的注册操作
GetObjectFromFactoryBean() 从FactoryBean通过getObject()获取对象,先判断缓存中是否有 如果有直接获取,没有则加入缓存
│ │ │ │ ├── InstantiationStrategy.java
│ │ │ │ └── SimpleInstantiationStrategy.java
│ │ │ ├── support
│ │ │ │ └── XmlBeanDefinitionReader.java
│ │ │ ├── Aware.java(接口)
│ │ │ ├── BeanClassLoaderAware.java(实现Aware接口)
│ │ │ ├── BeanFactory.java
│ │ │ ├──BeanFactoryAware.java(实现Aware接口)
│ │ │ ├── BeanNameAware.java
│ │ │ ├── ConfigurableListableBeanFactory.java
│ │ │ ├── DisposableBean.java
│ │ │ ├──FactoryBean.java(实现FactoryBean)
主要方法:
getObject()获取对象
getObjectType()对象类型
isSingleton()是否是单例对象 如果是单例对象会被放到内存中
│ │ │ ├── HierarchicalBeanFactory.java
│ │ │ ├── InitializingBean.java(接口) 定义初始化方法
│ │ │ └── ListableBeanFactory.java
│ │ ├── BeansException.java
│ │ ├── PropertyValue.java
│ │ └── PropertyValues.java
│ ├── context
│ │ ├── support
│ │ │ ├── AbstractApplicationContext.java(抽象类)
继承关系:实现 ConfigurableApplicationContext接口 继承DefaultResourceLoader类
│ │ │ ├── AbstractRefreshableApplicationContext.java
│ │ │ ├── AbstractXmlApplicationContext.java
│ │ │ ├── ApplicationContextAwareProcessor.java(实现BeanPostProcessor接口)
│ │ │ └── ClassPathXmlApplicationContext.java
│ │ ├── ApplicationContext.java
│ │ ├──ApplicationContextAware.java
│ │ └── ConfigurableApplicationContext.java(接口)
主要描述:虚拟机关闭钩子注册调用销毁,定义刷新容器,关闭应用上下文
继承关系:继承ApplicationContext
主要方法:
refresh():
registerShutdownHook():注册虚拟机钩子的方法
close():手动执行关闭虚拟机钩子的方法
│ ├── core.io
│ │ ├── ClassPathResource.java
│ │ ├── DefaultResourceLoader.java(实体类)
作用:资源处理器
│ │ ├── FileSystemResource.java
│ │ ├── Resource.java
│ │ ├── ResourceLoader.java
│ │ └── UrlResource.java
│ └── utils
│ └── ClassUtils.java
└── test
类图:
以上整个类关系图展示的就是添加 Bean 的实例化是单例还是原型模式以及 FactoryBean 的实现。
其实整个实现的过程并不复杂,只是在现有的 AbstractAutowireCapableBeanFactory 类以及继承的抽象类 AbstractBeanFactory 中进行扩展。
不过这次我们把 AbstractBeanFactory 继承的 DefaultSingletonBeanRegistry 类,中间加了一层 FactoryBeanRegistrySupport,这个类在 Spring 框架中主要是处理关于 FactoryBean 注册的支撑操作。
实现
Bean的作用范围定义和xml解析
BeanDefinition
public class BeanDefinition {String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;private Class beanClass;private PropertyValues propertyValues;private String initMethodName;private String destroyMethodName;private String scope = SCOPE_SINGLETON;private boolean singleton = true;private boolean prototype = false;// ...get/set
}
在 BeanDefinition 类中新增加的两个属性信息,用于把从 spring.xml 中解析到的 Bean 对象作用范围填充到属性中。
XmlBeanDefinitionReader
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {for (int i = 0; i < childNodes.getLength(); i++) {// 判断元素if (!(childNodes.item(i) instanceof Element)) continue;// 判断对象if (!"bean".equals(childNodes.item(i).getNodeName())) continue;// 解析标签Element bean = (Element) childNodes.item(i);String id = bean.getAttribute("id");String name = bean.getAttribute("name");String className = bean.getAttribute("class");String initMethod = bean.getAttribute("init-method");String destroyMethodName = bean.getAttribute("destroy-method");String beanScope = bean.getAttribute("scope");// 获取 Class,方便获取类中的名称Class<?> clazz = Class.forName(className);// 优先级 id > nameString beanName = StrUtil.isNotEmpty(id) ? id : name;if (StrUtil.isEmpty(beanName)) {beanName = StrUtil.lowerFirst(clazz.getSimpleName());}// 定义BeanBeanDefinition beanDefinition = new BeanDefinition(clazz);beanDefinition.setInitMethodName(initMethod);beanDefinition.setDestroyMethodName(destroyMethodName);if (StrUtil.isNotEmpty(beanScope)) {beanDefinition.setScope(beanScope);}// ...// 注册 BeanDefinitiongetRegistry().registerBeanDefinition(beanName, beanDefinition);}}}
在解析 XML 处理类 XmlBeanDefinitionReader 中,新增加了关于 Bean 对象配置中 scope 的解析,并把这个属性信息填充到 Bean 定义中。beanDefinition.setScope(beanScope)
创建和修改对象时候判断单例和原型模式
AbstractAutowireCapableBeanFactory
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {Object bean = null;try {bean = createBeanInstance(beanDefinition, beanName, args);// 给 Bean 填充属性applyPropertyValues(beanName, bean, beanDefinition);// 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法bean = initializeBean(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}// 注册实现了 DisposableBean 接口的 Bean 对象registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);// 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPEif (beanDefinition.isSingleton()) {addSingleton(beanName, bean);}return bean;}protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {// 非 Singleton 类型的 Bean 不执行销毁方法if (!beanDefinition.isSingleton()) return;if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));}}// ... 其他功能
}
单例模式和原型模式的区别就在于是否存放到内存中,如果是原型模式那么就不会存放到内存中,每次获取都重新创建对象,另外非 Singleton 类型的 Bean 不需要执行销毁方法。
所以这里的代码会有两处修改,一处是 createBean 中判断是否添加到 addSingleton(beanName, bean);,另外一处是 registerDisposableBeanIfNecessary 销毁注册中的判断 if (!beanDefinition.isSingleton()) return;。
定义 FactoryBean 接口
public interface FactoryBean<T> {T getObject() throws Exception;Class<?> getObjectType();boolean isSingleton();}
FactoryBean 中需要提供3个方法,获取对象、对象类型,以及是否是单例对象,如果是单例对象依然会被放到内存中。
实现一个 FactoryBean 注册服务
FactoryBeanRegistrySupport
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {/*** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object*/private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<String, Object>();protected Object getCachedObjectForFactoryBean(String beanName) {Object object = this.factoryBeanObjectCache.get(beanName);return (object != NULL_OBJECT ? object : null);}protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName) {if (factory.isSingleton()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {object = doGetObjectFromFactoryBean(factory, beanName);this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));}return (object != NULL_OBJECT ? object : null);} else {return doGetObjectFromFactoryBean(factory, beanName);}}private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName){try {return factory.getObject();} catch (Exception e) {throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);}}}
扩展 AbstractBeanFactory 创建对象逻辑
AbstractBeanFactory
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {protected <T> T doGetBean(final String name, final Object[] args) {Object sharedInstance = getSingleton(name);if (sharedInstance != null) {// 如果是 FactoryBean,则需要调用 FactoryBean#getObjectreturn (T) getObjectForBeanInstance(sharedInstance, name);}BeanDefinition beanDefinition = getBeanDefinition(name);Object bean = createBean(name, beanDefinition, args);return (T) getObjectForBeanInstance(bean, name);} private Object getObjectForBeanInstance(Object beanInstance, String beanName) {if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}Object object = getCachedObjectForFactoryBean(beanName);if (object == null) {FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;object = getObjectFromFactoryBean(factoryBean, beanName);}return object;}// ...
}
此处新增加的功能主要是在 doGetBean 方法中,添加了调用 (T) getObjectForBeanInstance(sharedInstance, name) 对获取 FactoryBean 的操作。
在 getObjectForBeanInstance 方法中做具体的 instanceof 判断,另外还会从 FactoryBean 的缓存中获取对象,如果不存在则调用 FactoryBeanRegistrySupport#getObjectFromFactoryBean,执行具体的操作。
测试
IUserDao
public interface IUserDao {String queryUserName(String uId);}
定义一个 IUserDao 接口,之所这样做是为了通过 FactoryBean 做一个自定义对象的代理操作。
UserService
public class UserService {private String uId;private String company;private String location;private IUserDao userDao;public String queryUserInfo() {return userDao.queryUserName(uId) + "," + company + "," + location;}// ...get/set
}
定义 FactoryBean 对象
public class ProxyBeanFactory implements FactoryBean<IUserDao> {@Overridepublic IUserDao getObject() throws Exception {InvocationHandler handler = (proxy, method, args) -> {Map<String, String> hashMap = new HashMap<>();hashMap.put("10001", "小傅哥");hashMap.put("10002", "八杯水");hashMap.put("10003", "阿毛");return "你被代理了 " + method.getName() + ":" + hashMap.get(args[0].toString());};//Proxy.newProxyInstance反射获取对象return (IUserDao) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IUserDao.class}, handler);}@Overridepublic Class<?> getObjectType() {return IUserDao.class;}@Overridepublic boolean isSingleton() {return true;}}
这是一个实现接口 FactoryBean 的代理类 ProxyBeanFactory 名称,主要是模拟了 UserDao 的原有功能,类似于 MyBatis 框架中的代理操作。
getObject() 中提供的就是一个 InvocationHandler 的代理对象,当有方法调用的时候,则执行代理对象的功能。
配置文件
<beans><bean id="userService" class="cn.bugstack.springframework.test.bean.UserService" scope="prototype"><property name="uId" value="10001"/><property name="company" value="腾讯"/><property name="location" value="深圳"/><property name="userDao" ref="proxyUserDao"/></bean><bean id="proxyUserDao" class="cn.bugstack.springframework.test.bean.ProxyBeanFactory"/></beans>
单元测试
单例&&原型
原型每次都不一样
@Test
public void test_prototype() {// 1.初始化 BeanFactoryClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");applicationContext.registerShutdownHook(); // 2. 获取Bean对象调用方法UserService userService01 = applicationContext.getBean("userService", UserService.class);UserService userService02 = applicationContext.getBean("userService", UserService.class);// 3. 配置 scope="prototype/singleton"System.out.println(userService01);System.out.println(userService02); // 4. 打印十六进制哈希System.out.println(userService01 + " 十六进制哈希:" + Integer.toHexString(userService01.hashCode()));System.out.println(ClassLayout.parseInstance(userService01).toPrintable());}
继承一个UserDao类型的BeanFactory工厂如代理类 ProxyBeanFactory 可以完美替换掉了 UserDao 的功能
问题与思考
1.spring的作用域什么是单例,什么是原型(在搜索并思考)