自己动手写个spring IOC容器
来源:互联网 发布:淘宝阿迪达斯高仿店铺 编辑:程序博客网 时间:2024/06/05 04:58
- 前言
- 自定义IOC容器的基本架构
- 架构图解
- 基本思路
- IOC容器实现图解
- IOC容器实现
- 创建一个java工程
- 导入 dom4jjar 和 jaxenjar
- 创建测试用的类
- 创建ApplicationContextxml
- XmlConfig
- BeanFactory
- 测试
- demo下载
前言
spring的优点和实现原理不在此详述,想要自己动手写一个简单的IOC容器,要求各位对spring有一定的了解或者使用过。
自定义IOC容器的基本架构
架构图解
基本思路
- 解析xml配置文件
- 根据配置的生成相应的对象
- 将对象存入IOC容器
IOC容器实现图解
IOC容器实现
要求:
1. 我们使用dom4j.jar 和 jaxen.jar 来解析xml文件(自行下载,或在文章末尾下载demo)
2. 需要懂得java的反射机制
1. 创建一个java工程
2. 导入 dom4j.jar 和 jaxen.jar
3. 创建测试用的类
package com.myspring.bean;public class User { private String userName; private Address address; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "User [userName=" + userName + ", address=" + address + "]"; }}
package com.myspring.bean;public class Address { private String city; public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Override public String toString() { return "Address [city=" + city + "]"; }}
4. 创建ApplicationContext.xml
将配置文件ApplicationContext.xml放在src下
<?xml version="1.0" encoding="UTF-8"?><beans> <bean id="address" class="com.myspring.bean.Address"> <property name="city" value="fuzhou"></property> </bean> <bean id="user" class="com.myspring.bean.User"> <property name="userName" value="tom"></property> <property name="address" ref="address"></property> </bean></beans>
5. XmlConfig
封装Bean和Property,对应配置文件中的bean节点和property节点
package com.myspring.config;import java.util.ArrayList;import java.util.List;/** * 封装配置文件中的bean节点 * @author 周君 */public class Bean { private String id; private String className; private List<Property> properties = new ArrayList<Property>();//bean节点下可以有多个property节点 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public List<Property> getProperties() { return properties; } public void setProperties(List<Property> properties) { this.properties = properties; } @Override public String toString() { return "Bean [id=" + id + ", className=" + className + ", properties=" + properties + "]"; }}
package com.myspring.config;/** * 封装配置文件中的property节点 * * @author 周君 */public class Property { private String name; //使用value属性直接指定值,也可以使用ref属性来指定依赖的对象 private String value; private String ref; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; }}
用于解析配置文件的类
package com.myspring.config;import java.io.InputStream;import java.util.HashMap;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.io.SAXReader;/** * 读取xml配置文件的类 * @author 周君 */public class XmlConfig { /** * 读取配置文件 * @param path 配置文件路径 * @return */ public static Map<String, Bean> getConfig(String path){ Map<String, Bean> configMap = new HashMap<String, Bean>(); //使用dom4j和xpath读取xml文件 Document doc = null; SAXReader reader = new SAXReader(); InputStream in = XmlConfig.class.getResourceAsStream(path); try { doc = reader.read(in); } catch (DocumentException e) { e.printStackTrace(); throw new RuntimeException("请检查您的xml配置文件路径是否正确!"); } //定义xpath,取出所有的bean String xpath = "//bean"; //对bean进行遍历 List<Element> list = doc.selectNodes(xpath); if(list!=null){ for (Element beanEle : list) { Bean bean = new Bean(); //bean节点的id String id = beanEle.attributeValue("id"); //bean节点的class属性 String className = beanEle.attributeValue("class"); //封装到bean对象中 bean.setId(id); bean.setClassName(className); //获取bean节点下所有的property节点 List<Element> proList = beanEle.elements("property"); if(proList != null){ for (Element proEle : proList) { Property prop = new Property(); String propName = proEle.attributeValue("name"); String propValue = proEle.attributeValue("value"); String propRef = proEle.attributeValue("ref"); //封装到property属性中 prop.setName(propName); prop.setValue(propValue); prop.setRef(propRef); bean.getProperties().add(prop); } } //id是不应重复的 if(configMap.containsKey(id)){ throw new RuntimeException("bean节点ID重复:" + id); } //将bean封装到map中 configMap.put(id, bean); } } return configMap; }}
6. BeanFactory
定义BeanFactory接口
package com.myspring.core;public interface BeanFactory { Object getBean(String beanName);}
实现类,作用是初始化IOC容器,生成对象放入容器中
所谓的容器,在代码中的表现形式其实就是个集合,我们使用HashMap来作为容器
package com.myspring.core;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import com.myspring.config.Bean;import com.myspring.config.Property;import com.myspring.config.XmlConfig;import com.myspring.utils.BeanUtil;public class ClassPathXmlApplicationContext implements BeanFactory{ //定义一个IOC容器 private Map<String, Object> ioc; private Map<String, Bean> config; /** * 构造函数 * 1. 初始化IOC容器 * 2. 加载配置文件,生成bean对象放入IOC容器 * @param path */ public ClassPathXmlApplicationContext(String path){ //初始化IOC容器 ioc = new HashMap<String, Object>(); //读取配置文件 config = XmlConfig.getConfig(path); if(config!=null){ for(Entry<String, Bean> entry : config.entrySet()){ String beanId = entry.getKey(); Bean bean = entry.getValue(); //根据bean生成相应的对象 Object object = createBean(bean); ioc.put(beanId, object); } } } /** * 根据bean生成对象实例 * @param bean * @return */ private Object createBean(Bean bean) { String beanId = bean.getId(); String className = bean.getClassName(); Class c = null; Object object = null; try { //根据bean的calss属性生成对象 c = Class.forName(className); } catch (ClassNotFoundException e) { throw new RuntimeException("您配置的class属性不合法:"+className); } try { //该方法调用的是类的无参构造方法 object = c.newInstance(); } catch (Exception e) { throw new RuntimeException("该类缺少一个无参构造方法:"+className); } //将bean的属性封装到对象中 if(bean.getProperties() != null){ for(Property p : bean.getProperties()){ //情况一:配置文件中使用的是value属性注入 if(p.getValue() != null){ //获取属性对应的getter方法 Method getMethod = BeanUtil.getSetterMethod(object,p.getName()); try { //调用set方法注入 getMethod.invoke(object, p.getValue()); } catch (Exception e) { throw new RuntimeException("属性名称不合法或者没有相应的getter方法:"+p.getName()); } } //情况二:配置文件中使用的是ref属性注入 if(p.getRef() != null){ //获取属性对应的getter方法 Method getMethod = BeanUtil.getSetterMethod(object,p.getName()); //从容器中找到依赖的对象 Object obj = ioc.get(p.getRef()); if(obj == null){ throw new RuntimeException("没有找到依赖的对象:"+p.getRef()); }else{ //调用set方法注入 try { getMethod.invoke(object, obj); } catch (Exception e) { throw new RuntimeException("属性名称不合法或者没有相应的getter方法:"+p.getName()); } } } } } return object; } @Override public Object getBean(String beanName) { return ioc.get(beanName); }}
测试
package com.myspring.test;import java.util.Map;import java.util.Map.Entry;import com.myspring.bean.Address;import com.myspring.bean.User;import com.myspring.config.Bean;import com.myspring.config.XmlConfig;import com.myspring.core.BeanFactory;import com.myspring.core.ClassPathXmlApplicationContext;public class Test { public static void main(String[] args) { testIOC(); //testConfig(); } /** * 测试IOC容器 */ private static void testIOC(){ BeanFactory bf = new ClassPathXmlApplicationContext("/ApplicationContext.xml"); User user = (User) bf.getBean("user"); System.out.println(user); System.out.println("address hashcode:"+user.getAddress().hashCode()); Address address = (Address) bf.getBean("address"); System.out.println(address); System.out.println("address hashcode:"+address.hashCode()); } /** * 测试读取配置文件 */ private static void testConfig(){ Map<String,Bean> map = XmlConfig.getConfig("/ApplicationContext.xml"); for (Entry<String, Bean> entry : map.entrySet()) { System.out.println(entry.getKey()+"==="+entry.getValue()); } }}
demo下载
点击下载
2 0
- 自己动手写个spring IOC容器
- 自己动手写个spring IOC容器
- 自己动手写个spring IOC容器
- 自己动手写ASP.NET的IOC容器!
- 自己动手开发IOC容器
- 自己动手实现spring ioc
- spring - 自己动手写spring
- 自己动手实现Spring IoC框架
- 自己动手模拟spring的IOC
- spring 之 自己动手实现IOC
- 自己写一个简单的Spring IOC容器
- 自己动手编写IoC容器(一)
- Spring反转容器IOC
- spring的Ioc容器
- Spring-- IOC容器详解
- Spring IOC 容器说明
- Spring IoC容器小结
- Spring--IoC容器
- 为什么Java接口里使用public static final修饰成员变量
- yum 查询软件信息
- 省份城市联动 多选
- Gulp 简易入门及API介绍
- IIS7 / IIS7.5 URL 重写 HTTP 重定向到 HTTPS
- 自己动手写个spring IOC容器
- android设置横竖屏切换时生命周期不会改变
- 第二章 adb 重启
- sql server 判断时间段是否重叠
- 移动非系统表空间文件到ASM中和从ASM中移回来 (使用rman)
- 一些shader的基本规则
- 数据结构 约瑟夫环问题C++
- ANDROID开发之SQLite详解
- 安装rac的7个注意