Spring源码分析——Bean实例化策略
本篇文章讨论Spring源码中BeanFactory和BeanDefinition的设计实现,分析Spring如何创建单例Bean和如何使用三级缓存解决循环依赖。
对应Github源码完整文档:https://github.com/TyCoding/mini-spring/tree/main/docs/ioc/02-bean-instance-strategy
引言
在上一节中我们提到了Bean创建的核心是AbstractAutowireCapableBeanFactory
类,其中我们提到了doCreateBean是创建Bean实例:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
....
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
....
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
....
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
....
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
....
}
从上面的代码中看出,创建Bean实例的核心是this.createBeanInstance()
函数,接着看这个函数:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
上面其实核心主要涉及两种实例化方式:
-
autowireConstructor
:使用自动装配其构造函数实现实例化,例如使用@Autowire
标记注入Bean -
instantiateBean
:全面负责创建和初始化Bean实例,会选择合适的实例化策略等完成Bean初始化
注意:
Spring默认使用instantiateBean
方式实例化Bean,当例如使用@Autowire
方式注入bean将可能使用autowireConstructor
方式注入bean;但是,这都不是决定性条件,Spring实例化一个Bean的时候会根据Bean的配置(构造函数、一些规则)等选择合适的方式去实例化Bean。
但是无论是使用哪种方式,都涉及一个调用:
/**
* Return the instantiation strategy to use for creating bean instances.
*/
protected InstantiationStrategy getInstantiationStrategy() {
return this.instantiationStrategy;
}
选择一种合适的实例化策略(下面开始展开)。
扩展:Spring中装配一个Bean有多少种方式
-
构造函数注入;(注意Bean有默认的无参构造函数,但是使用如@AllArgsConstructor注解后则需要显示指定无参构造函数) -
Setter方法注入; -
字段注入;(定义字段并使用如@Autowire注解注入) -
Java配置类;(使用@Configuration注解标记的配置类中,使用@Bean标记的函数将交由Spring装配) -
XML配置文件;(使用XML声明一个Bean) -
自动装配;(使用例如@Autowire、@Qualifier、@Resource注解标记的字段或方法参数)
InstantiationStrategy
在Spring源码中,主要有两种实例化策略:
-
SimpleInstantiationStrategy:简单的Bean实例化方式,使用默认构造函数生成Bean实例 -
CglibSubclassingInstantiationStrategy:使用Cglib实例化Bean(Spring默认方式),Cglib生成的bean实例是原始Bean的子类,Cglib会生成代理对象,用于AOP、事务处理等功能。
具体体现:
SimpleInstantiationStrategy
如下,SimpleInstantiationStrategy将使用构造函数创建Bean实例:
CglibSubclassingInstantiationStrategy
创建一个简单的测试类:
public class CglibTest {
@Test
public void test() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CglibProxy.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> proxy.invokeSuper(obj, args));
CglibProxy impl = (CglibProxy) enhancer.create();
impl.say1();
impl.say2();
}
}
class CglibProxy {
public void say1() {
System.out.println("this CglibProxy say1()");
}
public void say2() {
System.out.println("this CglibProxy say2()");
}
}
打印结果:
my.CglibProxy$$EnhancerByCGLIB$$365af6e0@57f51dec
this CglibProxy say1()
this CglibProxy say2()
代理技术
核心: 都是通过代理类生成被代理类的对象引用,调用方通过调用代理类去调用具体的接口实现,代理类本身不提供任何服务,但是借助代理类可以实现AOP、事务等扩展功能。
-
JDK动态代理:基于Java中的 java.lang.reflect.Proxy
类,通过反射机制再运行时动态的创建代理对象;它只能代理接口类型的目标对象,并且要求目标对象至少实现一个接口。 -
Cglib动态代理:基于Cglib库,通过继承目标对象并重写其方法来创建代理对象;它可以代理任何类型的目标对象,并且不需要目标对象实现接口。
Spring源码专栏
此专栏将从Spring源码角度整体分析Spring设计思路以及常见的面试题。
配套作者的手写Spring的项目:https://github.com/TyCoding/mini-spring 。该项目中包含各个阶段的开发文档,有关Spring源码更详细的分析测试文档请查阅:https://github.com/TyCoding/mini-spring/tree/main/docs
联系我
-
个人博客:http://tycoding.cn/ -
GitHub:https://github.com/tycoding -
微信公众号:程序员涂陌 -
QQ交流群:866685601
原文始发于微信公众号(程序员涂陌):Spring源码分析——Bean实例化策略
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/145621.html