本文可作为北京尚学堂 spring课程的学习笔记

我们还是用上一篇文章的例子 给数据库中增加一个user

整体代码如下

package com.bjsxt.test;  

import com.bjsxt.dao.UserDaoMysql;
import com.bjsxt.model.User;
import com.bjsxt.services.UserService;


public class Test {
public static void main(String[] args) {
User user=new User();
UserService userService=new UserService();
UserDao dao=new UserDaoMysql();
userService.setUserDao(dao);
userService.Save(user);
}
}


上一个的test中 还是需要我写出

UserDao dao=new UserDaoMysql();

如果我想从xml中读出数据 以后可以不再改硬代码 如何?

首先写出xml文件

<?xml version="1.0" encoding="UTF-8"?> 
<beans>

<bean id="u" class="com.bjsxt.dao.UserDaoMysql" />

</beans>


如果是oracle 也只用xml文件即可

现在我们需要做的就是读取xml  "自动"生成userdao 关于用jdom操作xml的只是 请看文章末尾的参考资料

我们现在要生产一个对象 那就是工厂模式嘛

package com.bjsxt.spring;

public interface BeanFactory {
public Object getBean(String id);
}

再来一个操作xml的类

package com.bjsxt.spring;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;


public class ClassPathXmlApplicationContext implements BeanFactory {

Map<String, Object> map=new HashMap<String, Object>();

@SuppressWarnings("unchecked")
public ClassPathXmlApplicationContext() throws JDOMException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(ClassPathXmlApplicationContext.class
.getClassLoader().getResourceAsStream("spring.xml")); // 构造文档对象
// Document doc=sb.build("d://test.xml"); //构造文档对象可以有两种方式 如果是在把xml文档放在
//eclipse的根目录下 就有上面的方法
Element root = doc.getRootElement(); // 获取根元素

List<Element> list = root.getChildren("bean");// 取名字为bean的所有元素
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);
String name = element.getAttributeValue("id");
String classPath = element.getAttributeValue("class");//取bean的元素class的内容

Object object=Class.forName(classPath).newInstance();
map.put(name,object);

System.out.println("bean:");
System.out.println("bean name: " + name);
System.out.println("bean class: " + classPath);

System.out.println("———————————–");
}
}

@Override
public Object getBean(String id) {
return map.get(id);
}

}

测试test如下

package com.bjsxt.test;

import java.io.IOException;

import org.jdom.JDOMException;

import com.bjsxt.dao.UserDao;
import com.bjsxt.dao.UserDaoMysql;
import com.bjsxt.model.User;
import com.bjsxt.services.UserService;
import com.bjsxt.spring.ClassPathXmlApplicationContext;

public class Test {
public static void main(String[] args) throws JDOMException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
User user=new User();
UserService userService=new UserService();
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext();
Object object=context.getBean("u");
userService.setUserDao((UserDao) object);
userService.Save(user);
}
}

现在看看 上面的代码 我们还是有

userService.setUserDao((UserDao) object);

能不能吧userservice也从xml中读取 同时 它内部的属性也从xml中来

可以 那么xml首先得变成如下的样子

<?xml version="1.0" encoding="UTF-8"?> 
<beans>

<bean id="u" class="com.bjsxt.dao.UserDaoMysql" />

<bean id="userService" class="com.bjsxt.services.UserService" >
<property name="userDao" bean="u" />
</bean>

</beans>

test测试函数应该是这样的

package com.bjsxt.test;

import com.bjsxt.model.User;
import com.bjsxt.services.UserService;
import com.bjsxt.spring.ClassPathXmlApplicationContext;


public class Test {
public static void main(String[] args) throws Exception {
User user=new User();

ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext();
UserService userService=(UserService) context.getBean("userService");
userService.Save(user);
}
}

关键问题就是 ClassPathXmlApplicationContext内部怎么写

其实大家可以这样想 我在读取每一个bean的时候就看看它底下有没有参数 有的话就用反射技术 自动将属性装填进去

package com.bjsxt.spring;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;

import org.jdom.input.SAXBuilder;

public class ClassPathXmlApplicationContext implements BeanFactory {

Map<String, Object> map = new HashMap<String, Object>();

@SuppressWarnings("unchecked")
public ClassPathXmlApplicationContext() throws Exception {
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(ClassPathXmlApplicationContext.class
.getClassLoader().getResourceAsStream("spring.xml")); // 构造文档对象
// Document doc=sb.build("d://test.xml");
Element root = doc.getRootElement(); // 获取根元素

List<Element> list = root.getChildren("bean");// 取名字为disk的所有元素
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);
String name = element.getAttributeValue("id");
String classPath = element.getAttributeValue("class");// 取disk子元素capacity的内容

Object object = Class.forName(classPath).newInstance();
map.put(name, object);

for (Element propertyElement : (List<Element>) element
.getChildren("property")) {
String parameter = propertyElement.getAttributeValue("name"); // 获得userDao这个属性名称
String bean = propertyElement.getAttributeValue("bean"); //就是xml里面的那个u
Object obj = map.get(bean); //找到map里面的那个u
//大家再试试把xml里面的两个bean的顺序调换一下 看有什么问题
// 如何修改?
String methodName = "set" //获得setUserDao这个方法名
+ parameter.substring(0, 1).toUpperCase()
+ parameter.substring(1);
System.out.println(methodName);
Method m = object.getClass().getMethod(methodName,
obj.getClass().getInterfaces()[0]);
// 查看getMethod的参数 String name, Class<?>... parameterTypes
// 我们知道方法的名字是setUserDao 可问题是一个类中 可能出现重载情况 也就是方法名一样的情况
// 所以后面的参数的意思就是 setUserDao的参数就是上面那个obj所实现的第一个接口

m.invoke(object, obj);

}
}
}

@Override
public Object getBean(String id) {
return map.get(id);
}

}


ok 搞定 里面最麻烦的东西 我认为还是反射

这些代码 我认为初学者还是自己敲一遍比较好


参考资料

​http://www.blogjava.net/fjq639/archive/2005/12/20/24806.html​