从山寨Spring中学习Spring IOC原理-XML-Constructor

前言

上一篇【从山寨Spring中学习Spring IOC原理-XML-Setter】我们完成了对Spring中Setter方法的山寨,那么这次就要改造一下我们的程序,让其满足使用构造方法注入。进入之前希望有条件的读者,下手把笔者贴出来的代码敲一遍,或者复制一遍在编译器里跟踪运行一下。这样每一步取了什么值,为什么这样写,就会更加明白了。更多Spring内容进入【Spring解读系列目录】

修改程序

如果是使用构造方法进行构建,那么就需要在UserServiceImpl使用构造方法传递UserDao进去,修改代码为:

public class UserServiceImpl implements UserService {
    private UserDao userDao;
  @Override
    public void find() {
        System.out.println("UserServiceImpl find()");
        userDao.query();
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public UserServiceImpl(UserDao userDao) {  //创建构造方法
        this.userDao = userDao;
    }
}

同时我们的配置文件也要修改,为了简化代码,只让有一个构造方法。

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="dao" class="com.demo.dao.UserDaoImpl"></bean>
    <bean id="service" class="com.demo.service.UserServiceImpl">
        <!--假设只有一个构造方法-->
        <constructor-arg name="userDao" ref="dao"></constructor-arg>
    </bean>
</beans>

最终修改的大头就落在了BeanFactory上,为了更加清楚,我们重构一个类BeanFactoryCon:

public class BeanFactoryCon {

    Map<String, Object> map=new HashMap<>();

    public BeanFactoryCon(String xml) {
        parseXml(xml);
    }

    public void parseXml(String xml){
        String path=this.getClass().getResource("/").getPath()+xml;
        File file=new File(path);
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(file);
            Element elementRoot=document.getRootElement();
            //拿取xml中元素的内容
            for (Iterator<Element> itFirst = elementRoot.elementIterator(); itFirst.hasNext();) {
                Element elementFirstChild = itFirst.next();
                //取到id值
                Attribute attribute=elementFirstChild.attribute("id");
                String beanName=attribute.getValue();
                //取到类全名
                Attribute attribute2=elementFirstChild.attribute("class");
                String clazzName=attribute2.getValue();
                //获取标签中的类全名
                Class clazz=Class.forName(clazzName);
                //当我们写了构造方法的时候,默认的构造方法就不存在了,所以不能直接newInstance()构建实例,而应该使用标签里的构造标签
                Object object=null;
                //维护依赖关系,找到依赖关系:判断是否有属性,然后判断属性是否有对应的constructor-arg
                //  如果有则注入,所以每循环到一个bean就要拿出子标签
                for (Iterator<Element> itSecond = elementFirstChild.elementIterator(); itSecond.hasNext();) {
                    Element elementSecondChild =itSecond.next();
                    if (elementSecondChild.getName().equals("constructor-arg")){
                        //把map中存的UserDao对象拿出来
                        String refValue=elementSecondChild.attribute("ref").getValue();
                        Object injectObj=map.get(refValue);
                        //把UserDao对象构造为一个类
                        Class injectObjClazz=injectObj.getClass();
                        String nameValue=elementSecondChild.attribute("name").getValue();
                        //拿到属性类型,为了创建构造方法
                        Field field=clazz.getDeclaredField(nameValue);
                        //根据属性类型创建构造方法对象,这里也可以通过实现的接口去构造
                        Constructor constructor=clazz.getConstructor(field.getType());
                        //clazz.getConstructor(injectObjClazz.getInterfaces()[0]);
                        //使用构造方法对象把UserDao对象注入进去。
                        object=constructor.newInstance(injectObj);
                    }
                }
                if(object==null){//没有子标签,意味着没有依赖所以new出来
                    object=clazz.newInstance();
                }
                map.put(beanName,object);
            }
            System.out.println(map.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String bean){
        return map.get(bean);
    }
}

修改完毕以后,修改Test类,运行测试:

public class Test {
    public static void main(String[] args) {
		BeanFactoryCon beanFactoryCon=new BeanFactoryCon("spring.xml");
        UserService service= (UserService) beanFactoryCon.getBean("service");
        service.find();
    }
}
运行结果:
UserServiceImpl find()
UserDaoImpl query 1

总结

在对上个程序进行简单的修改以后,我们就完成了容器基于构造方法的注入,其实通过这些例子的构造,大体也能猜出Spring源码到底的怎么写的,只是那些大神们的思维更加的严谨,更加的详实。目前已经注入没有问题了,既然要山寨Spring,就不能少了Spring的自动注入。所以下一篇【从山寨Spring中学习Spring IOC原理-byType自动装配】我们就会模拟一个Spring自动注入的过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值