我们讲一个Spring框架所依赖的核心容器 依赖注入容器,或者说依赖注入框架,简称DI容器,在今天,我们就实现一个DI容器的最小原型
那么什么是DI容器,他和我们的主题工厂模式有什么关系吗,其实DI容器从本质上来说,就是一个大的工厂类,负责在整个程序启动的时候,根据配置,来事先创建好对象,当应用程序启动的时候,根据配置,创建好对象,这样,在程序需要某个对象的时候,直接从容器中获取就可以了,也是因为他存储了一堆的对象,才会被称为容器
DI容器在工厂模式的基础上,包含了配置的解析,对象创建,对象的生命周期关系等功能
1.配置解析
因为对于一个框架来说,在运行之前,是不知道要创建哪些对象的,需要让应用告诉DI容器要创建什么对象,这就是我们要讲的配置
我们将需要由DI容器来创建的类或者对象以及创建对象的必要信息,例如参数,放到配置容器中,容器读取这个配置文件,并根据配置文件提供的信息来创建对象
具体的配置文件如下,下面是一个类的创建依赖于另外一个类
public class RateLimiter {
private RedisCounter redisCounter; public RateLimiter(RedisCounter redisCounter) { this.redisCounter = redisCounter; } public void test() { System.out.println(“Hello World!”); } //… } public class RedisCounter { private String ipAddress; private int port; public RedisCounter(String ipAddress, int port) { this.ipAddress = ipAddress; this.port = port; } //… } |
配置文件beans.xml:
<beans>
<bean id=”rateLimiter” class=”com.xzg.RateLimiter”> <constructor-arg ref=”redisCounter”/> </bean> <bean id=”redisCounter” class=”com.xzg.redisCounter”> <constructor-arg type=”String” value=”127.0.0.1″> <constructor-arg type=”int” value=1234> </bean> </beans> |
2,对象创建
我们给每一个类创建一个工厂类,类的个数会成倍的增加,所以可以将所有的类的创建都放在一个工厂类就可以了,例如BeansFactory
3.生命周期管理
工厂模式有两种实现方式,一种是每次创建新的对象,一种返回固定的对象,也就是一个是单例的,一个是每次创建新的,而且我们还可以选择是否是懒加载,是否是等到了对象真正被用到了,才会创建,还是对象在应用启动的时候,就创建好
而且可以配置对象的init-method和destory-method,来指定初始化的时候执行的对象,摧毁的时候执行的方法
那么如何实现一个简单的DI容器
在本次中,我们实现一个最小原型,可以配置文件,并且去获取实例,代码如下
配置文件beans.xml
<beans>
<bean id=”rateLimiter” class=”com.xzg.RateLimiter”> <constructor-arg ref=”redisCounter”/> </bean> <bean id=”redisCounter” class=”com.xzg.redisCounter” scope=”singleton” lazy-init=”true”> <constructor-arg type=”String” value=”127.0.0.1″> <constructor-arg type=”int” value=1234> </bean> </bean public class Demo { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( “beans.xml “); RateLimiter rateLimiter = (RateLimiter) applicationContext.getBean(“rateLimiter”); rateLimiter.test(); //… } } |
其中的ApplicationContext是我们暴露的外部入口,通过指定的方法来初始化整个框架
public interface ApplicationContext {
Object getBean(String beanId); } public class ClassPathXmlApplicationContext implements ApplicationContext { private BeansFactory beansFactory; private BeanConfigParser beanConfigParser; public ClassPathXmlApplicationContext(String configLocation) { this.beansFactory = new BeansFactory(); this.beanConfigParser = new XmlBeanConfigParser(); loadBeanDefinitions(configLocation); } private void loadBeanDefinitions(String configLocation) { InputStream in = null; try { in = this.getClass().getResourceAsStream(“/” + configLocation); if (in == null) { throw new RuntimeException(“Can not find config file: ” + configLocation); } List<BeanDefinition> beanDefinitions = beanConfigParser.parse(in); beansFactory.addBeanDefinitions(beanDefinitions); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // TODO: log error } } } } @Override public Object getBean(String beanId) { return beansFactory.getBean(beanId); } } |
然后具体流程如下,在ClassPathXmlApplicationContext中,继承了ApplicaiotnContextg
并且利用beanConfigParser来解析配置文件,获取为beanDefintions,集合类型的BeanDefinition,然后BeanFactorry通过这些BeanDefinition来创建对象
BeanConfigParser的实现如下
public interface BeanConfigParser {
List<BeanDefinition> parse(InputStream inputStream); List<BeanDefinition> parse(String configContent); } public class XmlBeanConfigParser implements BeanConfigParser { @Override public List<BeanDefinition> parse(InputStream inputStream) { String content = null; // TODO:… return parse(content); } @Override public List<BeanDefinition> parse(String configContent) { List<BeanDefinition> beanDefinitions = new ArrayList<>(); // TODO:… return beanDefinitions; } } public class BeanDefinition { private String id; private String className; private List<ConstructorArg> constructorArgs = new ArrayList<>(); private Scope scope = Scope.SINGLETON; private boolean lazyInit = false; // 省略必要的getter/setter/constructors public boolean isSingleton() { return scope.equals(Scope.SINGLETON); } public static enum Scope { SINGLETON, PROTOTYPE } public static class ConstructorArg { private boolean isRef; private Class type; private Object arg; // 省略必要的getter/setter/constructors } } |
解析完成,形成BeanDifinition类,从而方便去创建对象
然后是BeanFactory类的实现,这个类根据BeanDifinition来创建对象
public class BeansFactory {
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>(); private ConcurrentHashMap<String, BeanDefinition> beanDefinitions = new ConcurrentHashMap<>(); public void addBeanDefinitions(List<BeanDefinition> beanDefinitionList) { for (BeanDefinition beanDefinition : beanDefinitionList) { this.beanDefinitions.putIfAbsent(beanDefinition.getId(), beanDefinition); } for (BeanDefinition beanDefinition : beanDefinitionList) { if (beanDefinition.isLazyInit() == false && beanDefinition.isSingleton()) { createBean(beanDefinition); } } } public Object getBean(String beanId) { BeanDefinition beanDefinition = beanDefinitions.get(beanId); if (beanDefinition == null) { throw new NoSuchBeanDefinitionException(“Bean is not defined: ” + beanId); } return createBean(beanDefinition); } @VisibleForTesting protected Object createBean(BeanDefinition beanDefinition) { if (beanDefinition.isSingleton() && singletonObjects.contains(beanDefinition.getId())) { return singletonObjects.get(beanDefinition.getId()); } Object bean = null; try { Class beanClass = Class.forName(beanDefinition.getClassName()); List<BeanDefinition.ConstructorArg> args = beanDefinition.getConstructorArgs(); if (args.isEmpty()) { bean = beanClass.newInstance(); } else { Class[] argClasses = new Class[args.size()]; Object[] argObjects = new Object[args.size()]; for (int i = 0; i < args.size(); ++i) { BeanDefinition.ConstructorArg arg = args.get(i); if (!arg.getIsRef()) { argClasses[i] = arg.getType(); argObjects[i] = arg.getArg(); } else { BeanDefinition refBeanDefinition = beanDefinitions.getBean(arg.getArg()); if (refBeanDefinition == null) { throw new NoSuchBeanDefinitionException(“Bean is not defined: ” + arg.getArg()); } argClasses[i] = Class.forName(refBeanDefinition.getClassName()); argObjects[i] = createBean(refBeanDefinition); } } bean = beanClass.getConstructor(argClasses).newInstance(argObjects); } } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { throw new BeanCreationFailureException(“”, e); } if (bean != null && beanDefinition.isSingleton()) { singletonObjects.putIfAbsent(beanDefinition.getId(), bean); return singletonObjects.get(beanDefinition.getId()); } return bean; } } |
我们利用Java中的反射语法,来在JVM启动的时候,创建对象,并且如果这个设置为了singleton的话,就会将其放在一个singletonObjects的map中,下次在请求的时候,会直接从map中返回,不需要重新创建
而且支持了init的方法,但没有给出对应的摧毁方法的实现
这样,本章就完事了
讲解了IOC的实现,当然,这里放的是最小实现,但可以解决了其底层实现
那么,一个简单的DI容器的实现,就完事了,
流程大致分为了
配置文件解析
创建对象
管理生命周期