我们讲一个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容器的实现,就完事了,

流程大致分为了

配置文件解析

创建对象

管理生命周期

发表评论

邮箱地址不会被公开。 必填项已用*标注