手写Spring IOC 框架

本文详细介绍了Spring的IOC(控制反转)和DI(依赖注入)原理,从概念、参与者、作用到如何使用IoC/DI容器实现对象创建、装配和管理。通过自定义容器Cup设计,阐述了XML配置、DOM解析、工厂模式和反射等底层技术,并讨论了容器加载过程及其实现细节。最终目标是实现程序的高内聚和低耦合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.知识拓扑图

在这里插入图片描述

二.相关概念说明

1.控制反转 --> 谁控制谁? 控制什么? 为何叫反转(对应于正向)?哪些方面反转了?为何需要反转?

谁控制谁? --> IoC/DI容器控制应用程序

控制什么? --> IoC/DI容器控制对象本身的创建、实例化; IoC/DI容器控制对象之间的依赖关系

为何叫反转(对应于正向)? --> 因为现在应用程序不能主动去获取外部资源了,而是被动等待IoC/DI容器给它注入它所需要的资源,所以称之为反转.

哪些方面反转了? --> 1.创建对象 2.程序获取资源的方式反了

为何需要反转? --> 1.引入IoC/DI容器过后,体系更为松散,而且管理更有序; 2.类之间真正实现了松散耦合

2.依赖 --> 什么是依赖(按名称理解、按动词理解)? 谁依赖于谁? 为什么需要依赖? 依赖什么东西?

什么是依赖(按名称理解、按动词理解)? --> 依赖(按名称理解):依赖关系; 依赖(按动词理解):依赖的动作

谁依赖于谁? --> 应用程序依赖于IoC/DI容器

为什么需要依赖? --> 因为发生了反转,应用程序依赖的资源都是IoC/DI容器里面

依赖什么东西? --> 应用程序依赖于IoC/DI容器,依赖IoC/DI容器为它注入所需要的资源。(比如:依赖关系)

3.注入:谁注入于谁? 注入什么东西? 为何要注入?

谁注入于谁? --> IoC/DI容器注入于应用程序

注入什么东西? --> 注入应用程序需要的外部资源,比如依赖关系

为何要注入? --> 因为程序要正常运行需要这些外部资源

4.依赖注入和控制反转是同一概念吗?

不是同一概念, 其实它们两个描述的是同一件事件,但是是从不同的角度来说:控制反转是从IoC/DI容器的角度;依赖注入是从应用程序的角度

控制反转的描述: IoC/DI容器反过来控制应用程序,控制应用程序锁所需要的外部资源(比如:外部资源)
  依赖注入的描述: 应用程序依赖IoC/DI容器,依赖它注入所需要的外部资源。

5.参与者都有哪些?

IoC/DI容器、应用程序

6.IoC/DI是什么?能做什么?怎么做?用在什么地方?

IoC/DI是什么?

IoC(Inversion of Control):就是使用IoC/DI容器反过来控制应用程序所需要的外部资源,是程序开发思想。

DI(Dependency Injection):就是应用程序依赖IoC/DI容器来注入所需要的外部资源,也是程序的开发思想。

能做什么? --> 松散耦合对象

怎么做? --> 使用Spring框架,里面有实现好了的IoC/DI容器

用在什么地方? --> 凡是程序里面需要使用外部资源的情况,都可以考虑使用IoC/DI容器

7.什么是外部资源

对于一个类来讲,所谓的外部资源,就是指在自己类的内部不能得到或实现的东西,比如说:在类里面需要读取一个配置文件,那么这个配置文件就相当于这个类的外部资源。又比如:A类里面要调用B类,那么对于A类来讲B类就是外部资源。

8. IoC容器

简单的理解就是:实现IoC思想,并提供对象创建、对象装配以及对象生命周期管理的软件就是IoC容器。

对IoC的理解:

a. 应用程序无需主动new对象,而是描述对象应该如何被创建

b. 应用程序不需要主动装配对象之间的依赖关系,而是描述需要哪个服务,IoC容器会帮你装配,被动接受装配

c. 主动变被动,是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则

9.使用IoC/DI容器开发需要改变思路

