能简单说一下 Spring IOC 的实现机制吗?

能简单说一下 Spring IOC 的实现机制吗?
Spring的IOC本质上就是一个大工厂,我们可以想象一下一个工厂是如何运作的。
- 生产产品:工厂最核心的功能是生产产品。在Spring中,不需要由Bean自己来实例化,而是交给Spring来完成。这是通过反射来实现的。
那么工厂如何管理生产过程呢?答案无疑是工厂模式。
- 库存产品:工厂通常都会有库房,用于存放产品,因为生产出来的产品不能立即运走。在Spring中,我们知道它是一个容器,容器中存放的就是对象。为了避免每次需要对象时都进行现场的反射创建,创建好的对象需要被存储起来。
- 订单处理:工厂根据什么来提供产品呢?是根据订单。这些订单可能各式各样,有线上下单的,有工厂签订的,还有工厂销售人员上门签订的。这些订单经过处理后指导工厂进行生产和出货。
在Spring中也有类似的订单,它就是我们定义Bean和定义它们之间的依赖关系。这可以是XML形式的配置,也可以是我们熟悉的注解形式。
Bean 定义:
Bean 通过一个配置文件定义,把它解析成一个类型。
- beans.properties
偷懒,这里直接用了最方便解析的 properties,这里直接用一个<key,value>
类型的配置来代表 Bean 的定义,其中 key 是 beanName,value 是 class
userDao:cn.fighter3.bean.UserDao
- BeanDefinition.java
bean 定义类,配置文件中 bean 定义对应的实体
public class BeanDefinition {
private String beanName;
private Class beanClass;
//省略getter、setter
}
- ResourceLoader.java
资源加载器,用来完成配置文件中配置的加载
public class ResourceLoader {
public static Map<String, BeanDefinition> getResource() {
Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16);
Properties properties = new Properties();
try {
InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties");
properties.load(inputStream);
Iterator<String> it = properties.stringPropertyNames().iterator();
while (it.hasNext()) {
String key = it.next();
String className = properties.getProperty(key);
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setBeanName(key);
Class clazz = Class.forName(className);
beanDefinition.setBeanClass(clazz);
beanDefinitionMap.put(key, beanDefinition);
}
inputStream.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return beanDefinitionMap;
}
}
- BeanRegister.java
对象注册器,这里用于单例 bean 的缓存,我们大幅简化,默认所有 bean 都是单例的。可以看到所谓单例注册,也很简单,不过是往 HashMap 里存对象。
public class BeanRegister {
//单例Bean缓存
private Map<String, Object> singletonMap = new HashMap<>(32);
/**
* 获取单例Bean
*
* @param beanName bean名称
* @return
*/
public Object getSingletonBean(String beanName) {
return singletonMap.get(beanName);
}
/**
* 注册单例bean
*
* @param beanName
* @param bean
*/
public void registerSingletonBean(String beanName, Object bean) {
if (singletonMap.containsKey(beanName)) {
return;
}
singletonMap.put(beanName, bean);
}
}
- BeanFactory.java
- 对象工厂,我们最核心的一个类,在它初始化的时候,创建了 bean 注册器,完成了资源的加载。
获取 bean 的时候,先从单例缓存中取,如果没有取到,就创建并注册一个 bean
public class BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(); private BeanRegister beanRegister; public BeanFactory() { //创建bean注册器 beanRegister = new BeanRegister(); //加载资源 this.beanDefinitionMap = new ResourceLoader().getResource(); } /** * 获取bean * * @param beanName bean名称 * @return */ public Object getBean(String beanName) { //从bean缓存中取 Object bean = beanRegister.getSingletonBean(beanName); if (bean != null) { return bean; } //根据bean定义,创建bean return createBean(beanDefinitionMap.get(beanName)); } /** * 创建Bean * * @param beanDefinition bean定义 * @return */ private Object createBean(BeanDefinition beanDefinition) { try { Object bean = beanDefinition.getBeanClass().newInstance(); //缓存bean beanRegister.registerSingletonBean(beanDefinition.getBeanName(), bean); return bean; } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return null; } }
测试
- UserDao.java
我们的 Bean 类,很简单
public class UserDao { public void queryUserInfo(){ System.out.println("A good man."); } }
单元测试
public class ApiTest { @Test public void test_BeanFactory() { //1.创建bean工厂(同时完成了加载资源、创建注册单例bean注册器的操作) BeanFactory beanFactory = new BeanFactory(); //2.第一次获取bean(通过反射创建bean,缓存bean) UserDao userDao1 = (UserDao) beanFactory.getBean("userDao"); userDao1.queryUserInfo(); //3.第二次获取bean(从缓存中获取bean) UserDao userDao2 = (UserDao) beanFactory.getBean("userDao"); userDao2.queryUserInfo(); } }
运行结果
A good man. A good man.
至此,我们一个乞丐+破船版的 Spring 就完成了,代码也比较完整,有条件的可以跑一下。