Simple IOC 容器实现-基于XML配置

前端之家收集整理的这篇文章主要介绍了Simple IOC 容器实现-基于XML配置前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

IOC(Inversion of Control)“控制反转”,不过更流行的叫法是“依赖注入”(DI - Dependency Injection)。

什么是“控制反转”呢?其实就是将控制权(创建对象和对象之间的依赖关系的权利)交给Spring容器。以前我们写代码的需要某个对象的时候直接使用 new XXXImpl();,有了Spring IOC容器之后,它负责对象的创建和依赖注入,当我们需要某个对象时直接跟Spring IOC容器要就好了。

IOC 听起来很高大上,其实实现起来并不复杂。本文主要介绍基于XML配置的方式来实现一个IOC容器,后面会有单独的一章介绍如何通过注解的方式来实现IOC容器。

用法

具体用法与Spring IOC类似,如下:

1、beans.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>@H_301_17@
<beans@H_301_17@ xmlns@H_301_17@="http://www.springframework.org/schema/beans"@H_301_17@ xmlns:xsi@H_301_17@="http://www.w3.org/2001/XMLSchema-instance"@H_301_17@ xsi:schemaLocation@H_301_17@="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"@H_301_17@>@H_301_17@  

    <bean@H_301_17@ id@H_301_17@="userDao"@H_301_17@ class@H_301_17@="com.ricky.ioc.sample.dao.UserDaoImpl"@H_301_17@ scope@H_301_17@="singleton"@H_301_17@ init-method@H_301_17@="init"@H_301_17@ >@H_301_17@</bean@H_301_17@>@H_301_17@

    <bean@H_301_17@ id@H_301_17@="userService"@H_301_17@ class@H_301_17@="com.ricky.ioc.sample.service.UserServiceImpl"@H_301_17@>@H_301_17@  
        <property@H_301_17@ name@H_301_17@="userDao"@H_301_17@ ref@H_301_17@="userDao"@H_301_17@>@H_301_17@</property@H_301_17@>@H_301_17@  
    </bean@H_301_17@>@H_301_17@

    <bean@H_301_17@ id@H_301_17@="userController"@H_301_17@ class@H_301_17@="com.ricky.ioc.sample.controller.UserController"@H_301_17@>@H_301_17@  
        <property@H_301_17@ name@H_301_17@="userService"@H_301_17@ ref@H_301_17@="userService"@H_301_17@>@H_301_17@</property@H_301_17@>@H_301_17@  
    </bean@H_301_17@>@H_301_17@
</beans@H_301_17@>@H_301_17@

2、添加maven依赖

<dependency@H_301_17@>@H_301_17@
    <groupId@H_301_17@>@H_301_17@com.ricky.framework</groupId@H_301_17@>@H_301_17@
    <artifactId@H_301_17@>@H_301_17@ioc</artifactId@H_301_17@>@H_301_17@
    <version@H_301_17@>@H_301_17@1.0.0</version@H_301_17@>@H_301_17@
</dependency@H_301_17@>@H_301_17@

3、加载bean配置文件

ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"@H_301_17@);@H_301_17@

//通过id获取Bean
UserController userController =(UserController)ctx.getBean@H_301_17@("userController"@H_301_17@);@H_301_17@
userController.login@H_301_17@("ricky"@H_301_17@,"123"@H_301_17@);@H_301_17@

//通过Class获取Bean
UserService userService = ctx.getBean@H_301_17@(UserService.class@H_301_17@);@H_301_17@
System.out@H_301_17@.println@H_301_17@(userService);@H_301_17@
userService.login@H_301_17@("ricky"@H_301_17@,"abc"@H_301_17@);@H_301_17@

ctx.close@H_301_17@();@H_301_17@

运行结果如下:

UserController login name->ricky,password->123
UserServiceImpl login name->ricky,password->123
UserDaoImpl find name->ricky
com.ricky.ioc.sample.service.UserServiceImpl@214c265e
UserServiceImpl login name->ricky,password->abc
UserDaoImpl find name->ricky
container close…

具体实现

思路:
解析beans.xml获取Bean列表以及相互之间的依赖关系,然后通过反射技术构造出Bean实例,并根据Bean之间的依赖关系进行Bean装配。

首先,看看ApplicationContext类,代码如下:

package com@H_301_17@.ricky@H_301_17@.framework@H_301_17@.ioc@H_301_17@;@H_301_17@

import java.beans@H_301_17@.IntrospectionException@H_301_17@;@H_301_17@
import java.beans@H_301_17@.Introspector@H_301_17@;@H_301_17@
import java.beans@H_301_17@.PropertyDescriptor@H_301_17@;@H_301_17@
import java.lang@H_301_17@.reflect@H_301_17@.InvocationTargetException@H_301_17@;@H_301_17@
import java.lang@H_301_17@.reflect@H_301_17@.Method@H_301_17@;@H_301_17@

