本文共 5686 字,大约阅读时间需要 18 分钟。
看传智播客spring原理讲解的视频整理而来,当时是2011年,时隔8年,在网上找到了一些代码,然后自己整理了一下,基本能够拼装出来。spring容器ioc的实现,无非就是通过反射获取bean实例,然后实例化,当bean实例属性中包含其他bean,那么也是根据反射来注入实例。基本思路就是解析xml文件,然后通过反射机制找到bean,实例化,最后根据属性ref来注入依赖。
这里无需引入spring相关的jar包,但是我们需要引入一个spring的配置文件。配置文件的内容如下:
在自定义MyClassPathXMLApplication之前,我们需要把xml配置文件中的UserDaoImpl.java和UserService.java类文件给出来。
UserDao.java
package com.xxx.spring.dao;public interface UserDao { public void say(String name);}
UserDaoImpl.java
package com.xxx.spring.dao;public class UserDaoImpl implements UserDao { @Override public void say(String name) { System.out.println("Hello,"+name); }}
UserService.java
package com.xxx.spring.service;import com.xxx.spring.dao.UserDao;public class UserService { private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void say(String name){ userDao.say(name); }}
为了解析xml和装配bean实例,我们自定义两个实体。
BeanDefinition.java 这里对应xml配置文件中的实体bean配置:
<bean id="xxx" class="com.xxx.dao.XXX"><property name="yyy" ref="zzz"/></bean>
package com.xxx.spring;import java.util.ArrayList;import java.util.List;public class BeanDefinition { private String id; private String className; private Listproperties = new ArrayList (); public BeanDefinition(String id, String className) { this.id = id; this.className = className; } 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 getProperties() { return properties; } public void setProperties(List properties) { this.properties = properties; } }
PropertyDefinition.java 这里对应xml配置文件中的属性配置:<property name="yyy" ref="zzz"/>
package com.xxx.spring;public class PropertyDefinition { private String name; private String ref; public PropertyDefinition(String name,String ref){ this.name = name; this.ref = ref; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRef() { return ref; } public void setRef(String ref) { this.ref = ref; } }
接下来就是最重要的自定义解析类:MyClassPathXMLApplication.java
package com.xxx.spring;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.XPath;import org.dom4j.io.SAXReader;import com.xxx.spring.service.UserService;public class MyClassPathXMLApplication { //存放自定义BeanDefinition实例 private Listbeans = new ArrayList (); //存放通过反射构建的bean实例 private Map singletons = new HashMap (); public MyClassPathXMLApplication(String fileName){ this.readXML(fileName); this.instanceBeans(); this.injectObject(); } /** * 解析xml文件 * @param fileName */ @SuppressWarnings("unchecked") public void readXML(String fileName){ SAXReader reader = new SAXReader(); Document document = null; try { URL xmlpath = this.getClass().getClassLoader().getResource(fileName); document = reader.read(xmlpath); Map nsMap = new HashMap (); nsMap.put("ns", "http://www.springframework.org/schema/beans"); XPath xpath = document.createXPath("//ns:beans/ns:bean"); xpath.setNamespaceURIs(nsMap); List beanDefines = xpath.selectNodes(document); for(Element ele:beanDefines){ String id = ele.attributeValue("id"); String className = ele.attributeValue("class"); BeanDefinition beanDefinition = new BeanDefinition(id, className); XPath propPath = document.createXPath("ns:property"); propPath.setNamespaceURIs(nsMap); List props = propPath.selectNodes(ele); for(Element prop:props){ String name = prop.attributeValue("name"); String ref = prop.attributeValue("ref"); PropertyDefinition propertyDefinition = new PropertyDefinition(name, ref); beanDefinition.getProperties().add(propertyDefinition); } System.out.println(id+"==>"+className); beans.add(beanDefinition); } } catch (Exception e) { } } /** * 实例化bean对象 */ public void instanceBeans(){ for(BeanDefinition bean:beans){ try { if(bean.getClassName() != null && !"".equals(bean.getClassName().trim())){ singletons.put(bean.getId(), Class.forName(bean.getClassName()).newInstance()); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } /** * 为对象属性注入值 */ public void injectObject(){ //bean userDao //bean userService for(BeanDefinition bean:beans){ //com.xxx.spring.dao.UserDao //com.xxx.spring.service.UserService Object object = singletons.get(bean.getId()); if(object != null){ try{ PropertyDescriptor[] pds = Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors(); for(PropertyDefinition propertyDefinition:bean.getProperties()){ for(PropertyDescriptor pd:pds){ if(propertyDefinition.getName().equals(pd.getName())){ Method setter = pd.getWriteMethod(); if(setter != null){ Object value = singletons.get(propertyDefinition.getRef()); setter.setAccessible(true); setter.invoke(object, value);//userService.setUserDao(userDao); } break; } } } }catch(Exception e){ e.printStackTrace(); } } } } public Object getBean(String beanName){ return singletons.get(beanName); } public static void main(String[] args) { MyClassPathXMLApplication application = new MyClassPathXMLApplication("spring.xml"); UserService service = (UserService)application.getBean("userService"); service.say("spring."); }}
这个类承担了ioc功能的主要职责,负责解析xml文件,实例化bean实体,根据属性名注入依赖。
这里运行的结果如下所示:
转载地址:http://wuey.baihongyu.com/