以一个简单的用户管理的例子来模拟Spring的依赖注入
首先,要搞清楚在一个项目中为什么要进行分层。
方案一
进行用户管理,这里我们只有一个实体类User, 然后对于User的增删改查放到UserService中完成。
这样会有一个问题,这样的程序写出来没有扩展性。因为UserService中要写入很多连接数据库的逻辑,现在使用的是MySQL数据库,如果项目变动要用Oracle数据库了,这样UserService的代码就要重写,不符合“面向修改关系,面向扩展开放”原则。为了解决这样的问题,我们提出了下边的方案,应用到了AOP面向接口编程的思想
方案二
引入了DAO层进行有关对于数据库的链接与增删改查
这时,service层可以直接调用DAO层的方法来操作数据库,并且可以根据实际项目的需求,进行一些其他的逻辑业务的处理,如加密解密,权限认证等。在UserService中,组合进一个DAO的接口,然后在使用的时候,注入DAO的实例。比如说,现在用的是MySQL的数据库,用的是与MySQL相关的DAO,以后想用Oracle数据库了,就改用Oracle的相关DAO就可以了,反正他们都是继承自同一个DAO接口,而Service中也是根据DAO接口来调用的。相关代码如下
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;
}
}
public interface UserDAO {
public void save(User user);
}
public class UserDAOImpl implements UserDAO {
public void save(User user) {
System.out.println("user saved!");
}
}
public class UserService {
private UserDAO userDAO = new UserDAOImpl();
public void add(User user) {
userDAO.save(user);
}
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
这里又出现的问题是,当想换Oracle数据库的时候,就要重写Service中的代码。当然这可以通过配置文件来实现,即把UserDao的类型写入到xml文件中。但是这样比较麻烦,需要写很多配置文件,然后创建工厂,来解决这些问题。现在,我们就考虑到使用一个容器来自动化解决这些问题,因此出现了Spring.
构建一个容器,来自动化完成实例的装配
public interface BeanFactory {
public Object getBean(String 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 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);
System.out.println(clazz);
beans.put(id, o);
for(Element propertyElement : (List<Element>)element.getChildren("property")) {
String name = propertyElement.getAttributeValue("name"); //userDAO
String bean = propertyElement.getAttributeValue("bean"); //u
Object beanObject = beans.get(bean);//UserDAOImpl instance
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);
}
}
}
这个类的作用是,读取配置文件bean.xml中的信息,查看现在有多少个类需要管理,然后把这些类new出来实例放入到容器中。而且,这段代码还有一个功能,就是查看每一个需要管理的类中,是否有组合使用的bean对象,如果有的话,也把实例化的相关的实例注入到这个类中来
现在,如果想改变使用的数据库,则把相应的DAO写入到配置文件bean.xml中,容器会自动装配到相应的实例中,不需要人工太多的改变。
对于模拟的Spring容器的使用
@Test
public void testAdd() throws Exception {
BeanFactory applicationContext = new ClassPathXmlApplicationContext();
UserService service = (UserService)applicationContext.getBean("userService");
User u = new User();
u.setUsername("zhangsan");
u.setPassword("zhangsan");
service.add(u);
}
配置文件bean.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>