码迷,mamicode.com
首页 > 编程语言 > 详细

自定义Spring--DI依赖注入

时间:2014-11-12 22:53:39      阅读:275      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   io   color   ar   使用   java   sp   

1.框架思想

IoC(Inversion of Control,控制反转,反向控制),或者成为DI(Dependency Injection,依赖注入).

在传统程序中,相互的依赖性是固定在程序中的.程序的运行也是一步一步的,完全按照程序代码执行,根据代码就能知道程序怎样运行.

在Spring中程序间的依赖关系并不是直接写在程序中,而是配置在Spring文件中,有Spring在运行时配置的.在编译阶段,既没有实例化对象,也没有设置依赖关系,而是把依赖关系交给Spring,有Spring在运行阶段进行实例化,并组装对象.这种做法颠覆了传统的写代码,实例化,组装对象,然后一步一步执行的做法,因此被称为反向控制.

2.实现步骤

a.分析

传统创建对象的方式:

接口=new 实现类()的方式 

IBusinessService  businessService = new BusinessServiceImpl ();

使用Spring创建对象的方式:

接口 = BeanFactory.getBean(“配置文件中配置的Bean的Id属性的值”); 

IBusinessService businessService = BeanFactory.getBean("businessService");

b.配置文件与使用时注意

    1)如何通过接口的标识找到对应的实现类?

         需要在XML文件对每个名字对应的实现类进行配置,得到实现类的类名之后通过反射的方式获取实现类的字节码,再通过字节码创建实现类对象.

   <bean id="businessService" class="com.itheima.ebookstore.service.impl.BusinessServiceImpl" >

   2)对于实现类中成员变量为对象类型时,如何在创建实现类对象时保证成员变量已经被实例化?

         接下来对实现类中成员进行配置,name属性对应实现类中成员变量的标识,成员变量在声明时依然采用接口的方式,以方便当接口对应的实现类发生变化时,进行扩展,ref表示成员变量声明时采用的接口的标识,通过这个标识可以找到对应的实现类.

<property name="userDao" ref="userDao" value=""/>

        具体的配置文件如下:

   文件名:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> 
<beans> 
    <bean id="categoryDao" class="com.itheima.ebookstore.dao.impl.CategoryDaoImpl" scope="prototype"/> 
    <bean id="userDao" class="com.itheima.ebookstore.dao.impl.UserDaoImpl" scope="prototype"/> 
    <bean id="bookDao" class="com.itheima.ebookstore.dao.impl.BookDaoImpl" scope="prototype"/> 

<!-- 配置需要执行setter方法,及需要设置的内容的bean id

使用<property>标签进行配置

name="" 属性名,用于确定指定setter方法

ref="" 另一个bean实例的引用 id

-->

    <bean id="businessService" class="com.itheima.ebookstore.service.impl.BusinessServiceImpl" > 
        <property name="userDao" ref="userDao" value=""/> 
        <property name="bookDao" ref="bookDao" value=""/> 
        <property name="categoryDao" ref="categoryDao" value=""/> 
    </bean>    
</beans>

  存放位置的配置:

     可以在当前项目的web.xml中进行配置(通过ServletContext对象getInitParameter方法获得)

<context-param>

<param-name>contextConfigLocation</param-name>

< ---配置文件的存放位置:前缀classpath:指的是配置文件存放在src路径下,生成Web项目对应在WEB-INF/classes路径下,无前缀指的是在放在WEB-INF路径下-- >

<param-value>classpath: applicationContext.xml</param-value>

<param-value>applicationContext.xml</param-value>

<param-value>classpath: applicationContext.xml</param-value>

</context-param>

   3)使用时注意:

当接口对应实现类中有成员变量希望框架自动进行实例化,需要为该变量提供Set方法

其中接口IBusinessService 的实现类如下:

public class BusinessServiceImpl implements IBusinessService { 
    private ICategoryDao categoryDao; 
    private IUserDao userDao ; 
    private IBookDao bookDao ; 
    public void setCategoryDao(ICategoryDao categoryDao) { 
        this.categoryDao = categoryDao; 
    } 

