为了加深理解Spring 今天自己写了一个模拟的Spring....
步骤:
1.利用jdom解析bean.xml
2.创建ClassPathXmlApplicaitonContext用于模拟IoC
3.先解析所有的<bean/>,再解析所有的<property/>.如果边解析<bean/>,边解析<property/>,会导致property的ref找不到对应的bean.
4.利用简单的反射实现Ioc.
目录结构:
这里只给出核心代码,其余的bean,dao,service,并不重要,就不给出了.有兴趣的同志可以点击~这里下载源码.~
ClassPathXmlApplicationContext:
package glut.spring; import java.io.InputStream; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; public class ClassPathXMLApplicationContext { /** * 用于存放<bean/> */ private Map<String, Object> beans = new HashMap<>(); /** * 用于存放<property/> */ private Map<String, List<Element>> properties = new HashMap<>(); /** * 将xml文件转为输入流,作为参数传入. * @param is * @throws Exception */ public ClassPathXMLApplicationContext(InputStream is) throws Exception { // TODO Auto-generated constructor stub autoWired(is); } /** * 模拟DI * @param is * @throws Exception */ private void autoWired(InputStream is) throws Exception { SAXBuilder sb = new SAXBuilder(); Document doc = sb.build(is); Element rootElement = doc.getRootElement(); List<Element> elementOfBeans = rootElement.getChildren("bean"); //遍历xml中所有的<bean/> for (Element e : elementOfBeans) { String beanId = e.getAttributeValue("id"); String beanClz = e.getAttributeValue("class"); Object beanInstance = Class.forName(beanClz).newInstance(); //将beanId和bean的实例存入map beans.put(beanId, beanInstance); //把所有的property先存着,等bean初始化完毕再初始化property,否则可能会导致某些property无法初始化 properties.put(beanId, e.getChildren("property")); } //Dependency Injection Simulation for (Entry<String, List<Element>> entry : properties.entrySet()) { for (Element e : entry.getValue()) { String propertyName = e.getAttributeValue("name"); String propertyRef = e.getAttributeValue("ref"); //通过set方法注入 String methodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); //通过beanId获得对应的bean Object beanInstance = beans.get(entry.getKey()); //通过ref的值去寻找对应的bean,如果没有对应的bean,在下面用到getClass的时候会抛出异常. Object refBeanInstance = beans.get(propertyRef); Method setterMethod = beanInstance.getClass().getMethod( methodName,//呵呵,功能有点简陋,默认只支持refBean实现的第一个接口. refBeanInstance.getClass().getInterfaces()[0]); //调用对应的setter方法,将ref的bean注入到指定的bean中. setterMethod.invoke(beanInstance, refBeanInstance); } } } /** * 根据beanName获得bean */ public Object getBean(String beanName) { // TODO Auto-generated method stub return beans.get(beanName); } }
测试代码:
package glut.test; import glut.bean.User; import glut.service.UserService; import glut.spring.ClassPathXMLApplicationContext; import org.junit.Test; public class SpringTest { @Test public void test() throws Exception { ClassPathXMLApplicationContext ctx = new ClassPathXMLApplicationContext( this.getClass().getClassLoader() .getResourceAsStream("beans.xml")); UserService userService = (UserService) ctx.getBean("userService"); User user = new User("user", "123"); userService.add(user); } }
打印的结果为User的toString:
User [uid=user, pwd=123]
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-25 18:23:44