模拟Spring阐述依赖注入的思想以及spring的内部的实现原理(读取配置文件,通过反射进行装配和依赖注入)...

阅读: 评论:0

模拟Spring阐述依赖注入的思想以及spring的内部的实现原理(读取配置文件,通过反射进行装配和依赖注入)...

模拟Spring阐述依赖注入的思想以及spring的内部的实现原理(读取配置文件,通过反射进行装配和依赖注入)...

模拟Spring阐述依赖注入的思想以及spring的内部的实现原理(读取配置文件,通过反射进行装配和依赖注入)

/*

 * 想分层,把不同的层次作用以及之间的关系给别人说一遍。

 * 例如要想在数据库添加一个用户,一开始最土的方法是直接在main方法里面写数据库的连接,写直接写add一个用户,后来人们想到至少分一个层次出来即model层,但是添加的方法add写到

 * model层的话需要new一个对象才能使用这个方法,所以人们又想到对于用户的管理层,通过UserService调用User,之后添加用户会把User添加到DB中,也就是所UserService

 * 会访问User以及数据库DB。最初是这样的,但是这样不合理。如果我们想跨越数据库平台,我写的这个Userservice这个add方法呢,既能往mysql里面存,也能往Oracle中存,也

 * 可以往其他的数据库中存,那么这一个方法肯定是涵盖不了的,除非在里面写一大堆的if,所以更好的方法是抽象出来一个对数据库的管理层,这个我们可以称为DAO层,这里为UserDAO层

 * 由UserDAO负责和User以及数据库DB打交道(把User存到数据库中)对于UserService只需要访问UserDAO层,对外只提供UserService接口,由UserService来调用UserDAO

 * DAO层提供一个对数据库的屏蔽作用,例如底层数据库变了,只要变UserDAO就可以了。

 * 那么怎样实现跨数据库平台呢?我们在DAO层中的写UserDAO类,写成public class UserDAO{里面写 public void save(User user){}方法},但是这样的话把UserDAO写死了,因为save

 * 方法里面写了连接MySQL的代码,要想连接Oracle则需要改save方法里面的代码,把它换成连接Oracle的代码,这样比较麻烦。那怎么才能实现呢?才能变的灵活了?办法是面向抽象的编程,也就是面向接口的编程呢个,即把public class UserDAO

 * 该成public interface UserDAO{},接下来再分一个DAO的实现,实现了UserDAO 接口,然后实现里面的save方法。然后当我们使用UserService是对接口进行编程,userDAO = new UserDAOImpl();现在灵活性就出来了,要想实现跨数据库平台

 * 就可以多写几个UserDAO的实现,想连接mysql写UserDAOMysqlImpl的UserDAO的实现,相连接Oracle我们就写UserDAOOracleImpl的UserDAO的实现。然后Service层中的UserService需要用mysql存数据的时候就new UserDAOMysqlImpl()

 * 需要用Oracle的时候就new UserDAOOracleImpl()这个就叫做面向抽象的编程,原来的话就是写死的,现在就灵活了,相连接那个数据库就new哪个。

 * 假如说我有好多好多的DAO以及Service

 * 添加不同对象的管理,例如我想添加对老师的管理,就需要添加TeacherService,如果添加对课程的管理,就需要添加CourceService

 * 对应的子道中需要添加TeacherDAO,还需要添加TeacherDAOImpl,

 * 添加对学生的管理,就需要添加对学生的管理,需要添加StudentService,还需要添加StudentDAO,还需要

 * 添加其实现。这样就会产生很多的DAO。怎样管理不同对象的DAO呢,可以通过一个工厂来进行管理,就需要用到工厂模式

 * 这样其实也比较麻烦因为每一个不同的DAO都要产生不同的工厂,既然这样的话不如来一个大的工厂,把我们所有的具体的

 * DAO东西都用这个大的工厂来产生。这个工厂呢要求比较灵活的产生这些DAO,那么怎样实现呢?需要用配置文件来实现,用XML文件,那么就要学习怎样读取XML文件?

1.首先讲解dom4j 解析XML的过程:

     1.引入jar包,jdom-1.1.jar。

  

     2.把要解析的XML文件放到项目工程的src下面,代码如下

<?xml version="1.0" encoding="UTF-8"?>
<HD><disk name="C"><capacity>8G</capacity><directories>200</directories><files>1580</files></disk><disk name="D"><capacity>10G</capacity><directories>500</directories><files>3000</files></disk>
</HD> 


写解析jdom的方法:

import java.util.List;import org.jdom.*;
import org.jdom.input.SAXBuilder;public class sample1 {public static void main(String[] args) throws Exception{ SAXBuilder sb=new SAXBuilder();//构造文档对象Document doc=sb.build(ClassLoader().getResourceAsStream(&#l")); //获取根元素HDElement root&#RootElement(); //取名字为disk的所有元素List list&#Children("disk");//通过集合遍历所有元素,一个disk其实就是一个元素for(int i=0;i<list.size();i++){Element element = (Element) (i);String name = AttributeValue("name");//获取属性为name的值String capacity&#ChildText("capacity");//取disk子元素capacity的内容String directories&#ChildText("directories");String files&#ChildText("files");System.out.println("磁盘信息:");System.out.println("分区盘符:"+name);System.out.println("分区容量:"+capacity);System.out.println("目录数:"+directories);System.out.println("文件数:"+files);System.out.println("-----------------------------------");}  }
}
运行结果:
 
磁盘信息:
分区盘符:C
分区容量:8G
目录数:200
文件数:1580
-----------------------------------
磁盘信息:
分区盘符:D
分区容量:10G
目录数:500
文件数:3000
-----------------------------------


2.使用反射的思想和jdom解析XML文件模拟Spring容器初始解析配置文件的过程以及搞明白什么是IOC/DI

在不用Spring的时候,我们在Service调用DAO,需要在UserService里面把new Dao层的对象。例如private UserDao userDAO = new UserDAOImpl();有了容器后容器帮我们把DAO层注入到Service层。怎么注入的?我们看下面的代码:

下面是我的整个项目工程:

这里给出部分代码:

DAO层:

package com.lp.dao;import del.User;
//UserDao负责把对象存到不同的数据库中去,考虑为什么写成接口,而不写成一个类?
//答案是:为了实现跨数据库,面向抽象的编程
public interface UserDao {public void save(User user);
}
package com.lp.dao.impl;import com.lp.dao.UserDao;
import del.User;
//UserDAOImpl负责和不同的数据库打交道,为了实现跨数据库,我们可以多写几个UserDao的实现
//例如mysql的连接就写一个UsermysqlDAO的实现,其它数据库的实现就写其他数据库的实现
public class UserDAOImpl implements UserDao {public void save(User user) {//这里写不同的数据库连接的实现//Hibernate//JDBC//XML//NetWorkSystem.out.println("user saved!");}}

Service层:

package com.lp.service;import com.lp.dao.UserDao;
import del.User;
import com.lp.dao.impl.UserDAOImpl;

public class UserService {//private UserDao userDAO = new UserDAOImpl();private UserDao userDAO;//有了配置文件就不用向上面的那样new了,public UserDao getUserDAO() {return userDAO;}public void setUserDAO(UserDao userDAO) {this.userDAO = userDAO;}//向数据库中添加一个用户,只要通过调用UserDAO,然后通过调用save()方法就能实现public void add(User user){userDAO.save(user);}}

 模拟Spring里面的l在src下面放置要解析的配置文件l,代码:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans><!-- 把 UserDAOImpl读出来放到DAO里面去,也就是new一个Class的对象为u的--><bean id="u" class="com.lp.dao.impl.UserDAOImpl"/><bean id="userService" class="com.lp.service.UserService"><!-- 在userService有一个属性,这个属性就是userDAO,更准确点就是setUserDAO方法,也就是说spring可以把userService下面的userDAO注入进来,装配到一块。--><property name = "userDAO" bean="u"></property></bean>
</beans>

 

跟上面读取配置文件一样。这个类实现了一个接口叫做BeanFactory。叫做bean工厂。

 

package com.lp.spring;
/** 存放各种各样的DAO的工厂*/
public interface BeanFactory {public Object getBean(String name);//每个bean都有一个名字通过id指定
}

 

 

    为了模拟spring怎样读取配置文件还需要读取配置文件的类,这里我们自己创建一个包叫Com.lp.spring这里存放了spring里面的类:这里ClassPathXmlApplicationContext类:ClassPathXmlApplicationContext:使用这个类来读取l的配置文件,实现BeanFactory,实现里面获取bean对象的方法:

 

    package com.lp.spring;import flect.Method;import java.util.*;import org.jdom.*;import org.jdom.input.SAXBuilder;/** ClassPathXmlApplicationContext是模拟spring的类*/public class ClassPathXmlApplicationContext implements BeanFactory {//用Map容器存储bean的名字和值private Map<String , Object> beans = new HashMap<String, Object>();//IOC Inverse of Control DI Dependency Injectionpublic ClassPathXmlApplicationContext() throws Exception {SAXBuilder sb=new SAXBuilder();//解析l文件Document doc=sb.Class().getClassLoader().getResourceAsStream(&#l")); //构造文档对象//获取根元素beansElement root&#RootElement(); List list&#Children("bean");//取名字为bean的所有的小孩存放到List集合当中for(int i=0;i<list.size();i++){Element element=((i);String id&#AttributeValue("id");//取出属性值为id的值String clazz&#AttributeValue("class");//取出属性值为class的值//把class="com.lp.dao.impl.UserDAOImpl"生成一个对象 o Object o = Class.forName(clazz).newInstance();//System.out.println(id);//System.out.println(clazz);beans.put(id, o);//然后把id和对应的对象放到容器里面//用了反射思想for(Element propertyElement : (List<Element>)Children("property")) {String name = AttributeValue("name"); //userDAOString bean = AttributeValue("bean"); //uObject beanObject = (bean);//UserDAOImpl instance
                   String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);//通过这句话构造setUserDAO()方法System.out.println("method name = " + methodName);Method m = o.getClass().getMethod(methodName, Class().getInterfaces()[0]);//setUserDAO(UserDao.class)
                   m.invoke(o, beanObject);}}  }/*** 从容器中把这个对象取出来*/public Object getBean(String id) {(id);}}

 