    public void setUserDao(IUserDao userDao) { 
        this.userDao = userDao; 
    } 

    public void setBookDao(IBookDao bookDao) { 
        this.bookDao = bookDao; 
    } 

}

c.实现自定义框架

  对XML的bean标签封装到Bean类对象中,并将Bean对象存放在BeanFactory工厂类中,以便工厂在创建实例对象的时候参照,XML文件中有多个bean标签,对应多个接口的配置,需要使用容器将Bean对象保存起来,为了方便的使用接口标识直接能够得到Bean类对象,在工厂中定义成员private static Map<String,Bean> beanMap = new HashMap<String,Bean>();对XML的解析结果进行缓存,缓存的工作可以由ServletContext对象的监听器事件去完成.

  XML配置文件中,Bean标签对应的类实现:

/** 以下标签的封装对象 
* <bean id="" class="" scope=""></bean> 
* @author Administrator 
* 
*/ 
public class Bean { 
    private String beanId; 
    private String beanClass; 
    private String beanScope;  //暂 不使用 
    //一对多:一个bean 可以使用 【多个属性】--容器 Set(不重复、无序) 
    private Set<Property> propSet = new HashSet<Property>() ; //注意:建议将容器进行实例化,方便操作。 
    public String getBeanId() { 
        return beanId; 
    } 
    public void setBeanId(String beanId) { 
        this.beanId = beanId; 
    } 
    public String getBeanClass() { 
        return beanClass; 
    } 
    public void setBeanClass(String beanClass) { 
        this.beanClass = beanClass; 
    } 
    public String getBeanScope() { 
        return beanScope; 
    } 
    public void setBeanScope(String beanScope) { 
        this.beanScope = beanScope; 
    } 
    public Bean() { 
        super(); 
    } 
    public Bean(String beanId, String beanClass, String beanScope) { 
        super(); 
        this.beanId = beanId; 
        this.beanClass = beanClass; 
        this.beanScope = beanScope; 
    } 
    public Set<Property> getPropSet() { 
        return propSet; 
    } 
    public void setPropSet(Set<Property> propSet) { 
        this.propSet = propSet; 
    } 
}

XML配置文件中,Property标签对应的类实现:

/** 
* 用于封装 xml文件中 <property name="" ref="" value=""> 
* @author Administrator 
* 
*/ 
public class Property { 
    private String propName;        //属性名 
    private String propRef;            //属性引用bean的id值 
    private String propValue;        //属性值(暂不用) 
    public String getPropName() { 
        return propName; 
    } 
    public void setPropName(String propName) { 
        this.propName = propName; 
    } 
    public String getPropRef() { 
        return propRef; 
    } 
    public void setPropRef(String propRef) { 
        this.propRef = propRef; 
    } 
    public String getPropValue() { 
        return propValue; 
    } 
    public void setPropValue(String propValue) { 
        this.propValue = propValue; 
    } 
    public Property() { 
        super(); 
    } 
    public Property(String propName, String propRef, String propValue) { 
        super(); 
        this.propName = propName; 
        this.propRef = propRef; 
        this.propValue = propValue; 
    } 
}

BeanFactory的实现:

public class BeanFactory { 
    // key : beanId ; value : <bean>标签封装对象 
    private static Map<String,Bean> data = new HashMap<String, Bean>(); 
    public static Map<String, Bean> getData() { 
        return data; 
    } 
    /** 
     * 通过bean标示符获得bean实例 
     * @param beanId 
     * @return 
     */ 
    public static Object getBean(String beanId){ 
        //通过 id 获得 类的全限定类名,并使用反射进行实例化 
        try { 
            //1 通过id获得Bean对象 
            Bean bean = data.get(beanId); 
            if (bean == null) { 
                throw new RuntimeException("[" + beanId + "]不存在,请检查配置文件"); 
            } 
            //2 获得全限定类名 
            String beanClass = bean.getBeanClass(); 
            //3 创建bean实例 
            Class clazz = Class.forName(beanClass); 
            Object beanObj = clazz.newInstance();  //new BusinessServiceImpl() 
            //4 执行实例的setter,注意,需要在实现类中对相应属性提供Set方法 
            // * 获得所有<property>内容,执行 setter方法,并将ref对应的实例进行设置 
            for(Property prop:bean.getPropSet()){ 
                // 属性名:表示需要指定setter方法 
                String propName = prop.getPropName(); 
                // 引用名称:表示使用getBean获得实例 
                String propRef = prop.getPropRef(); 
                // 引用对应实例对象 
                Object propRefObj = getBean(propRef); 
                // 将对用的值设置相应的实例 
                BeanUtils.setProperty(beanObj, propName, propRefObj); 
            } 
            //返回创建的实例 
            return beanObj; 
        } catch (Exception e) { 
            throw new RuntimeException(e); 
        } 
    } 
    public static <T> T getBean(String beanId,Class<T> clazz){ 
        return (T)getBean(beanId); 
    } 

}

