学习Spring
在学习Spring 的时候,我们先不直接去学,我们先来模拟一下Spring的一些功能,然后再去学,这样就比好容易理解
1.建立一个项目。。。名字叫springTest_IOC(这样取名的目的是为了直接明了,看见标题就知道这个是干什么的)
2.创建了一个项目,第一步不是去考虑用什么设计模式或者其他,首先肯定要用一个实体,我们先来建立一个用户实体
package com.bjsxt.model;
public class User { private String userName ; private String password ; public String getUserName() { return userName ; } public void setUserName(String userName) { this . userName = userName; } public String getPassword() { return password ; } public void setPassword(String password) { this . password = password; } }
3.我们应该分层 一般有这几层:model(实体层),service(服务层,控制层),dao(数据库管理层,数据交换层),一般又把service分为service(应用接口层)和serviceImpl(应用实现层),dao也同样dao和daoImpl 源码: package com.test.dao;
import com.test.model.User; public interface UserDAO { public void save(User u);
}
package com.test.dao.Impl; import com.test.dao.UserDAO; import com.test.model.User; public class UserDAOImpl implements UserDAO{
@Override public void save(User u) { System. out .println( "save user" ); }
}
package com.test.service;
import com.test.dao.UserDAO; import com.test.dao.Impl.UserDAOImpl; import com.test.model.User;
public class UserService { private UserDAO userDAO = new UserDAOImpl(); public UserDAO getUserDA0() { return userDA0 ; } public void setUserDAO(UserDAO userDAO) { this . userDAO = userDAO; }
public void addUser(User user ){ userDAO .save(user); };
}
4.spring 读取文件时通过*.xml格式的文件来读取的 我们首先来看先怎样读取文件 xml文件
<? xml version = "1.0" encoding = "UTF-8" ?> < result > < value > < no > A1234 </ no > < addr > 成都 </ addr > </ value > < value > < no > B1234 </ no > < addr > 上海 </ addr > </ value > </ result >
我们可以通过四种方法来读取xml文件
这里的xml文件需要注意的是:如果你发现你复制一段xml文件到xml里面去,却没有变色,则说明这段xml文件有误
我这里先介绍一种JDOM JDOM的目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型,JDOM一直得到大力推广和促进。正在考虑通过“Java规范请求JSR-102”将它最终用作“Java标准扩展”。从2000年初就已经开始了JDOM开发。
JDOM与DOM主要有两方面不同。首先,JDOM仅使用具体类而不使用接口。这在某些方面简化了API,但是也限制了灵活性。第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。
JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题”(根据学习曲线假定为20%)。JDOM对于大多数Java/XML应用程序来说当然是有用的,并且大多数开发者发现API比DOM容易理解得多。JDOM还包括对程序行为的相当广泛检查以防止用户做任何在XML中无意义的事。然而,它仍需要您充分理解XML以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习DOM或JDOM接口都更有意义的工作。
JDOM自身不包含解析器。它通常使用SAX2解析器来解析和验证输入XML文档(尽管它还可以将以前构造的DOM表示作为输入)。它包含一些转换器以将JDOM表示输出成SAX2事件流、DOM模型或XML文本文档。JDOM是在Apache许可证变体下发布的开放源码。
代码:
import java.util.List;
import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder;
public class MyXMLReader { public static void main(String[] args) throws Exception { long lasting=System. currentTimeMillis(); SAXBuilder builder= new SAXBuilder(); Document doc=builder.build(MyXMLReader. class .getClassLoader().getResourceAsStream( "text.xml" )); //读取文件 Element foo=doc.getRootElement(); //获取根元素 System. out .println(foo); List allChildren=foo.getChildren(); //获取所有的子元素 for ( int i=0;i<allChildren.size();i++){ System. out .println( "号码" +((Element)allChildren.get(i)).getChild( "no" ).getText()); System. out .println( "地址" +((Element)allChildren.get(i)).getChild( "addr" ).getText()); } } }
结果: [Element: <result/>] 号码A1234 地址成都 号码B1234 地址上海
5.加测试,怎么样加喃? 第一,选择你要测试的类,右键-->New-->Juint test-->选择Junit 4--->finish---最好建立一个包叫测试包,然后把测试方法统一的放到里面去。
源码: package com.test.test;
import static org.junit.Assert.*;
import org.junit.Test;
public class UserServiceTest {
@Test public void testAddUser() { fail( "Not yet implemented" ); }
} 6.写自己的测试方法(修改上面的测试方法) public class UserServiceTest {
@Test public void testAddUser() { UserService service= new UserService(); User user= new User(); service.addUser(user); }
} 结果: save user
7.下面我们来模仿spring的xml配置
我们来建立一个beans.xml文件
源码: < beans > <!-- class 是全路径,包名加类名 --> < bean id = "u" class = "com.test.dao.impl.UserDAOImpl" > </ bean > <!-- <bean id="userService" class="com.test.service.UserService"> <property name="userDAO" bean="u"/> </bean> --> </ beans >
8.我们来建立一个spring的类,主要是为了模拟spring。在用这个类来实现一个beanFactory(bean工厂)接口。
我们在做这一步的时候也要修改UseeService的源码:
修改:
public class UserService { //private UserDAO userDao=new UserDAOImpl();原来是这样的 private UserDAO userDao ; //现在是这样,通过配置文件来实例化 public UserDAO getUserDao() { return userDao ; } public void setUserDao(UserDAO userDao) { this . userDao = userDao; }
public void addUser(User user ){ userDao .save(user); };
}
源码:
package com.test.spring;
import java.util.HashMap; import java.util.List; import java.util.Map;
import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder;
import com.test.util.MyXMLReader;
public class ClassPathXmlApplicationContext implements BeanFactory{ private Map<String, Object> beans = new HashMap<String,Object>(); //容器,用户来装bean public ClassPathXmlApplicationContext() throws Exception{ SAXBuilder builder= new SAXBuilder(); Document doc=builder.build(MyXMLReader. class .getClassLoader().getResourceAsStream( "beans.xml" )); //读取文件 Element root=doc.getRootElement(); //获取根元素 System. out .println(root); List allChildren=root.getChildren(); //获取所有的子元素 for ( int i=0;i<allChildren.size();i++){ Element element=(Element)allChildren.get(i); //获取一个子元素 String id=element.getAttributeValue( "id" ); //子元素的属性id String clazz=element.getAttributeValue( "class" ); System. out .println(id+ ":" +clazz); Object o=Class.forName(clazz).newInstance(); //通过反射来产生一个实体 beans .put(id, o); //放入bean中 } }
@Override public Object getBean(String name) {//从beans中获取一个元素 return beans .get(name); }
}
public class UserServiceTest {
@Test public void testAddUser() throws Exception{ // UserService service=new UserService();原来的做法 // User user=new User(); // service.addUser(user); BeanFactory beans= new ClassPathXmlApplicationContext(); //实例化bean工厂 UserService service= new UserService(); UserDAO userDAO=(UserDAO)beans.getBean( "u" ); //通过工厂是实例化 service.setUserDao(userDAO); User user= new User(); service.addUser(user); }
}
运行:
结果: [Element: <beans/>] u:com.test.dao.impl.UserDAOImpl save user
9.上面体现了一点SPring的好处,但是它的最好的还没体现,就是自动装配,上面的beans源码不是下面的一段被注释了嘛
< beans > <!-- class 是全路径,包名加类名 --> < bean id = "u" class = "com.test.dao.impl.UserDAOImpl" > </ bean > <!-- <bean id="userService" class="com.test.service.UserService"> <property name="userDAO" bean="u"/> </bean> --> </ beans >
红色的一段就是自动装配
修改代码: //这个类取这样的名字都是为了模仿spring,因为spring里面也有这样的类
public class ClassPathXmlApplicationContext implements BeanFactory{ private Map<String, Object> beans = new HashMap<String,Object>(); //容器,用户来装bean public ClassPathXmlApplicationContext() throws Exception{ SAXBuilder builder= new SAXBuilder(); Document doc=builder.build(MyXMLReader. class .getClassLoader().getResourceAsStream( "beans.xml" )); //读取文件 Element root=doc.getRootElement(); //获取根元素 System. out .println(root); List allChildren=root.getChildren(); //获取所有的子元素 for ( int i=0;i<allChildren.size();i++){ Element element=(Element)allChildren.get(i); //获取一个子元素 String id=element.getAttributeValue( "id" ); //子元素的属性id String clazz=element.getAttributeValue( "class" ); System. out .println(id+ ":" +clazz); Object o=Class.forName(clazz).newInstance(); //通过反射来产生一个实体 beans .put(id, o); //放入bean中 //下面是才增加的方法 for(Element propertyElement:(List<Element>)element.getChildren("property" )){ String name=propertyElement.getAttributeValue("name" );//取出name属性userDAO String bean=propertyElement.getAttributeValue("bean" );//u Object beanObject= beans.get(bean); //取出K为bean的值 String methodName="set" +name.substring(0, 1).toUpperCase()+name.substring(1);//拼凑set方法名字 Method m=o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);//取出方法,传递参数(setUserDAO(UserDAOImpl实现了一个借口)就变成了setUserDAO(UserDAO)) m.invoke(o, beanObject); } } }
@Override public Object getBean(String name) { return beans .get(name); }
}
public class UserServiceTest {
@Test public void testAddUser() throws Exception{ // UserService service=new UserService(); // User user=new User(); // service.addUser(user); BeanFactory beans= new ClassPathXmlApplicationContext(); //实例化bean工厂 // UserService service=new UserService(); // UserDAO userDAO=(UserDAO)beans.getBean("u");//通过工厂是实例化 // // service.setUserDao(userDAO); UserService service=(UserService)beans.getBean( "userService" );//现在直接工厂来实例化 User user= new User(); service.addUser(user); }
} 运行: 结果: [Element: <beans/>] u:com.test.dao.impl.UserDAOImpl userService:com.test.service.UserService save user
上面就是模拟spring的IOC的注入功能
这里解释一下什么叫IOC(DI)
IOC:控制反转 例如:原来我们创建一个叫userDAO的实例是这样创建的
UserDAO userDAO=new UserDAO();
但是现在我们不用这样创建,我们只需要配置一下文件,让spring 来帮我们创建,本来是我们 控制 创建,但是现在是spring 来控制创建,我们把控制权交给了spring 所以叫控制反转
DI:依赖注入
比如:userService里面的userDAO是依赖容器帮我注入进来的。
这样做的好处:解耦和,就是修改代码很容易,只需要修改一下配置文件就OK了(也就是书上说的更加灵活)