浅试实现mini-spring-ioc容器

系统管理员 2024-03-24 17:59 126阅读 0赞

IOC

我们学Java的基本上都会使用Spring进行开发,而Spring中最为核心的又是IOC和AOP,接下来的内容是在学习手写Spring渐进式源码实践这本书后的学习总结,看是否我们能开发出一个mini-Spring

第一章:实现一个简单的Spring Bean容器

先不深究Spring源码,我就看自己平时使用Spring时的体会,使用Spring时,通过XML配置文件或者通过注解,声明哪些类是需要注入到容器中的,到自己使用时,可以从容器中获取该类对象。那这不就是我们基础中学的Collection或者Map就能实现的操作嘛,因为我需要频繁的从容器中获取指定类对象,所以查询返回的效率需要非常高,那就我们就用Map来实现,先不要想那么多。

  1. public class BeanFactory {
  2. // 用Map来存储Bean
  3. private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
  4. // 获取
  5. public Object getBean(String name) {
  6. return beanDefinitionMap.get(name).getBean();
  7. }
  8. // 注册
  9. public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
  10. beanDefinitionMap.put(name, beanDefinition);
  11. }
  12. }
  13. 复制代码

这里我们使用BeanDefinition来包裹实际的对象,因为我们知道一个Bean不仅拥有自己属性,还拥有一些通用属性,比如:单例模式还是原型模式,Bean内需要填充的属性,这里我们只做包裹,其余的后面实现。

  1. public class BeanDefinition {
  2. // 实际填充的对象
  3. private Object bean;
  4. // 省略 构造器 和 get方法。。
  5. }
  6. 复制代码

我们来测试一下:

  1. @Test
  2. public void test_BeanFactory(){
  3. // 1.初始化 BeanFactory
  4. BeanFactory beanFactory = new BeanFactory();
  5. // 2.注入bean
  6. BeanDefinition beanDefinition = new BeanDefinition(new UserService());
  7. beanFactory.registerBeanDefinition("userService", beanDefinition);
  8. // 3.获取bean
  9. UserService userService = (UserService) beanFactory.getBean("userService");
  10. userService.queryUserInfo();
  11. }
  12. 复制代码

第二章:实现Bean对象的定义,注册和获取

在上面我们可以看到我是创建好了的UserService放入容器中,这和我们之前学的依赖倒置并不符合,我们应只指定哪些Bean需要加载到容器中,具体的对象实例应又BeanFactory自己管理,所以我们修改BeanDefinition,在内只存放Bean的Class对象。

  1. public class BeanDefinition {
  2. private Class beanClass;
  3. // 构造器 get,set方法
  4. }
  5. 复制代码

BeanFactory也修改为接口,定义获取Bean的方式,具体Bean存储与获取交给子类来实现,使职责单一。

我们在这里先假设每个Bean都是单例的,创建SingletonBeanRegistry接口,定义注册和获取单例对象的方式,剩下的交给子类具体实现。

现在系统中有两个容器,一个是BeanDefinitionMap负责存储加载到容器的Bean信息,一个是singletonObjects负责存储已经创建好的单例对象。具体可看下面的UML类图,关系还是很清楚的。BeanFactory在实例化对象时,通过BeanDefinitionMap中的类信息,通过反射直接创建对象,并放入容器中。

Spring中有大量的接口与抽象类,我个人感觉是将职责划分清楚,容易未来系统的扩展性,有一点是通过抽象类去实现接口,并定义自己的抽象方法,而且可以实现一部分的接口方法,这样既可以扩容接口,又能保证自己可以只实现自己职责内的方法。

第三章:基于Cglib实现含有构造函数的类实例化策略

在第二章中我们在AbstractAutowireCapableBeanFactory::createBean中通过反射进行Bean的实例化,这一章我们引入了实例化策略:InstantiationStrategy,并通过JDK和Cglib两个种方式去实现。

JDK 和 Cglib实例化对象有什么区别

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

format_png

第四章:注入属性与依赖对象

format_png 1

比方说我UserService内需要注入UserDao来操作数据库,所以我在实例化Bean后,应将所需的属性和依赖注入到Bean中,而这部分信息通过PropertyValues记录,并封装到BeanDefinition中。在实例化后应通过对应BeanDefinition获取到需要哪些内容,并进行填充处理。

format_png 2

第五章:资源加载器解析文件注册对象

format_png 3

这里我们要加入XML解析,在上面我们都是手动将所有信息通过Java注册到BeanFactory的,这不利于维护,现实Spring中我们都是使用Xml进行配置或者注解开发,所以我们需要定义一个ResourceLoader去加载各种数据(XML文件,URL,Classpath)。

资源加载,读取指定资源,转化为Resource,核心是获取文件的二进制流为后面解析

format_png 4

资源解析:利用XML解析器解析Spring.xml文件,获取所有Bean信息定义,并将其封装为BeanDefinition并注册

发表评论

表情:
评论列表 (有 0 条评论,126人围观)

还没有评论,来说两句吧...

相关阅读

    相关 谈C++ STL 容器

    什么是容器 首先,我们必须理解一下什么是容器,在C++ 中容器被定义为:在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对像的指针,这种对象类型就叫做容器。很简单,