在ServletContext对象的监听器中将XML文件中的标签解析为对应的Java类对象,并将解析的结果保存在BeanFactory中:

public class ContextLoaderListener implements ServletContextListener { 

    @Override 
    public void contextInitialized(ServletContextEvent sce) { 
        //1 获得web.xml文件配置 spring配置文件位置 
        ServletContext sc = sce.getServletContext(); 
        String contextConfigLocation = sc.getInitParameter("contextConfigLocation"); 
        //2 获得资源流 
        InputStream is = null; 
        if(contextConfigLocation.startsWith("classpath:")){ 
            //xml在src下 
            String fileName = contextConfigLocation.substring("classpath:".length()); 
            is = ContextLoaderListener.class.getClassLoader().getResourceAsStream(fileName); 
        } else{ 
            //WEB-INF目录下 
            is = sc.getResourceAsStream("/WEB-INF/" + contextConfigLocation); 
        } 
        //3 解析并封装 
        parser(is); 
    } 
    /** 
     * 使用dom4j解析 
     * @param is 
     */ 
    private void parser(InputStream is) { 
        try { 
            //1 获得doucument 
            SAXReader saxReader = new SAXReader(); 
            Document document = saxReader.read(is); 
            //2 解析 
            //2.1 获得根元素 
            Element rootElement = document.getRootElement(); 
            //2.2 获得所有的<bean>元素 
            List<Element> allBeanElement = rootElement.elements("bean"); 
            //2.3 遍历 
            for (Element beanElement : allBeanElement) { 
                //2.4.1 id属性 
                String beanId = beanElement.attributeValue("id"); 
                //2.4.2 class属性 
                String beanClass = beanElement.attributeValue("class"); 
                //2.4.3 scope属性 
                String beanScope = beanElement.attributeValue("scope"); 
                //2.5 封装 Bean对象,添加BeanFactory的提供Map中 
                Bean bean = new Bean(beanId, beanClass, beanScope); 
                /**2.6 解析 <bean>中 <property> start*/ 
                // 2.6.1 获得所有的<property>元素 
                List<Element> allPropElement = beanElement.elements("property"); 
                for(Element propElement : allPropElement){ 
                    //2.6.2 获得name属性 
                    String propName = propElement.attributeValue("name"); 
                    //2.6.3 获得ref属性 
                    String propRef = propElement.attributeValue("ref"); 
                    //2.6.4 获得value属性 
                    String propValue = propElement.attributeValue("value"); 
                    //2.6.5 将获得内容,封装 JavaBean Property对象中,并添加到 bean实例 
                    Property prop = new Property(propName, propRef, propValue); 
                    bean.getPropSet().add(prop); 
                } 
                /**解析 <bean>中 <property> end*/ 
                BeanFactory.getData().put(beanId, bean); 
            } 
            System.out.println("--------------- 配置解析完成,加载了"+BeanFactory.getData().size()+"<bean>标签"); 
        } catch (Exception e) { 
            throw new RuntimeException(e); 
        } 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent sce) { 

    } 
}

自定义Spring--DI依赖注入

标签:des   style   blog   io   color   ar   使用   java   sp   

原文地址:http://www.cnblogs.com/fujianyi/p/4093532.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!