引言
学习贵在持之以恒,写文章也是;工作时间8H好好工作,写文章的时间只有晚上啦。但也是只有在晚上,夜深人静的时候,更能专注于写作。为自己加油,鼓劲!
今天晚上我们继续进行【一起学Spring】专栏,我将Spring的生命周期按流程进行拆解,分为以下核心十步来进行讲解和学习,如下:
- Bean扫描和加载
- 实例化
- 属性填充
- 初始化Bean
- 回调Aware接口
- 初始化之前的操作
- 执行初始化
- 初始化后的操作
- 存放单例池
- Bean销毁
那我们今天呢,我们先来看下实例化
目标
先看项目结构最终的UML图
随着功能点的增加,相较于上一节中,增加了不少接口和类文件,其中黄颜色背景区域是Bean实例化的核心类交互图。另外,我也对BeanFactory的实现增加了一些工厂类。以上主要实现的功能如下:
1、通过重新定义BeanDefinition,填充要实例化的Class类型,最终通过CGLIB的方式进行实例化
2、增加Bean单例池,用于对象实例化后,将对象注册到单例池中,如果在同获取同一名称的对象,直接从Bean单例池中进行获取
3、增加Bean实例化流程,定义实例化的策略类,当前最终是通过CLIB的方式调用类的无参构造函数进行实例化。
基于以上功能,我们定义了:
1、基于BeanFactory扩展了HierarchicalBeanFactory,ConfigurableBeanFactory接口
2、增加了AbstractBeanDefinition抽象类,用于配置Bean的Class类型配置信息
3、增加了单例池注册接口SingletonBeanRegistry和其实现类DefaultSingletonBeanRegistry
4、增加了实例化策略接口InstantiationStrategy和其实现类SimpleInstantiationStrategy,CglibSubclassingInstantiationStrategy;以及基于CGLIB的最终创建static类CglibSubclassCreator
准备
IDE:idea
JDK: 1.8
Maven: 3.9.5
实践
项目结构
使用tree命令查看项目目录及文件
因为我是Windows系统,使用命令如下:
tree /f
目录结构如下
│ pom.xml
│
├─assets
└─src
├─main
│ └─java
│ └─cn
│ └─itdebug
│ └─spring
│ └─beans
│ │ BeansException.java
│ │
│ ├─factory
│ │ │ BeanFactory.java
│ │ │ HierarchicalBeanFactory.java
│ │ │
│ │ ├─config
│ │ │ BeanDefinition.java
│ │ │ ConfigurableBeanFactory.java
│ │ │ SingletonBeanRegistry.java
│ │ │
│ │ └─support
│ │ AbstractAutowireCapableBeanFactory.java
│ │ AbstractBeanDefinition.java
│ │ AbstractBeanFactory.java
│ │ BeanDefinitionRegistry.java
│ │ CglibSubclassingInstantiationStrategy.java
│ │ DefaultListableBeanFactory.java
│ │ DefaultSingletonBeanRegistry.java
│ │ FactoryBeanRegistrySupport.java
│ │ InstantiationStrategy.java
│ │ RootBeanDefinition.java
│ │ SimpleInstantiationStrategy.java
│ │
│ └─util
│ Assert.java
│ CollectionUtils.java
│ ObjectUtils.java
│ StringUtils.java
│
└─test
└─java
└─cn
└─itdebug
└─spring
└─beans
└─factory
│ BeanFactoryTest.java
│
└─model
Baozi.java
代码实现
1、基于BeanFactory扩展了HierarchicalBeanFactory,ConfigurableBeanFactory接口
HierarchicalBeanFactory:
/**
* Sub-interface implemented by bean factories that can be part
* of a hierarchy.
*
* <p>The corresponding <code>setParentBeanFactory</code> method for bean
* factories that allow setting the parent in a configurable
* fashion can be found in the ConfigurableBeanFactory interface.
*
* 由 Bean 工厂实现的子接口,可以是层次结构的一部分。
* <p><code><code> 可以在 ConfigurableBeanFactory 接口中找到允许以可配置方式设置父级的 Bean 工厂的相应 setParentBeanFactory 方法。
*
* @创建人 Eric.Lu
* @创建时间 2023/12/26
* @描述
*/
public interface HierarchicalBeanFactory extends BeanFactory {
}
ConfigurableBeanFactory:
/**
* Configuration interface to be implemented by most bean factories. Provides
* facilities to configure a bean factory, in addition to the bean factory
* client methods in the {@link org.springframework.beans.factory.BeanFactory}
* interface.
*
* <p>This bean factory interface is not meant to be used in normal application
* code: Stick to {@link org.springframework.beans.factory.BeanFactory} or
* {@link org.springframework.beans.factory.ListableBeanFactory} for typical
* needs. This extended interface is just meant to allow for framework-internal
* plug'n'play and for special access to bean factory configuration methods.
*
* 大多数 Bean 工厂要实现的配置接口。除了 {@link org.springframework.beans.factory.BeanFactory}
* 接口中的 Bean 工厂客户端方法外,还提供用于配置 Bean 工厂的工具。
*
* <p>这个 Bean 工厂接口不适合在普通应用程序代码中使用:对于典型需求,
* 请坚持使用 {@link org.springframework.beans.factory.BeanFactory}
* 或 {@link org.springframework.beans.factory.ListableBeanFactory}。
* 这个扩展接口只是为了允许框架内部即插即用和对 Bean 工厂配置方法的特殊访问。
*
* @创建人 Eric.Lu
* @创建时间 2023/12/26
* @描述
*/
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory,SingletonBeanRegistry{
}
2、增加了AbstractBeanDefinition抽象类,用于配置Bean的Class类型配置信息
/**
* @创建人 Eric.Lu
* @创建时间 2023/12/25
* @描述
*/
public abstract class AbstractBeanDefinition implements BeanDefinition {
private volatile Object beanClass;
@Override
public String getBeanClassName() {
Object beanClassObject = this.beanClass;
if (beanClassObject instanceof Class) {
return ((Class<?>) beanClassObject).getName();
}
else {
return (String) beanClassObject;
}
}
@Override
public void setBeanClassName(String beanClassName) {
this.beanClass = beanClassName;
}
public Class<?> getBeanClass() throws BeansException {
Object beanClassObject = this.beanClass;
if (beanClassObject == null) {
throw new BeansException("No bean class specified on bean definition");
}
if (!(beanClassObject instanceof Class)) {
throw new BeansException(
"Bean class name [" + beanClassObject + "] has not been resolved into an actual Class");
}
return (Class) beanClassObject;
}
public void setBeanClass(Class<?> beanClass) {
this.beanClass = beanClass;
}
}
3、增加了单例池注册接口SingletonBeanRegistry和其实现类DefaultSingletonBeanRegistry
SingletonBeanRegistry:
/**
* Interface that defines a registry for shared bean instances.
* Can be implemented by {@link BeanFactory}
* implementations in order to expose their singleton management facility
* in a uniform manner.
*
* 定义共享 Bean 实例的注册表的接口。可以通过 {@link BeanFactory} 实现来实现,以便以统一的方式公开其单例管理工具。
* @创建人 Eric.Lu
* @创建时间 2023/12/26
* @描述
*/
public interface SingletonBeanRegistry {
/**
* Register the given existing object as singleton in the bean registry,
* under the given bean name.
* <p>The given instance is supposed to be fully initialized; the registry
* will not perform any initialization callbacks (in particular, it won't
* call InitializingBean's <code>afterPropertiesSet</code> method).
* The given instance will not receive any destruction callbacks
* (like DisposableBean's <code>destroy</code> method) either.
* <p>When running within a full BeanFactory: <b>Register a bean definition
* instead of an existing instance if your bean is supposed to receive
* initialization and/or destruction callbacks.</b>
* <p>Typically invoked during registry configuration, but can also be used
* for runtime registration of singletons. As a consequence, a registry
* implementation should synchronize singleton access; it will have to do
* this anyway if it supports a BeanFactory's lazy initialization of singletons.
*
* 在 Bean 注册表中,在给定的 Bean 名称下,将给定的现有对象注册为单例。
* <p>给定的实例应该被完全初始化;注册表不会执行任何初始化回调(特别是,它不会调用
* InitializingBean 的 <code>afterPropertiesSet<code> 方法)。
* 给定的实例也不会收到任何销毁回调(如 DisposableBean 的 <code>destroy<code> 方法)。
* <p>在完整的 BeanFactory 中运行时:如果您的 Bean <b>应该接收初始化和/或销毁回调,
* 请注册一个 Bean 定义而不是现有实例。<b>
* <p>通常在注册表配置期间调用,但也可用于单例的运行时注册。
* 因此,注册表实现应同步单例访问;
* 如果它支持 BeanFactory 的单例延迟初始化,它无论如何都必须这样做。
*
* @param beanName the name of the bean
* @param singletonObject the existing singleton object
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.DisposableBean#destroy
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinition
*/
void registerSingleton(String beanName, Object singletonObject);
/**
* Return the (raw) singleton object registered under the given name.
* <p>Only checks already instantiated singletons; does not return an Object
* for singleton bean definitions which have not been instantiated yet.
* <p>The main purpose of this method is to access manually registered singletons
* (see {@link #registerSingleton}). Can also be used to access a singleton
* defined by a bean definition that already been created, in a raw fashion.
* <p><b>NOTE:</b> This lookup method is not aware of FactoryBean prefixes or aliases.
* You need to resolve the canonical bean name first before obtaining the singleton instance.
*
* 返回在给定名称下注册的(原始)单例对象。仅检查已实例化的单例;
* <p>不返回尚未实例化的单例 Bean 定义的 Object。
* <p>此方法的主要用途是访问手动注册的单例
* (请参阅 {@link registerSingleton})。还可用于以原始方式访问由已创建的 Bean 定义定义的单例。
* <p><b>注意:<b>此查找方法无法识别 FactoryBean 前缀或别名。
* 在获取单例实例之前,您需要先解析规范 Bean 名称。
*
* @param beanName the name of the bean to look for
* @return the registered singleton object, or <code>null</code> if none found
* @see ConfigurableListableBeanFactory#getBeanDefinition
*/
Object getSingleton(String beanName);
}
DefaultSingletonBeanRegistry:
/**
* @创建人 Eric.Lu
* @创建时间 2023/12/26
* @描述
*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
/**
* Internal marker for a null singleton object:
* used as marker value for concurrent Maps (which don't support null values).
*
* 空单例对象的内部标记:用作并发映射(不支持空值)的标记值。
*/
protected static final Object NULL_OBJECT = new Object();
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
@Override
public void registerSingleton(String beanName, Object singletonObject) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
addSingleton(beanName, singletonObject);
}
}
/**
* Add the given singleton object to the singleton cache of this factory.
* <p>To be called for eager registration of singletons.
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
}
}
@Override
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
*
* 返回在给定名称下注册的(原始)单例对象。<p>检查已实例化的单例,并允许对当前创建的单例的早期引用(解析循环引用)。
*
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or <code>null</code> if none found
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
4、增加了实例化策略接口InstantiationStrategy和其实现类SimpleInstantiationStrategy,CglibSubclassingInstantiationStrategy;以及基于CGLIB的最终创建static类CglibSubclassCreator
InstantiationStrategy:
/**
* @创建人 Eric.Lu
* @创建时间 2023/12/25
* @描述
*/
public interface InstantiationStrategy {
Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner)
throws BeansException;
}
SimpleInstantiationStrategy:
/**
* @创建人 Eric.Lu
* @创建时间 2023/12/25
* @描述
*/
public class SimpleInstantiationStrategy implements InstantiationStrategy{
@Override
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) throws BeansException {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
protected Object instantiateWithMethodInjection(
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
throw new UnsupportedOperationException(
"Method Injection not supported in SimpleInstantiationStrategy");
}
}
CglibSubclassingInstantiationStrategy:
/**
* @创建人 Eric.Lu
* @创建时间 2023/12/25
* @描述
*/
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// Must generate CGLIB subclass.
return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null);
}
/**
* An inner class so we don't have a CGLIB dependency in core.
*/
private static class CglibSubclassCreator {
private static final Log logger = LogFactory.getLog(CglibSubclassCreator.class);
private final RootBeanDefinition beanDefinition;
private final BeanFactory owner;
public CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
this.beanDefinition = beanDefinition;
this.owner = owner;
}
/**
* Create a new instance of a dynamically generated subclasses implementing the
* required lookups.
*
* @param ctor constructor to use. If this is <code>null</code>, use the
* no-arg constructor (no parameterization, or Setter Injection)
* @param args arguments to use for the constructor.
* Ignored if the ctor parameter is <code>null</code>.
* @param ctor 构造函数使用。如果此值为 <code>null<code>,
* 请使用 no-arg 构造函数(无参数化或 Setter 注入)
* @return new instance of the dynamically generated class
* <p>
* 创建动态生成的子类的新实例,以实现所需的查找。
* @param用于构造函数的 args 参数。如果 ctor 参数为 null,则忽略<code><code>。
* @return动态生成的类的新实例
*/
public Object instantiate(Constructor ctor, Object[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setCallback(NoOp.INSTANCE);
// enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects));
return (ctor == null) ?
enhancer.create() :
enhancer.create(ctor.getParameterTypes(), args);
}
}
}
5、为实现以上功能,AbstractBeanFactory、AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory等流程也进行了代码重新编排
AbstractBeanFactory:
/**
* @创建人 Eric.Lu
* @创建时间 2023/12/24
* @描述
*/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
/** Map from bean name to merged RootBeanDefinition */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions =
new ConcurrentHashMap<String, RootBeanDefinition>();
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 提前检查对象是否已存在,如果存在,直接返回
Object sharedInstance = getSingleton(name);
if(sharedInstance != null && args == null) {
logger.info("Returning cached instance of singleton bean '" + name + "'");
} else {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(name);
sharedInstance = createBean(name, mbd, args);
addSingleton(name, sharedInstance);
}
return (T) sharedInstance;
}
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
return (RootBeanDefinition) getBeanDefinition(beanName);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeansException;
}
AbstractAutowireCapableBeanFactory:
/**
* @创建人 Eric.Lu
* @创建时间 2023/12/24
* @描述
*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeansException {
return instantiateBean(beanName, mbd);
}
protected Object instantiateBean(final String beanName, final RootBeanDefinition mbd) {
final BeanFactory parent = this;
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
/**
* Set the instantiation strategy to use for creating bean instances.
* Default is CglibSubclassingInstantiationStrategy.
*
* 设置用于创建 Bean 实例的实例化策略。默认值为 CglibSubclassingInstantiationStrategy。
* @see CglibSubclassingInstantiationStrategy
*/
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
/**
* Return the instantiation strategy to use for creating bean instances.
*
* 返回用于创建 Bean 实例的实例化策略。
*/
protected InstantiationStrategy getInstantiationStrategy() {
return this.instantiationStrategy;
}
}
DefaultListableBeanFactory:
/**
* Default implementation of the
* {@link org.springframework.beans.factory.ListableBeanFactory} and
* {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
* based on bean definition objects.
*
* <p>Typical usage is registering all bean definitions first (possibly read
* from a bean definition file), before accessing beans. Bean definition lookup
* is therefore an inexpensive operation in a local bean definition table,
* operating on pre-built bean definition metadata objects.
*
* <p>Can be used as a standalone bean factory, or as a superclass for custom
* bean factories. Note that readers for specific bean definition formats are
* typically implemented separately rather than as bean factory subclasses:
* see for example {@link PropertiesBeanDefinitionReader} and
* {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
*
* <p>For an alternative implementation of the
* {@link org.springframework.beans.factory.ListableBeanFactory} interface,
* have a look at {@link StaticListableBeanFactory}, which manages existing
* bean instances rather than creating new ones based on bean definitions.
*
* {@link org.springframework.beans.factory.ListableBeanFactory} 和 {@link BeanDefinitionRegistry} 接口的默认实现:
* 基于 Bean 定义对象的成熟 Bean 工厂。
* <p>典型的用法是先注册所有 Bean 定义(可能从 Bean 定义文件中读取),然后再访问 Bean。
* 因此,Bean 定义查找是本地 Bean 定义表中的一项低成本操作,它对预构建的 Bean 定义元数据对象进行操作。
* 可以用作独立的 Bean 工厂<p>,也可以用作自定义 Bean 工厂的超类。
* 请注意,特定 Bean 定义格式的读取器通常是单独实现的,而不是作为 Bean 工厂子类实现的:
* 例如,参见 {@link PropertiesBeanDefinitionReader} 和 {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}。
* <p>有关{@link org.springframework.beans.factory.ListableBeanFactory}接口的替代实现,请查看{@link StaticListableBeanFactory},它管理现有的bean实例,
* 而不是基于bean定义创建新的bean实例。
*
* @创建人 Eric.Lu
* @创建时间 2023/12/24
* @描述
*/
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry{
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeansException {
beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
if (bd == null) {
logger.info("No bean named '" + beanName + "' found in " + this);
throw new BeansException(beanName);
}
return bd;
}
}
单元测试验证
验证目标:
1、实例化成功
2、再次获取对象是从对象池进行获取,返回的对象地址一致
3、因为是通过CGLIB创建对象,打印的地址格式应是:....$$EnhancerByCGLIB$$....
验证代码如下:
public class BeanFactoryTest extends TestCase {
public void testDefaultListableBeanFactory() {
/*
* 1、创建DefaultListableBeanFactory
* 2、改造BeanDefinition,由固定对象变为Class对象
* 3、在获取对象时,通过对象名称到beanDefinition中查找对象定义,并最终通过CGLIB代理创建对象
* 4、实例化对象后,将对象注册到单例注册表中
* 5、验证再次获取同一名称bean,获取的对象是否从单例注册表中进行获取
*
*/
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinition rootBeanDefinition = new RootBeanDefinition(Baozi.class);
beanFactory.registerBeanDefinition("baozi", rootBeanDefinition);
Assert.assertEquals(beanFactory.getBean("baozi"), beanFactory.getBean("baozi"));
System.out.println(beanFactory.getBean("baozi").getClass());
}
}
验证结果如下:
验证通过
总结
随着功能的增加,类文件也在增加,我们唯有使用好我们的设计模式和设计原则,才能保证后续继续增加的情况下,让我们的代码方便扩展和维护。同样,在工作中的我们写代码也是一样。通过这一讲,我们可以继续学习到一些设计模式:
1、策略模式
在编写我们实例化代码中,我们定义了InstantiationStrategy 策略接口,并使用CglibSubclassingInstantiationStrategy 的实现类。但当前代码中存在不完整的地方,你觉得哪里可以继续优化呢?
代码源码
最后
还是要说一下,如果想要写好代码,还是要实践,提高自己的动手能力。另外还需拿出一点时间,进行思考和写作。
那非常感谢小伙伴们阅读到结尾,本期的文章就分享到这里,希望可以帮到大家,谢谢。 👉 如果你觉得本篇文章有帮助到您,鼓励一下编程哥吧! `点击`【`关注+点赞+收藏+评论+转发` 】支持一下哟 😛 您的支持就是我更新的最大动力。👇