/*

 * 测试类专门写在另外一个source包里面,然后引入junit.jar文件,然后右键

 * 要测试的类,选择jUnitCase创建测试类

 * 使用bean容器

 */

 

package com.lp.service;
/** 测试类专门写在另外一个source包里面,然后引入junit.jar文件,然后右键* 要测试的类,选择jUnitCase创建测试类*/
import static org.junit.Assert.*;import org.junit.Test;import com.lp.dao.UserDao;
import del.User;
import com.lp.spring.BeanFactory;
import com.lp.spring.ClassPathXmlApplicationContext;public class UserServiceTest {@Testpublic void testAdd() throws Exception {//把容器给new出来BeanFactory factory = new ClassPathXmlApplicationContext();//思考怎样使UserService也不用new?答案就是交给工厂BeanFactory,从配置文件里面读出来//UserService service = new UserService();UserService service = (UserService) Bean("userService");/*UserDao userdao = (UserDao) Bean("u");service.setUserDAO(userdao);//把这个对象注入到service中
*/        User u = new User();service.add(u);}
}

运行结果:

method name = setUserDAO
user saved!

以前要写的代码与在容器中配置的文件对应关系:

<bean id="userService" class="com.lp.service.UserService"><property name = "userDAO" bean="u"></property></bean>

这段代码的意识:userService中调用userDao:

  相当于

    UserService service = new UserService();

 

    service.setUserDAO(userdao);

   这两句代码。

   意思:通过配置文件把userdao和service 这两个对象的关系设定好了,不用硬性的编码,也就是把userDao装配到service里面了。

 

  

IOC/DI原理:IOC(inverse of controll)控制反转:通过上面的例子可以看出,以前Service层中想调用Dao层中的方法,需要在Service层中new出来,是由自己控制的,而现在由Spring容器控制创建初始化bean(对象),维护bean与bean之间的关系,权利从程序中转移到了Spring容器,而程序本身不需要再维护。

DI(dependency injection)依赖注入:实际上和IOC是一个概念,为了更准确的描述Spring的核心技术,对象之间的关系是相互依赖的,一些通用的bean组件可以依赖容器注入进来。原理:也可以说成反射注入,通过使用解析XML技术,以及反射的机制,构造真实实例对象,构造set方法把userDAO这个bean注入到userService中。

好处:耦合性大大的降低,用配置文件注入bean,修改起来方便,不用硬性的修改代码。

 

 

转载于:.html

本文发布于:2024-02-02 02:51:45,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170681557340921.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:配置文件   反射   原理   思想   Spring
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23