文章摘要(AI生成)
什么是控制反转?控制-创建对象传统的对象创建流程中,我们需要使用new关键字创建对象。在这个过程中,用户-也就是我们自己有权决定对象的创建,这种方式下,用户需要自己创建对象,也就是要自己控制对象实例化和属性赋值等操作。假如我们有以下java类:@Datapublic class B {private
什么是控制反转?
控制-创建对象
传统的对象创建流程中,我们需要使用new关键字创建对象。在这个过程中,用户-也就是我们自己有权决定对象的创建,这种方式下,用户需要自己创建对象,也就是要自己控制对象实例化和属性赋值等操作。
假如我们有以下java类:
@Data
public class B {
private String s;
public B(String s) {
this.s = s;
}
}
那么想要创建对象A时就需要如下操作:
public static void main(String[] args) {
B b = new B("hello");
System.out.println(b);
}
//--------控制台输出----------
//B(s=hello)
反转-拿来吧你~
使用spring进行对象创建时,我们只需要配置xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<bean id="b" class="org.jdbc.demo.B">
<constructor-arg index="0" value="hello"/>
</bean>
</beans>
spring就会帮我们完成对象的创建:
public static void main(String[] args) {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring/application-context.xml"));
B b = (B) beanFactory.getBean("b");
System.out.println(b);
}
//--------控制台输出----------
//B(s=hello)
也就是说,创建对象的控制权由用户交到了spring手中,对象的控制权由此发生了反转,不再由用户自己创建。
假如有个需求~~
用户自己创建对象会导致以下问题:
- 硬编码:当需要更改对象创建的方式时,所有使用该对象的代码都需要更改,且很难进行单元测试。
- 可维护性差:对象的创建和使用耦合在一起,难以进行模块化和重构。
- 依赖性强:代码和特定的实现细节紧密耦合,难以切换不同的实现。
- 可测试性差:难以进行单元测试,因为我们无法将依赖项替换为模拟对象。
为了避免上述问题,所以我们需要将代码中对象的创建和管理转移给框架或容器,从而使代码更加灵活和可维护。即从容器中直接获取已创建好的对象进行取用。
即通过B b = Container.getObject("b")
就能得到对象。
如何进行需求实现
总结上述过程:
输入:
- 配置对象创建文件
- 调用容器获取对象的接口
输出:
- 对应对象
整个系统的交互如下:
所以我们需要进行以下操作:
- 解析对象创建文件,获取各个对象定义,包括参数赋值等存储到对象创建集合中
- 在用户调用容器获取对象时,我们根据对象定义,通过反射的方式完成对象创建
对上述操作进行拆解可以得到:
- 首先使用【文档加载器】加载xml文件,然后通过【对象定义文档阅读器】获取配置文件中的各个配置,使用【对象定义解析器】解析我们配置文件中的对象定义列表,存储到【对象工厂】中
- 在用户调用【对象工厂】获取对象时,我们遍历【对象工厂】中的对象定义列表,获取到对应的对象定义配置,通过【对象工厂】进行具体的对象创建
基于上述过程中的对象分析,我们可以定义出各个对象的职责:
- 【文档加载器】:加载我们对象定义的配置文件
- 【对象定义文档阅读器】:负责读取配置文件中的各个配置
- 【对象定义解析器】:负责解析我们配置文件中的对象定义集合
- 【对象工厂】:存储我们解析后的对象定义列表,并通过反射完成对象创建
- 【对象定义】:配置文件中的对象定义配置映射后的实体类
所以我们可设计出如下方案进行实现:
对照spring源码:
名称 | 源码类名 | 类型 |
---|---|---|
文档加载器 | org.springframework.beans.factory.xml.DocumentLoader |
接口 |
对象定义文档阅读器 | org.springframework.beans.factory.support.BeanDefinitionReader |
接口 |
对象工厂 | org.springframework.beans.factory.BeanFactory |
接口 |
对象定义 | org.springframework.beans.factory.config.BeanDefinition |
接口 |
对象定义解析器 | org.springframework.beans.factory.xml.BeanDefinitionParserDelegate |
类 |
加亿点点技术~
配置文件加载
加载xml文件使用了JDK自带的jax工具类进行加载(org.springframework.beans.factory.xml.DefaultDocumentLoader
):
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
对象定义解析
在对象定义解析中,通过获取xml文件中的对象定义配置,创建对应的对象定义配置实体类(org.springframework.beans.factory.xml.BeanDefinitionParserDelegate
):
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
//异常处理
return null;
}
对象定义注册
对象定义的注册(对应类为org.springframework.beans.factory.support.DefaultListableBeanFactory
),在注册时需要判断对象工厂是否已经开始创建对象,如果已经开始创建对象,则需要通过加锁保证线程安全。
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
//对象定义配置验证
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//是否对象定义中已经存在
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//如果已经存在且不允许覆盖
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
//此处省略其他覆写规则的判断
//。。。。
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//检查此工厂的 bean 创建阶段是否已经开始,即在此期间是否有任何 bean 被标记为已创建。
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
//如果创建阶段已开始,此时需要等到创建完成后才能对象bean定义集合进行更新
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
//对象定义集合中不存在,则进行注册
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
对象实例化
在对应的org.springframework.beans.factory.support.SimpleInstantiationStrategy
中,可以看到实例化是通过反射完成对象创建的。
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor<?> ctor, Object... args) {
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(ctor);
return null;
});
}
return BeanUtils.instantiateClass(ctor, args);
}
else {
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
拓展–需求迭代
截至到此,我们只是实现了一个简单对象的控制反转,那么如果我们有如下的一个类:
@Data
public class A {
private String c;
private B b;
}
如何通过需求迭代实现:
即通过A a = Container.getObject("a")
就能得到对象呢?
评论区