import org.apache@H_301_17@.commons@H_301_17@.lang@H_301_17@3.StringUtils@H_301_17@;@H_301_17@

import com@H_301_17@.ricky@H_301_17@.framework@H_301_17@.ioc@H_301_17@.model@H_301_17@.BeanDefinition@H_301_17@;@H_301_17@
import com@H_301_17@.ricky@H_301_17@.framework@H_301_17@.ioc@H_301_17@.model@H_301_17@.PropertyDefinition@H_301_17@;@H_301_17@
import com@H_301_17@.ricky@H_301_17@.framework@H_301_17@.ioc@H_301_17@.util@H_301_17@.ReflectionUtils@H_301_17@;@H_301_17@

public abstract class ApplicationContext {

    public abstract Object getBean(String id);@H_301_17@

    public abstract <T> T getBean(Class<T> clazz);@H_301_17@

    public abstract void close();@H_301_17@

    protected abstract BeanDefinition getBeanDefinition(String id);@H_301_17@

    protected Object createBean(BeanDefinition bd) {

        try {
            Object bean = ReflectionUtils.newInstance@H_301_17@(bd.getClassName@H_301_17@());@H_301_17@
            if(StringUtils.isNotEmpty@H_301_17@(bd.getInitMethodName@H_301_17@())){
                ReflectionUtils.invokeMethod@H_301_17@(bean,bd.getInitMethodName@H_301_17@());@H_301_17@
            }

            return bean;@H_301_17@
        } catch (ClassNotFoundException | InstantiationException
                | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException("create bean error,class->"@H_301_17@+bd.getClassName@H_301_17@(),e);@H_301_17@
        }
    }

    protected void injectBeanProperties(Object bean,BeanDefinition beanDefinition){

        try {
            PropertyDescriptor[] ps = Introspector.getBeanInfo@H_301_17@(bean.getClass@H_301_17@()).getPropertyDescriptors@H_301_17@(); @H_301_17@

            for(PropertyDefinition propertyDefinition : beanDefinition.getProperties@H_301_17@()){  

                for(PropertyDescriptor propertyDescriptor:ps){

                    if(propertyDescriptor.getName@H_301_17@().equals@H_301_17@(propertyDefinition.getName@H_301_17@())){  

                        Method setter = propertyDescriptor.getWriteMethod@H_301_17@(); @H_301_17@
                        setter.setAccessible@H_301_17@(true); @H_301_17@

                        setter.invoke@H_301_17@(bean,getBean(propertyDefinition.getRef@H_301_17@())); @H_301_17@
                    }
                }
            }
        } catch (SecurityException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException
                | IntrospectionException e) {
            throw new RuntimeException("inject bean properties error"@H_301_17@,e);@H_301_17@
        }
    }
}

在这涉及到两个关键类:BeanDefinition 和 PropertyDefinition,它们分别是用来描述 javabean的定义和javabean 属性的定义,一个BeanDefinition 可以有1个或多个PropertyDefinition,它们之间是1:N的关系。代码如下:

BeanDefinition.java

package@H_301_17@ com.ricky.framework.ioc.model;

import@H_301_17@ java.util.List;

public@H_301_17@ class@H_301_17@ BeanDefinition@H_301_17@ {@H_301_17@
    private@H_301_17@ String id;
    private@H_301_17@ String className;
    private@H_301_17@ String scope;   //singleton|prototype@H_301_17@
    private@H_301_17@ String initMethodName;
    private@H_301_17@ List<PropertyDefinition> properties;

    public@H_301_17@ BeanDefinition@H_301_17@(String id,String className) {  
        this@H_301_17@.id = id;  
        this@H_301_17@.className = className;  
    }

    public@H_301_17@ String getId@H_301_17@() {
        return@H_301_17@ id;
    }
    public@H_301_17@ void@H_301_17@ setId@H_301_17@(String id) {
        this@H_301_17@.id = id;
    }
    public@H_301_17@ String getClassName@H_301_17@() {
        return@H_301_17@ className;
    }
    public@H_301_17@ void@H_301_17@ setClassName@H_301_17@(String className) {
        this@H_301_17@.className = className;
    }
    public@H_301_17@ String getScope@H_301_17@() {
        return@H_301_17@ scope;
    }
    public@H_301_17@ void@H_301_17@ setScope@H_301_17@(String scope) {
        this@H_301_17@.scope = scope;
    }
    public@H_301_17@ String getInitMethodName@H_301_17@() {
        return@H_301_17@ initMethodName;
    }
    public@H_301_17@ void@H_301_17@ setInitMethodName@H_301_17@(String initMethodName) {
        this@H_301_17@.initMethodName = initMethodName;
    }
    public@H_301_17@ List<PropertyDefinition> getProperties@H_301_17@() {
        return@H_301_17@ properties;
    }
    public@H_301_17@ void@H_301_17@ setProperties@H_301_17@(List<PropertyDefinition> properties) {
        this@H_301_17@.properties = properties;
    }

    @Override@H_301_17@
    public@H_301_17@ String toString@H_301_17@() {
        return@H_301_17@ "BeanDefinition [id="@H_301_17@ + id + ",className="@H_301_17@ + className
                + ",scope="@H_301_17@ + scope + ",initMethodName="@H_301_17@ + initMethodName
                + ",properties="@H_301_17@ + properties + "]"@H_301_17@;
    }

}

