模拟spring原理的实现
Spring 表示是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。(以上来自百度百科)
下面就先来自己实现一个spring的小例子:
首先有一个实体类User位于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;
}
}
然后是一个UserDAO接口位于dao包下
public interface UserDAO {
public void save(User u);
}
接着是实现了UserDAO接口的UserDAOImpl类位于dao包下的impl包中
public class UserDAOImpl implements UserDAO{
public void save(User u){
System.out.println("a user saved!");
}
}
还有一个UserService类来对User进行增删改查位于service包中
public class UserService {
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void add(User u){
userDAO.save(u);
}
}
UserService对外公开的只是它的业务逻辑,而UserDAO负责和DB打交道,就可以写多个实现了UserDAO接口的类了如UserDAOImpl,这就是面向抽象编程(面向接口),它是程序有更多的灵活性。但是如果有很多个Service如TeacherService,ScoreService等等,就可以用一个大的总的工厂来产生所有这些DAO如UserDAO,用XML文件来对这些进行配置,用JDOM来读取XML文件
XML文件:
<beans>
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl" />
<bean id="userService" class="com.bjsxt.service.UserService" >
<property name="userDAO" bean="u"/>
</bean>
</beans>
Property指的是set方法,在UserService中有个方法叫setUserDAO,当它初试化的时候应该把id="u"所对应的class对象传进来,这样就把userService中的UserDAO和UserDAOImpl装配到一起了,这就叫注入。
现在来模拟Spring原理,spring中有一个类ClassPathXmlApplicationContext的作用是把读取的XML中的信息存入到一个容器,将来要用就直接从中拿,它实现了一个BeanFactory接口,以上完全是为了模拟spring,但是这些类和接口在spring中确实存在,而且名字相同。
类ClassPathXmlApplicationContext的实现如下:
import java.lang.reflect.Method;
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;
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beans = new HashMap<String, Object>();
public Object getBean(String id) {
return this.beans.get(id);
}
public ClassPathXmlApplicationContext() throws Exception{
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml")); // 构造文档对象
Element root = doc.getRootElement(); // 获取根元素HD
List<Element> list = root.getChildren("bean");// 取名字为disk的所有元素
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);
String id = element.getAttributeValue("id");
String clazz = element.getAttributeValue("class");
Object o = Class.forName(clazz).newInstance();
System.out.println(id+":"+clazz);
beans.put(id, o);
for(Element propertyElement:(List<Element>)element.getChildren("property")){
String name = propertyElement.getAttributeValue("name");
String bean = propertyElement.getAttributeValue("bean");
Object beanObject = beans.get(bean);
String methodName = "set" + name.substring(0,1).toUpperCase()+ name.substring(1);
System.out.println("method name= "+methodName);
Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
m.invoke(o, beanObject);
}
}
}
}
上面用到了反射机制
类BeanFactory的实现如下:
publicinterface BeanFactory {
public Object getBean(String id);
}
下面来用Junit进行测试,关于Junit的知识将作为一个专题在后面讲解。
import java.io.IOException;
import org.jdom2.JDOMException;
import org.junit.Test;
import com.bjsxt.dao.UserDAO;
import com.bjsxt.model.User;
import com.bjsxt.spring.BeanFactory;
import com.bjsxt.spring.ClassPathXmlApplicationContext;
publicclass UserServiceTest {
@Test
publicvoid testAdd() throws Exception{
BeanFactory factory = new ClassPathXmlApplicationContext();
UserService service = (UserService)factory.getBean("userService");
// UserDAO userDAO = (UserDAO)factory.getBean("u");
// service.setUserDAO(userDAO);
User u = new User();
service.add(u);
}
}
分层模型:
Test通过add(User)方法来调用UserService对象,通过UserService来调用UserDAO,UserDAO可以调用User对象又可以把数据导入DB,通过UserDAO可以提供对数据库的屏蔽,只是提供UserService接口