zoukankan      html  css  js  c++  java
  • 模拟实现Spring IoC功能

    为了加深理解Spring 今天自己写了一个模拟的Spring....


    步骤:

    1.利用jdom解析bean.xml(pull,sax也能够,我这里用了jdom)

    2.先解析全部的<bean/>,再解析全部的<property/>.假设边解析<bean/>,边解析<property/>,会导致property的ref找不到相应的bean.

    3.利用反射,依据解析到的类路径,new出一个实例,实现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]

  • 相关阅读:
    Spring Cloud Gateway 数据库存储路由信息的扩展方案
    Spring GateWay 路由源码分析
    SpringCloud实战十四:Gateway之 Spring Cloud Gateway 动态路由进阶
    SpringCloud实战十三:Gateway之 Spring Cloud Gateway 动态路由
    springcloudgateway动态路由
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1074:津津的储蓄计划
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1073:救援
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1073:救援
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1073:救援
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1072:鸡尾酒疗法
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7070115.html
Copyright © 2011-2022 走看看