PropertyDefinition.java

package com.ricky.framework.ioc.model;

public@H_301_17@ class@H_301_17@ PropertyDefinition {  
    private@H_301_17@ String name;
    private@H_301_17@ String ref@H_301_17@;

    public@H_301_17@ PropertyDefinition@H_301_17@(String name,String ref@H_301_17@) {  
        this@H_301_17@.name = name;  
        this@H_301_17@.ref@H_301_17@ = ref@H_301_17@;  
    }  
    public@H_301_17@ String getName@H_301_17@() {  
        return@H_301_17@ name;  
    }  
    public@H_301_17@ void@H_301_17@ setName@H_301_17@(String name) {  
        this@H_301_17@.name = name;  
    }  
    public@H_301_17@ String getRef@H_301_17@() {  
        return@H_301_17@ ref@H_301_17@;  
    }  
    public@H_301_17@ void@H_301_17@ setRef@H_301_17@(String ref@H_301_17@) {  
        this@H_301_17@.ref@H_301_17@ = ref@H_301_17@;  
    }

    @Override
    public@H_301_17@ String toString@H_301_17@() {
        return@H_301_17@ "PropertyDefinition [name="@H_301_17@ + name + ",ref="@H_301_17@ + ref@H_301_17@ + "]"@H_301_17@;
    }

}

2、接下来是ClassPathXmlApplicationContext类,代码如下:

package@H_301_17@ com.ricky.framework.ioc;

import@H_301_17@ java.io.FileNotFoundException;
import@H_301_17@ java.util.HashMap;
import@H_301_17@ java.util.List;
import@H_301_17@ java.util.Map;

import@H_301_17@ org.apache.commons.lang3.StringUtils;
import@H_301_17@ org.dom4j.DocumentException;

import@H_301_17@ com.ricky.framework.ioc.model.BeanDefinition;
import@H_301_17@ com.ricky.framework.ioc.parser.BeanXmlConfigParser;
import@H_301_17@ com.ricky.framework.ioc.util.BeanScope;
import@H_301_17@ com.ricky.framework.ioc.util.ReflectionUtils;