a. 应用程序不主动创建对象,但是要描述创建它们的方式

b. 在应用程序代码中不直接进行服务的装配,但是要描述哪一个组件需要哪一项服务,由容器负责将这些装配在一起。也就是说:所有的组件都是被动的,组件初始化和专供都是由容器负责,应用程序只是在获取相应的组件后,实现应用的功能即可。


三,IOC和DI使用的底层技术

?Xml配置文件

?dom4j解析xml

?工厂设计模式

?反射

四,最终目地

程序的高内聚,低耦合

五.IOC容器加载的过程

ClasspathxmlApplcation app = new ClasspathxmlApplcation(“classpath:spring-*.xml”);
Object value = app.getBean(“xx”)
app.getBean(Interface.class);
在这里插入图片描述

六.容器Cup设计

Ioc,aop,DI
主要实现容器,切面,依赖注入的功能
2.2 包设计
com.sxt.core
Anno
Context
Util
在这里插入图片描述

2.3 接口设计
2.3.1 包扫描或读取配置文件

/**
 * 包扫描,获取读取配置文件来实现获取  定义对象
 * @author CodeLab
 *
 */
public interface BeanDefindedGet {
   
   
	
	/**
	 * 读取xml 获取对象的定义对象
	 * @param path
	 * @return
	 */
	List<Bean> readXml(String path);
	
	/**
	 * 包扫描获取对象的定义对象
	 * @param basePackage
	 *   可以使用,隔空
	 * @return
	 */
	List<Bean> packScan(String basePackage);

}


2.3.2 创建对象并放入容器里面

/**
 * 创建对象,并且把该对象注入到容器里面
 * @author CodeLab
 *
 */
public interface BeanFactory {
   
   

	/**
	 * 创建对象并且放入到容器里面
	 * @param beans
	 *  对象创建的定义对象
	 */
	void createAndPut(List<Bean> beans);
}

2.3.3 完成容器里面的属性注入

/**
 * 属性注入的接口 完成容器里面 对象的属性注入
 * @author CodeLab
 *
 */
public interface PropInject {
   
   

	/**
	 * 把容器里面的对象的属性注入
	 */
	void injectProp();
}

2.4 数据结构设计
容器使用Map 集合来实现
2.4.1 设计容器的功能

/**
 * 核心容器
 * @author CodeLab
 *
 */
public interface CupContext {
   
   

	/**
	 * 将一个对象放入容器里面
	 * @param key
	 * 对象的标识
	 * @param value
	 * 对象
	 */
	void putCup(Key key,Object value);
	
	/**
	 * 通过对象的名称来获取对象
	 * @param name
	 *  对象的名称
	 * @return
	 *  对象
	 */
	Object get(String name);
	
	/**
	 * 通过接口来获取对象
	 *  ClasspathApplicationContext app
	 *  app.getBean("");
	 *  UserService userServiceImpl = app.getBean(UserService.class);
	 * @param clazz
	 *   对象接口
	 * @return
	 * 对象
	 */
	Object get(Class<?> clazz);

}

2.4.2 设计key
Key: 对象的标识 对象的标识有对象的名称 对象的接口也可以标识

package com.sxt.core.model;

import com.sxt.core.test.UserService;

/**
 * 对象的标识
 * @author CodeLab
 *
 */
public class Key implements Comparable<Key> {
   
   
	/**
	 * 对象的名称
	 */
	private String name;

	/**
	 * 对象的接口
	 */
	private Class<?> interfaces;
	

	public static Key of(String name) {
   
   
		return new Key(name, null);
	}
	
	public static Key of(Class<?> interfaces) {
   
   
		return new Key(null, interfaces);
	}
	
	
	public Key() {
   
   }
	public Key(String name, Class<?> interfaces) {
   
   
		super();
		this.name = name;
		this.interfaces = interfaces;
	}



	public String getName() {
   
   
		return name;
	}

	public void setName(String name) {
   
   
		this.name = name;
	}

	public Class<?> getInterfaces<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值