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中出现两个则需要抛出自定义异常(再容器中找到两个一样的注入对象)

 

原文地址:https://www.cnblogs.com/gnwzj/p/11128173.html