public@H_301_17@ class@H_301_17@ ClassPathXmlApplicationContext@H_301_17@ extends@H_301_17@ ApplicationContext@H_301_17@ {@H_301_17@

    private@H_301_17@ Map<String,BeanDefinition> beanDefinitionMap = new@H_301_17@ HashMap<String,BeanDefinition>();
    protected@H_301_17@ Map<String,Object> beanInstanceMap = new@H_301_17@ HashMap<String,Object>();

    public@H_301_17@ ClassPathXmlApplicationContext@H_301_17@(String xmlFilePath) {

        System.out.println("****************container init begin****************"@H_301_17@);

        readXml(xmlFilePath);
        initBeans();
        injectBeans();

        System.out.println("****************container init end****************"@H_301_17@);
    }

    private@H_301_17@ void@H_301_17@ readXml@H_301_17@(String xmlFilePath) {

        BeanXmlConfigParser beanXmlConfigParser = new@H_301_17@ BeanXmlConfigParser();

        List<BeanDefinition> bean_def_list = null@H_301_17@;
        try@H_301_17@ {
            bean_def_list = beanXmlConfigParser.parse(xmlFilePath);
        } catch@H_301_17@ (FileNotFoundException e) {
            throw@H_301_17@ new@H_301_17@ RuntimeException("not found bean xml,file->"@H_301_17@+xmlFilePath,e);
        } catch@H_301_17@ (DocumentException e) {
            throw@H_301_17@ new@H_301_17@ RuntimeException("bean xml format error,e);
        }

        for@H_301_17@ (BeanDefinition beanDefinition : bean_def_list) {

            if@H_301_17@(StringUtils.isEmpty(beanDefinition.getId()) || StringUtils.isEmpty(beanDefinition.getClassName())){
                throw@H_301_17@ new@H_301_17@ IllegalArgumentException("bean definition is empty!"@H_301_17@);
            }

            if@H_301_17@ (beanDefinitionMap.containsKey(beanDefinition.getId())) {
                throw@H_301_17@ new@H_301_17@ IllegalArgumentException(
                        "duplicated bean id,id->"@H_301_17@
                                + beanDefinition.getId());
            }

            beanDefinitionMap.put(beanDefinition.getId(),beanDefinition);
        }
    }

    private@H_301_17@ void@H_301_17@ initBeans@H_301_17@() {

        for@H_301_17@ (Map.Entry<String,BeanDefinition> me : beanDefinitionMap.entrySet()) {

            BeanDefinition bd = me.getValue();
            if@H_301_17@(StringUtils.isEmpty(bd.getScope()) || bd.getScope().equals(BeanScope.SINGLETON)){
                try@H_301_17@ {
                    Object bean = createBean(bd);
                    beanInstanceMap.put(bd.getId(),bean);
                } catch@H_301_17@ (Exception e) {
                    throw@H_301_17@ new@H_301_17@ IllegalArgumentException("create bean error,class->"@H_301_17@+bd.getClassName(),e);
                }
            }
        }
    }

    private@H_301_17@ void@H_301_17@ injectBeans@H_301_17@() {

        for@H_301_17@ (Map.Entry<String,BeanDefinition> me : beanDefinitionMap.entrySet()) {

            BeanDefinition beanDefinition = me.getValue();
            //判断有没有注入属性 @H_301_17@
            if@H_301_17@ (beanDefinition.getProperties() != null@H_301_17@ && beanDefinition.getProperties().size()>0@H_301_17@) {  

                Object bean = beanInstanceMap.get(beanDefinition.getId());  
                try@H_301_17@ {
                    injectBeanProperties(bean,beanDefinition);
                } catch@H_301_17@ (Exception e) {
                    e.printStackTrace();
                }
            }  
        }  
    }

    @Override@H_301_17@
    public@H_301_17@ Object getBean@H_301_17@(String id) {

// System.out.println("get bean by id:"+id);@H_301_17@

        if@H_301_17@ (StringUtils.isEmpty(id)) {
            return@H_301_17@ null@H_301_17@;
        }

        if@H_301_17@ (beanDefinitionMap.containsKey(id)) {

            BeanDefinition bd = beanDefinitionMap.get(id);

            if@H_301_17@(StringUtils.isEmpty(bd.getScope()) || bd.getScope().equals(BeanScope.SINGLETON)){

                return@H_301_17@ beanInstanceMap.get(id);
            }

            Object bean = null@H_301_17@;
            try@H_301_17@ {
                bean = createBean(bd);
                injectBeanProperties(bean,bd);
                beanInstanceMap.put(bd.getId(),bean);
            } catch@H_301_17@ (Exception e) {
                e.printStackTrace();
            }

            return@H_301_17@ bean;
        }
        throw@H_301_17@ new@H_301_17@ IllegalArgumentException("unknown bean,id->"@H_301_17@ + id);
    }

    @SuppressWarnings@H_301_17@("unchecked"@H_301_17@)
    @Override@H_301_17@
    public@H_301_17@ <T> T getBean@H_301_17@(Class<T> clazz) {

// System.out.println("get bean by type:"+clazz.getName());@H_301_17@

        for@H_301_17@(Map.Entry<String,BeanDefinition> me : beanDefinitionMap.entrySet()){

            BeanDefinition bd = me.getValue();
            Class<?> beanClass = null@H_301_17@;
            try@H_301_17@ {
                beanClass = ReflectionUtils.loadClass(bd.getClassName());
            } catch@H_301_17@ (ClassNotFoundException e) {
                e.printStackTrace();
            }

            if@H_301_17@(beanClass!=null@H_301_17@ && clazz.isAssignableFrom(beanClass)){
// System.out.println("find bean by type,class->"+clazz.getName());@H_301_17@
                return@H_301_17@ (T) getBean(bd.getId());
            }
        }

        return@H_301_17@ null@H_301_17@;
    }

    @Override@H_301_17@
    protected@H_301_17@ BeanDefinition getBeanDefinition@H_301_17@(String id) {

        return@H_301_17@ beanDefinitionMap.get(id);
    }

    @Override@H_301_17@
    public@H_301_17@ void@H_301_17@ close@H_301_17@() {

        System.out.println("container close..."@H_301_17@);

        // release resource@H_301_17@
        beanDefinitionMap.clear();
        beanDefinitionMap = null@H_301_17@;

        beanInstanceMap.clear();
        beanInstanceMap = null@H_301_17@;
    }

}

在ClassPathXmlApplicationContext类中,主要负责三大功能:解析XML配置文件、通过反射构建Bean实例以及对Bean进行装配。


小结

以上所有代码均已上传GitHub上,欢迎大家fork。另外由于时间比较仓促,代码设计上有不合理的地方还请包涵,后面会抽时间对代码进行重构。

原文链接:https://www.f2er.com/xml/295215.html

猜你在找的XML相关文章