为了看懂spring底层代码结构,模拟完成了一个依赖注入的小例子,仅供自己更好的理解springIoc。
1、创建一个dao接口和对应的两个实现类。
public interface UserService { public void find(); } public class UserDaoImpl implements UserDao { @Override public void query() { System.out.println("user"); } } public class UserDaoImpl1 implements UserDao { @Override public void query() { System.out.println("user1"); } }2、创建一个service接口和一个实现类,调用dao接口。
public class UserServiceImpl implements UserService { UserDao dao; TestDao test; /*public UserServiceImpl(UserDao dao){//构造方法注入时使用 this.dao = dao; } */ @Override public void find() { System.out.println("service"); dao.query(); test.query(); } /*public void setDao(UserDao dao) {//setter方法注入时使用 this.dao = dao; }*/ }3、创建一个xml配置文件,提供需要维护的对象和对象之间的依赖关系。
<?xml version="1.0" encoding="UTF-8"?> <beans default-autowire="byType"><!-- 自动装配时使用 --> <!--<bean id="dao" class="com.spring.dao.UserDaoImpl"></bean>--> <bean id="dao1" class="com.spring.dao.UserDaoImpl1"></bean> <bean id="test" class="com.spring.dao.TestDaoImpl"></bean> <bean id="service" class="com.spring.service.UserServiceImpl"> <!--setter方法注入--> <!--<property name="dao" ref="dao"></property>--> <!--构造方法注入--> <!--<constructor-arg name="dao" ref="dao"></constructor-arg>--> </bean> </beans>4、解析xml,创建对象并维护对象的依赖。(根据配置文件中的要求实现)
public class BeanFactory { //对象名称和类的对应关系 Map<String,Object> map = new HashMap<String,Object>(); public BeanFactory(String xml){ parseXml(xml); } //解析xml中的映射关系 private void parseXml(String xml){ //读取XML文件 File xmlFile = new File(this.getClass().getResource("/").getPath()+"//"+xml); SAXReader reader = new SAXReader(); try { //获得XML文档 Document document = reader.read(xmlFile); Element documentRoot = document.getRootElement(); //是否自动装配 Attribute autowire = documentRoot.attribute("default-autowire"); Boolean flag = false; if(autowire != null){ flag = true; } //bean列表 for (Iterator<Element> itFirst = documentRoot.elementIterator(); itFirst.hasNext();) { //创建对象 Element elementFirst = itFirst.next(); //对象名 Attribute attributeId = elementFirst.attribute("id"); String attributeIdName = attributeId.getValue(); //对象 Attribute attributeClass = elementFirst.attribute("class"); String attributeClassName = attributeClass.getValue(); Class objectClazz = Class.forName(attributeClassName); Object object = null; //维护对象的依赖关系 for (Iterator<Element> itSecond = elementFirst.elementIterator(); itSecond.hasNext();) { Element elementSecond = itSecond.next(); //用setter方法注入 if(elementSecond.getName().equals("property")){ //使用默认构造方法 object = objectClazz.newInstance(); //获取ref属性值 Attribute attributeRef = elementSecond.attribute("ref"); String refValue = attributeRef.getValue(); Object refObject = map.get(refValue);//根据ref值找到对应对象 //获取name属性值--对应对象中的set方法后面的值 Attribute attributeName = elementSecond.attribute("name"); String nameValue = attributeName.getValue(); Field field = objectClazz.getDeclaredField(nameValue); //找不到对应方法 if(field == null){ throw new NyExecption("依赖在类中未被注入!"); } field.setAccessible(true);//开启属性注入 field.set(object,refObject); }else if(elementSecond.getName().equals("constructor-arg")){ //获得依赖对象 String refValue = elementSecond.attribute("ref").getValue(); Object refObject = map.get(refValue); //获得构造参数需要的class String nameValue = elementSecond.attribute("name").getValue(); Class fieldClazz = objectClazz.getDeclaredField(nameValue).getType(); //获得构造对象 Constructor constructor = objectClazz.getConstructor(fieldClazz); //使用特殊的构造方法 object = constructor.newInstance(refObject); }else { throw new NyExecption("配置文件标签错误,请修改。"); } } //没有配置注入时使用自动装配 if(flag && object == null){ String autoType = autowire.getValue(); if(autoType.equals("byType")){//按类型装配 //获得对象 object = objectClazz.newInstance(); //判斷是否有依賴 Field[] fields = objectClazz.getDeclaredFields(); for (Field field : fields) { //得到屬性的類型 Class injectClazz = field.getType(); /** * 由於是bytype 所以需要遍历map当中的所有对象 * 判断对象的类型是不是和这个injectObjectClazz相同 */ int count = 0; Object injectObject = null; for (String key : map.keySet()) { Class injectObjectClazz = map.get(key).getClass().getInterfaces()[0]; if(injectObjectClazz.getName().equals(injectClazz.getName())){ injectObject = map.get(key); //记录找到一个,因为可能找到多个count count++; } } if(count > 1){ throw new NyExecption("需要一个对象,但是找到了"+count+"个对象"); }else {//注入对象依赖 field.setAccessible(true); field.set(object,injectObject); } } }else if(autoType.equals("byName")){//按名称装配 //判斷是否有依賴 Field[] fields = objectClazz.getDeclaredFields(); object = objectClazz.newInstance();//获得对象 for (Field field : fields) { String injectName = field.getName(); Object injectObject = map.get(injectName); //找不到注入的对象 if(injectObject == null){ throw new NyExecption("依赖的对象不存在!"); } //对象注入属性--依赖对象 field.setAccessible(true); field.set(object,injectObject); } } } //没有子标签 if(object == null){ object = objectClazz.newInstance(); } map.put(attributeIdName,object); } } catch (Exception e) { e.printStackTrace(); } } //获取对应对象 public Object getBean(String beanName){ return map.get(beanName); } }5、测试类(根据不同情况进行修改测试)
public class Test { public static void main(String[] args) { BeanFactory beanFactory = new BeanFactory("spring.xml"); UserService userService = (UserService) beanFactory.getBean("service"); userService.find(); } }前两步与第一种方法一样。 3、自定义一个注解,用于标记扫描的类
@Retention(RetentionPolicy.RUNTIME) public @interface MyService { public String value(); }4、解析注解
public class MyAnnotationConfigApplicationContext { //对象名称和类的对应关系 Map<String,Object> map = new HashMap<String,Object>(); public MyAnnotationConfigApplicationContext(String basePackage){ Scan(basePackage); } public Object Scan(String basePackage){ Object object = null; String rootPath = this.getClass().getResource("/").getPath(); //将包路径替换为/格式 String basePackagePath = basePackage.replaceAll("\\.","\\\\"); File file = new File(rootPath+"\\"+basePackagePath); String[] fileList = file.list();//获取路径下所有类 for (String className : fileList) { try { className = className.substring(0,className.indexOf(".")); //获取class对象 Class clazz = Class.forName(basePackage + "." + className); //只扫描有MyService注解的类 if (clazz.isAnnotationPresent(MyService.class)) { //获取注解中的value MyService service = (MyService) clazz.getDeclaredAnnotation(MyService.class); System.out.println(service.value()); //对象注入 object = clazz.newInstance(); System.out.println(object); map.put(service.value(),object); } } catch (Exception e) { e.printStackTrace(); } } //检查类中是否有需要自动注入的属性 //思路:1、建一个map存入上方注入的类名称和class对象 //2、检查注入的对象中属性是否有@Autowired注解或@Resource注解 //3、如果有@Autowired注解按照属性类型的class到map中找是否有对应类型进行注入,注意只能有一个 //4、如果有@Resource注解,取里面的name属性,到map中的key中找是否有对应的key,进行注入。 if (!map.isEmpty()){ //遍历对象进行依赖注入 for (String name : map.keySet()) { Object injectObject = map.get(name); Class injectObjectClazz = injectObject.getClass(); Object innerObject = null; //获取所有属性 Field[] fields = injectObjectClazz.getDeclaredFields(); if(fields.length > 0){ for (Field field : fields) { //存在Autowired注解 if(field.isAnnotationPresent(Autowired.class)){ Class fieldClazz = field.getType(); int count = 0; //遍历map找到对应class对象 for (String objName : map.keySet()) { Class objClazz = map.get(objName).getClass(); if(fieldClazz.getName().equals(objClazz.getInterfaces()[0].getName())){ innerObject = map.get(objName); count++; } } //判断是否有匹配的注入对象 if(count == 0){ throw new NyExecption("没有找到属性值匹配的类型对象。"); }else if(count == 1){ try { field.setAccessible(true); field.set(injectObject,innerObject); } catch (Exception e) { e.printStackTrace(); } }else { throw new NyExecption("需要一个对象,但是找到了"+count+"个对象"); } } //存在Resource注解 if(field.isAnnotationPresent(Resource.class)){ //获取注解中的name Resource resource = (Resource) field.getDeclaredAnnotation(Resource.class); String daoName = resource.name(); //在map中找到对应class对象 Object fieldObject = map.get(daoName); if(fieldObject == null){ throw new NyExecption("没有找到属性值匹配的类型对象。"); } try { field.setAccessible(true); field.set(injectObject,fieldObject); } catch (Exception e) { e.printStackTrace(); } } } } } } return object; } //获取对应对象 public Object getBean(String beanName){ return map.get(beanName); } }5、测试类,根据不同情况调整代码进行测试
public class Test { public static void main(String[] args) { MyAnnotationConfigApplicationContext context = new MyAnnotationConfigApplicationContext("com.spring.dao"); TestDao testDao = (TestDao) context.getBean("testDaoImpl"); testDao.query(); } }以上就是简易的SpringIoc实现小例子,需要根据不同情况就行调整测试,是新手理解springIoc的一个好方式。