交给 Spring 管理的 Bean 对象,一定就是我们用类创建出来的 Bean 吗?创建出来的 Bean 就永远是单例吗,没有可能是原型模式吗?
设计:提供一个能让使用者定义复杂的 Bean 对象。
接口
。
接口
的处理接口调用和相应的功能逻辑实现即可。FactoryBean
的 getObject
方法中获取对象的功能即可。这样所有实现此接口的对象类,就可以扩充自己的对象功能了。MapperFactoryBean
类,在 getObject
方法中提供 SqlSession
对执行 CRUD 方法的操作。FactoryBean
类型对象创建过程中关于获取具体调用对象的 getObject
操作。SCOPE_SINGLETON
、SCOPE_PROTOTYPE
,对象类型的创建获取方式,主要区分在于:
AbstractAutowireCapableBeanFactory#createBean
创建完成对象后是否放入内存中,如果不放入则每次获取都会重新创建。createBean
执行对象创建、属性填充、依赖加载、前置后置处理、初始化等操作后。就要开始做执行判断整个对象是否是一个 FactoryBean
对象。
FactoryBean
具体对象中的 getObject
对象了。getBean
过程中都会新增一个单例类型的判断 factory.isSingleton()
,用于决定是否使用内存存放对象信息。
<dependency>
<groupId>org.openjdk.jolgroupId>
<artifactId>jol-cliartifactId>
<version>0.14version>
dependency>
spring-step-09
|-src
|-main
| |-java
| |-com.lino.springframework
| |-beans
| | |-factory
| | | |-config
| | | | |-AutowireCapableBeanFactory.java
| | | | |-BeanDefinition.java
| | | | |-BeanFactoryPostProcessor.java
| | | | |-BeanPostProcessor.java
| | | | |-BeanReference.java
| | | | |-ConfigurableBeanFactory.java
| | | | |-SingletonBeanRegistry.java
| | | |-support
| | | | |-AbstractAutowireCapableBeanFactory.java
| | | | |-AbstractBeabDefinitionReader.java
| | | | |-AbstractBeabFactory.java
| | | | |-BeabDefinitionReader.java
| | | | |-BeanDefinitionRegistry.java
| | | | |-CglibSubclassingInstantiationStrategy.java
| | | | |-DefaultListableBeanFactory.java
| | | | |-DefaultSingletonBeanRegistry.java
| | | | |-DisposableBeanAdapter.java
| | | | |-FactoryBeanRegistrySupport.java
| | | | |-InstantiationStrategy.java
| | | | |-SimpleInstantiationStrategy.java
| | | |-support
| | | | |-XMLBeanDefinitionReader.java
| | | |-Aware.java
| | | |-BeanClassLoaderAware.java
| | | |-BeanFactory.java
| | | |-BeanFactoryAware.java
| | | |-BeanNameAware.java
| | | |-ConfigurableListableBeanFactory.java
| | | |-DisposableBean.java
| | | |-FactoryBean.java
| | | |-HierarcgicalBeanFactory.java
| | | |-InitializingBean.java
| | | |-ListableBeanFactory.java
| | |-BeansException.java
| | |-PropertyValue.java
| | |-PropertyValues.java
| |-context
| | |-support
| | | |-AbstractApplicationContext.java
| | | |-AbstractRefreshableApplicationContext.java
| | | |-AbstractXmlApplicationContext.java
| | | |-ApplicationContextAwareProcessor.java
| | | |-ClassPathXmlApplicationContext.java
| | |-ApplicationContext.java
| | |-ApplicationContextAware.java
| | |-ConfigurableApplicationContext.java
| |-core.io
| | |-ClassPathResource.java
| | |-DefaultResourceLoader.java
| | |-FileSystemResource.java
| | |-Resource.java
| | |-ResourceLoader.java
| | |-UrlResource.java
| |-util
| | |-ClassUtils.java
|-test
|-java
|-com.lino.springframework.test
|-bean
| |-IUserDao.java
| |-ProxyBeanFactory.java
| |-UserService.java
|-ApiTest.java
|-resources
|-spring.xml
AbstractAutowireCapableBeanFactory
类以及继承的抽象类 AbstractBeanFactory
中进行扩展。AbstractBeanFactory
继承的 DefaultSingletonBeanRegistry
类,中间加一层 FactoryBeanRegistrySupport
,这个类在 Spring 框架中主要是处理关于 FactoryBean 注册的支撑操作。BeanDefinition.java
package com.lino.springframework.beans.factory.config;
import com.lino.springframework.beans.PropertyValues;
/**
* @description: Bean 对象信息定义
*/
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;
public BeanDefinition(Class beanClass) {
this(beanClass, null);
}
public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}
public void setScope(String scope) {
this.scope = scope;
this.singleton = SCOPE_SINGLETON.equals(scope);
this.prototype = SCOPE_PROTOTYPE.equals(scope);
}
public boolean isSingleton() {
return singleton;
}
public boolean isPrototype() {
return prototype;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
public String getInitMethodName() {
return initMethodName;
}
public void setInitMethodName(String initMethodName) {
this.initMethodName = initMethodName;
}
public String getDestroyMethodName() {
return destroyMethodName;
}
public void setDestroyMethodName(String destroyMethodName) {
this.destroyMethodName = destroyMethodName;
}
}
singleton
、prototype
,是本次在 BeanDefinition 类中新增加的两个属性信息。
spring.xml
中解析到的 Bean 对象作用范围填充到属性中。XmlBeanDefinitionReader.java
package com.lino.springframework.beans.factory.xml;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanReference;
import com.lino.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import com.lino.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.lino.springframework.core.io.Resource;
import com.lino.springframework.core.io.ResourceLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.IOException;
import java.io.InputStream;
/**
* @description: XML处理Bean注册
*/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
...
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
Document doc = XmlUtil.readXML(inputStream);
Element root = doc.getDocumentElement();
NodeList childNodes = root.getChildNodes();
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 > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
beanDefinition.setInitMethodName(initMethod);
beanDefinition.setDestroyMethodName(destroyMethodName);
if (StrUtil.isNotEmpty(beanScope)) {
beanDefinition.setScope(beanScope);
}
// 读取属性并填充
for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
// 判断元素
if (!(bean.getChildNodes().item(j) instanceof Element)) {
continue;
}
// 判断对象
if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) {
continue;
}
// 解析标签:property
Element property = (Element) bean.getChildNodes().item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
scope
的解析,并把这个属性信息填充到 Bean 定义中。
beanDefinition.setScope(beanScope)
AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.support;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.AutowireCapableBeanFactory;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.BeanReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @description: 实现默认bean创建的抽象bean工厂超类
*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
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_PROTOTYPE
if (beanDefinition.isSingleton()) {
registerSingletonBean(beanName, bean);
}
return bean;
}
private 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));
}
}
...
}
FactoryBean.java
package com.lino.springframework.beans.factory;
/**
* @description: 工厂对象接口
*/
public interface FactoryBean<T> {
/**
* 获取对象
*
* @return 泛型对象
* @throws Exception 异常
*/
T getObject() throws Exception;
/**
* 获取对象类型
*
* @return 对象类型
*/
Class<?> getObjectType();
/**
* 是否单例对象
*
* @return 是否:布尔值
*/
boolean isSingleton();
}
DefaultSingletonBeanRegistry.java
package com.lino.springframework.beans.factory.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.DisposableBean;
import com.lino.springframework.beans.factory.config.SingletonBeanRegistry;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @description: 通用的注册表实现
*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
protected static final Object NULL_OBJECT = new Object();
private Map<String, Object> singletonObjects = new HashMap<>();
private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
...
}
Object NULL_OBJECT = new Object()
。FactoryBeanRegistrySupport.java
package com.lino.springframework.beans.factory.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.FactoryBean;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: FactoryBean注册对象
*/
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
/**
* FactoryBean对象缓存
*/
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>();
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);
}
}
}
factoryBeanObjectCache
,用于存放单例类型的对象,避免重复创建。
doGetObjectFromFactoryBean
是具体的获取 FactoryBean#getObject()
方法。
getObjectFromFactoryBean
进行逻辑包装。AbstractBeanFactory.java
package com.lino.springframework.beans.factory.support;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.FactoryBean;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanPostProcessor;
import com.lino.springframework.beans.factory.config.ConfigurableBeanFactory;
import com.lino.springframework.util.ClassUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 抽象的 Bean 工厂基类,定义模板方法
*/
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
...
protected <T> T doGetBean(final String name, final Object[] args) {
Object sharedInstance = getSingleton(name);
if (null != sharedInstance) {
// 如果是 FactoryBean,则需要调用 FactoryBean#getObject
return (T) getObjectFromBeanInstance(sharedInstance, name);
}
BeanDefinition beanDefinition = getBeanDefinition(name);
Object bean = createBean(name, beanDefinition, args);
return (T) getObjectFromBeanInstance(bean, name);
}
private Object getObjectFromBeanInstance(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;
}
...
}
AbstractBeanFactory
原来继承的 DefaultSingletonBeanRegistry
,修改为继承 FactoryBeanRegistrySupport
。
doGetBean
方法中,添加了调用 (T) getObjectFromBeanInstance(sharedInstance, name)
对获取 FactoryBean
的操作。getObjectFromBeanInstance
方法中做具体的 instanceof
判断,另外还会从 FactoryBean
的缓存中获取对象,如果不存在则调用 FactoryBeanRegistrySupport#getObjectFromFactoryBean
,执行具体的操作。IUserDao.java
package com.lino.springframework.test.bean;
/**
* @description: 用户dao接口
*/
public interface IUserDao {
/**
* 根据用户ID获取用户名称
*
* @param uId 用户ID
* @return 用户名称
*/
String queryUserName(String uId);
}
IUserDao
接口,是为了通过 FactoryBean
做一个自定义对象的代理操作。UserService.java
package com.lino.springframework.test.bean;
/**
* @description: 模拟用户 Bean 对象
*/
public class UserService {
private String uId;
private String company;
private String location;
private IUserDao userDao;
/**
* 查询用户信息
*/
public String queryUserInfo() {
return userDao.queryUserName(uId) + "," + company + "," + location;
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
}
IUserDao
,后面会给这个属性注入代理对象。ProxyBeanFactory.java
package com.lino.springframework.test.bean;
import com.lino.springframework.beans.factory.FactoryBean;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
/**
* @description: 代理对象工厂
*/
public class ProxyBeanFactory implements FactoryBean<IUserDao> {
@Override
public IUserDao getObject() throws Exception {
InvocationHandler handler = (proxy, method, args) -> {
// 添加排除方法
if ("toString".equals(method.getName())) {
return this.toString();
}
Map<String, String> hashMap = new HashMap<>();
hashMap.put("10001", "张三");
hashMap.put("10002", "李四");
hashMap.put("10003", "王五");
return "你被代理了 " + method.getName() + ": " + hashMap.get(args[0].toString());
};
return (IUserDao) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{IUserDao.class},
handler);
}
@Override
public Class<?> getObjectType() {
return IUserDao.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
FactoryBean
的代理类 ProxyBeanFactory
名称,主要是模拟了 UserDao
的原有功能,类似于 Mybatis 框架中的代理操作。getObject()
中提供的就是一个 InvocationHandler
的代理对象,当有方法调用的时候,则执行代理对象的功能。spring.xml
<beans>
<bean id="userService" class="com.lino.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="com.lino.springframework.test.bean.ProxyBeanFactory"/>
beans>
proxyUserDao
这个代理对象,注入到 userService
的 userDao
中。ApiTest.java
@Test
public void test_prototype() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext 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());
}
spring.xml
配置文件中,设置了 scope="prototype"
,这样就每次获取到的对象都应该是一个新的对象。测试结果
com.lino.springframework.test.bean.UserService$$EnhancerByCGLIB$$5e50ce60@6bdf28bb
com.lino.springframework.test.bean.UserService$$EnhancerByCGLIB$$5e50ce60@6b71769e
com.lino.springframework.test.bean.UserService$$EnhancerByCGLIB$$5e50ce60@6bdf28bb 十六进制哈希: 6bdf28bb
com.lino.springframework.test.bean.UserService$$EnhancerByCGLIB$$5e50ce60 object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 bb 28 df (00000001 10111011 00101000 11011111) (-550978815)
4 4 (object header) 6b 00 00 00 (01101011 00000000 00000000 00000000) (107)
8 4 (object header) 3d e5 01 f8 (00111101 11100101 00000001 11111000) (-134093507)
12 4 java.lang.String UserService.uId (object)
16 4 java.lang.String UserService.company (object)
20 4 java.lang.String UserService.location (object)
24 4 com.lino.springframework.test.bean.IUserDao UserService.userDao (object)
28 1 boolean UserService$$EnhancerByCGLIB$$5e50ce60.CGLIB$BOUND true
29 3 (alignment/padding gap)
32 4 net.sf.cglib.proxy.NoOp UserService$$EnhancerByCGLIB$$5e50ce60.CGLIB$CALLBACK_0 (object)
36 4 (loss due to the next object alignment)
Instance size: 40 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
ApiTest.java
@Test
public void test_factory_bean() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();
// 2.调用代理方法
UserService userService = applicationContext.getBean("userService", UserService.class);
System.out.println("测试结果:" + userService.queryUserInfo());
}
测试结果
测试结果:你被代理了 queryUserName: 张三,阿里,杭州
ProxyBeanFactory
完美替换掉了 UserDao
的功能。FactoryBean
的实现以及测试过程的使用,以后再需要使用 FactoryBean
开发相应的组件时,一定会非常清楚它是如何创建自己的复杂 Bean 对象以及在什么时候初始化和调用的。遇到问题也可以快速的排查、定位和解决。