欢迎访问shiker.tech

请允许在我们的网站上展示广告

您似乎使用了广告拦截器,请关闭广告拦截器。我们的网站依靠广告获取资金。

spring如何实现控制反转?
(last modified Apr 16, 2023, 12:38 AM )
by
侧边栏壁纸
  • 累计撰写 192 篇文章
  • 累计创建 66 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

spring如何实现控制反转?

橙序员
2023-04-09 / 0 评论 / 0 点赞 / 669 阅读 / 2,100 字 / 正在检测百度是否收录... 正在检测必应是否收录...
文章摘要(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")就能得到对象。

如何进行需求实现

总结上述过程:

输入:

  • 配置对象创建文件
  • 调用容器获取对象的接口

输出:

  • 对应对象

整个系统的交互如下:
image-20230409171440742

所以我们需要进行以下操作:

  1. 解析对象创建文件,获取各个对象定义,包括参数赋值等存储到对象创建集合中
  2. 在用户调用容器获取对象时,我们根据对象定义,通过反射的方式完成对象创建

对上述操作进行拆解可以得到:

  1. 首先使用【文档加载器】加载xml文件,然后通过【对象定义文档阅读器】获取配置文件中的各个配置,使用【对象定义解析器】解析我们配置文件中的对象定义列表,存储到【对象工厂】中
  2. 在用户调用【对象工厂】获取对象时,我们遍历【对象工厂】中的对象定义列表,获取到对应的对象定义配置,通过【对象工厂】进行具体的对象创建

基于上述过程中的对象分析,我们可以定义出各个对象的职责:

  • 【文档加载器】:加载我们对象定义的配置文件
  • 【对象定义文档阅读器】:负责读取配置文件中的各个配置
  • 【对象定义解析器】:负责解析我们配置文件中的对象定义集合
  • 【对象工厂】:存储我们解析后的对象定义列表,并通过反射完成对象创建
  • 【对象定义】:配置文件中的对象定义配置映射后的实体类

所以我们可设计出如下方案进行实现:

image-20230409181707050

对照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")就能得到对象呢?

0

评论区