spring-5-spring源码(模拟自动注入)
简单模拟spring中xml方式注入
1、定义接口
package com.service; public interface Service { public void queryDao(); } package com.dao; public interface Dao { public void query(); }
2、实现类
package com.service; import com.dao.Dao; public class ServiceImpl implements Service { Dao dao ; Dao getDao() { return dao; } public void setDao(Dao dao) { this.dao = dao; } public void queryDao() { System.out.println("开始调用Dao!"); dao.query(); } } package com.dao; public class DaoImpl implements Dao { @Override public void query(){ System.out.println("操作数据库!"); } }
3、工厂类
package com.util; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.File; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class BeanFactory { public Map map = new HashMap<String,Object>(); public BeanFactory(String xml) { parseXml(xml); } public void parseXml(String xml){ try { File file = new File(this.getClass().getResource("/").getPath()+"//"+xml); SAXReader reader = new SAXReader(); Document document = reader.read(file); Element root = document.getRootElement(); for (Iterator<Element> it1 = root.elementIterator(); it1.hasNext();) { Element element = it1.next(); Attribute elementAttrId = element.attribute("id"); String elementId = elementAttrId.getValue(); Attribute elementAttrClass = element.attribute("class"); String elementClass = elementAttrClass.getValue(); //实例化对象 Class clazz = Class.forName(elementClass); Object beanObject = clazz.newInstance(); map.put(elementId,beanObject); for (Iterator<Element> it2 = element.elementIterator(); it2.hasNext();) { Element element2 = it2.next(); if("property".equals(element2.getName())){ String attributeName = element2.attribute("name").getValue(); String attributeRef = element2.attribute("ref").getValue(); //获取目标对象中的所有属性,[规则:属性的名字一定和property中的那么保持一致] Field field = beanObject.getClass().getDeclaredField(attributeName); //说明依赖已经存在map中,需要将依赖注入到目标中的属性中 Object injectInObject = map.get(attributeRef); if(map.get(attributeRef)==null){ System.out.println("依赖还没有注入,请检查以来是否在"+clazz.getName()+"对象之前已经注入!"); }
//使用反射set方法必须传的值,否则会报IllegalAccessException:"BeanFactory不能访问com.service类的成员。ServiceImpl与修饰符" field.setAccessible(true); field.set(beanObject,injectInObject); } } } } catch (Exception e) { e.printStackTrace(); } } public Object getBean(String beanName){ if(map == null || map.get(beanName)==null){ return null; } return map.get(beanName); } }
4、测试类
public static void main(String args[]){ BeanFactory beanFactory = new BeanFactory("spring.xml"); System.out.println(beanFactory.map); Service service = (ServiceImpl)beanFactory.getBean("service"); service.queryDao(); }
使用构造方式依赖注入
package com.util; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class BeanFactory { public Map map = new HashMap<String,Object>(); public BeanFactory(String xml) { parseXml(xml); } public void parseXml(String xml){ try { File file = new File(this.getClass().getResource("/").getPath()+"//"+xml); SAXReader reader = new SAXReader(); Document document = reader.read(file); Element root = document.getRootElement(); for (Iterator<Element> it1 = root.elementIterator(); it1.hasNext();) { Element element = it1.next(); Attribute elementAttrId = element.attribute("id"); String elementId = elementAttrId.getValue(); Attribute elementAttrClass = element.attribute("class"); String elementClass = elementAttrClass.getValue(); //实例化对象 Class clazz = Class.forName(elementClass); Object beanObject = clazz.newInstance(); for (Iterator<Element> it2 = element.elementIterator(); it2.hasNext();) { Element element2 = it2.next(); //实例化对象,如果子标签是property则默认使用setter方法,并且默认构造 String attributeName = element2.attribute("name").getValue(); String attributeRef = element2.attribute("ref").getValue(); Object injectInObject = null; if("property".equals(element2.getName())){ injectInObject = map.get(attributeRef); //说明依赖不存在map中,需要将依赖注入到目标中的属性中 if(injectInObject==null){ System.out.println("依赖对象还没有注册到容器!"); } //获取目标对象中的所有属性,[规则:属性的名字一定和property中的那么保持一致] Field field = beanObject.getClass().getDeclaredField(attributeName); field.setAccessible(true); field.set(beanObject,injectInObject); //当然构造方法中可以有多个参数,这里只默认为一个注入对象 }else if("constructor-arg".equals(element2.getName())){ injectInObject = map.get(attributeRef); if(injectInObject==null){ System.out.println("依赖对象还没有注册到容器!"); } Constructor constructor= clazz.getConstructor(injectInObject.getClass().getInterfaces()[0]); beanObject = constructor.newInstance(injectInObject); }else{ System.out.println("解析中出现特殊子标签,请继续编写!"); } } if(beanObject==null){ beanObject = clazz.newInstance(); } map.put(elementId,beanObject); } } catch (Exception e) { e.printStackTrace(); } } public Object getBean(String beanName){ if(map == null || map.get(beanName)==null){ return null; } return map.get(beanName); } }
模拟自动装配方式,并且属性方式>自动装配,自定义异常
1、自动装配
byType方式:如果xml中beans标签中包含自动装配属性并且value=byType,我们要循环目标对象的属性,并且使用属性查找map(已注入的对象)是否一致(这里判断的是接口名字),如果一致使用set方式注入,如果map中出现两个则需要抛出自定义异常(再容器中找到两个一样的注入对象)