/*
* 想分层,把不同的层次作用以及之间的关系给别人说一遍。
* 例如要想在数据库添加一个用户,一开始最土的方法是直接在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 rootRootElement(); //取名字为disk的所有元素List listChildren("disk");//通过集合遍历所有元素,一个disk其实就是一个元素for(int i=0;i<list.size();i++){Element element = (Element) (i);String name = AttributeValue("name");//获取属性为name的值String capacityChildText("capacity");//取disk子元素capacity的内容String directoriesChildText("directories");String filesChildText("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 rootRootElement(); List listChildren("bean");//取名字为bean的所有的小孩存放到List集合当中for(int i=0;i<list.size();i++){Element element=((i);String idAttributeValue("id");//取出属性值为id的值String clazzAttributeValue("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小时内删除。
留言与评论(共有 0 条评论) |