手写Spring之 实现Bean管理(IOC与DI)
写在前面
最近学习了一下spring的相关内容,所以也就想要照猫画虎地记录一下spring的框架,通过阅读这些也希望能够消除对Spring框架的恐惧,其实细心阅读也很容易理解。
项目的源码我放在了github上:源码地址
我会在这里整理文章的系列目录:
- 从头开始实现一个小型spring框架——手写Spring之实现SpringBoot启动
- 从头开始实现一个小型spring框架——手写Spring之集成Tomcat服务器
- 从头开始实现一个小型spring框架——控制器controller的实现
- 从头开始实现一个小型spring框架——实现Bean管理(IOC与DI)
一、bean管理
1.1 什么是bean?
- bean是spring抽象出的概念
区别于普通的对象,bean的声明周期一般较长。 - 在整个虚拟机中都是可见的
普通的对象仅在当前类可见,在其他类中是引用不到的。因此对bean的维护成本要高于对普通对象的维护。 - bean一般单例存在
正因为对bean的维护成本很高,因此bean单例存在。
1.2 bean优势
- 运行期效率高
bean在项目启动时初始化,使用时直接获取,提高了获取对象的性能;也减少了代码在维护上成本;减少了对象使用过后被抛弃的情况,降低虚拟机在gc时的压力。 - 统一维护,便于管理和拓展
不必处理链式的依赖 - 单例存在
二、依赖注入和控制反转
很多人认为控制反转和依赖注入是相同的,其实这是一个误区。
2.1 控制反转
IOC(Inversion of Control):思想
控制反转是一种设计的原则和思想,用来降低代码之间的耦合度。
2.2 依赖注入
DI(Dependency Injection):方式
依赖注入是实现IOC的一种方式。
采用依赖注入的方式,类A中只需要定义一个B的属性,不需要通过new来获取对象,二是通过bean容器将对象new出来,并注入到A对象的引用里。
控制正转方式:

控制反转创建的方式:
三、实现
因为我们已经在上一篇文章中实现了包扫描,所以可以非常方便获取到类的信息。
获取到类的信息后,我们就要根据是否存在需要注入的依赖来实例化 Bean对象了,我们来看具体的实现:
3.1 包结构的改变
直接看下图

更改后的内容添加了对依赖注入的实现,具体有
framework模块:
- beans包下增加
- Autowired自定义注解:用于标记需要进行注入的域
- Bean自定义注解:标记类为需要实例化的Bean
test模块
- service包增加
- UserService :实现到controller的注入
3.2 具体实现
framework模块
Autowired标记注解
package com.qcby.beans;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}
Bean注解
package com.qcby.beans;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Bean {
}
BeanFactory工厂
这是本次实现的核心代码,将Bean通过map的形式进行保存,提供getBean,initBean方法对Bean容器内的实例进行获取和初始化Bean容器
package com.qcby.beans;
import com.qcby.web.mvc.Controller;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author kevinlyz
* @ClassName BeanFactory
* @Description bean工厂
* @Date 2019-06-09 11:09
**/
public class BeanFactory {
//ConcurrentHashMap保存bean
public static Map<Class<?>,Object> classToBean = new ConcurrentHashMap<>();
//获取bean
public static Object getBean(Class<?> cls){
return classToBean.get(cls)