Spring依赖的自动注入

一、准备类
public interface UserDao {
    public void findName();
}
public class UserDaoImpl implements  UserDao{
    @Override
    public void findName() {
        System.out.println("我是dao实现类1");
    }
}
public class UserDaoImpl2 implements  UserDao{
    @Override
    public void findName() {
        System.out.println("我是dao实现类2");
    }
    
}
public interface UserService {
    public void findAge();
}
public class UserServiceImpl implements UserService {

    UserDao dao;

    @Override
    public void findAge() {
        System.out.println("我是service的实现类");
        dao.findName();
    }

    public void setDao(UserDao dao) {
        this.dao = dao;
    }
}
二、实现方法
public class BeanFactory {
   
    Map<String,Object> map = new HashMap<String,Object>();
    public BeanFactory(String xml){
        parseXml(xml);
    }

    public void parseXml(String xml) throws CjxSpringException{

        File file = new File(this.getClass().getResource("/").getPath()+"//"+xml);
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(file);
            Element elementRoot = document.getRootElement();
            Attribute attribute = elementRoot.attribute("default");
            boolean flag=false;
            if (attribute!=null){
                flag=true;
            }
            for (Iterator<Element> itFirlst = elementRoot.elementIterator(); itFirlst.hasNext();) {
                /**
                 * setup1、实例化对象
                 */
                Element elementFirstChil = itFirlst.next();
                Attribute attributeId = elementFirstChil.attribute("id");
                String beanName = attributeId.getValue();
                Attribute attributeClass = elementFirstChil.attribute("class");
                String clazzName  = attributeClass.getValue();
                Class clazz = Class.forName(clazzName);

                /**
                 * 维护依赖关系
                 * 看这个对象有没有依赖(判断是否有property。或者判断类是否有属性)
                 * 如果有则注入
                 */
                Object object = null;
                for (Iterator<Element> itSecond = elementFirstChil.elementIterator(); itSecond.hasNext();){
                    // 得到ref的value,通过value得到对象(map)
                    // 得到name的值,然后根据值获取一个Filed的对象
                    //通过field的set方法set那个对象

                    //<property name="dao" ref="dao"></property>
                    Element elementSecondChil = itSecond.next();
                    if(elementSecondChil.getName().equals("property")){
                        //由于是setter,沒有特殊的构造方法
                        object= clazz.newInstance();
                        String refVlaue = elementSecondChil.attribute("ref").getValue();
                        Object injetObject= map.get(refVlaue) ;
                        String nameVlaue = elementSecondChil.attribute("name").getValue();
                        Field field = clazz.getDeclaredField(nameVlaue);
                        field.setAccessible(true);
                        field.set(object,injetObject);

                    }else{
                        //證明有特殊構造
                        String refVlaue = elementSecondChil.attribute("ref").getValue();
                        Object injetObject= map.get(refVlaue) ;
                        Class injectObjectClazz = injetObject.getClass();
                        Constructor constructor = clazz.getConstructor(injectObjectClazz.getInterfaces()[0]);
                        object = constructor.newInstance(injetObject);
                    }

                }
                if(object==null) {
                    if (flag) {
                        if (attribute.getValue().equals("byType")) {
                            //判斷是否有依賴
                            Field fields[] = clazz.getDeclaredFields();
                            for (Field field : fields) {
                                //得到屬性的類型,比如String aa那麽這裏的field.getType()=String.class
                                Class injectObjectClazz = field.getType();
                                /**
                                 * 由于是bytype 所以需要遍历map当中的所有对象
                                 * 判断对象的类型是不是和这个injectObjectClazz相同
                                 */
                                int count = 0;
                                Object injectObject = null;
                                for (String key : map.keySet()) {
                                    Class temp = map.get(key).getClass().getInterfaces()[0];
                                    if (temp.getName().equals(injectObjectClazz.getName())) {
                                        injectObject = map.get(key);
                                        //记录找到一个,因为可能找到多个count
                                        count++;
                                    }
                                }

                                if (count > 1) {
                                    throw new CjxSpringException("需要一个对象,但是找到了两个对象");
                                } else {
                                    object = clazz.newInstance();
                                    field.setAccessible(true);
                                    field.set(object, injectObject);
                                }
                            }
                        }
                    }
                }

                if(object==null){//沒有子标签
                    object = clazz.newInstance();
                }
                map.put(beanName,object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(map);
    }
    public Object getBean(String beanName){
        return map.get(beanName);
    }

}

三、配置文件
<?xml version="1.0" encoding="UTF-8" ?>

<beans default="byType">
<bean id="dao" class="com.cjx.spring.dao.UserDaoImpl"></bean>
<bean id="service" class="com.cjx.spring.service.UserServiceImpl">

</bean>
</beans>
四、总结

代码的逻辑是,获取根节点并判断是否配置的byType,如果配置了byType,开启byType自动注入。遍历根节点下的所有二级标签,这里的二级标签为bean,下面就用bean标签来替换二级标签,比较容易理解。拿到第一个bean标签,就可以拿到标签配置的id和class的属性值,紧接着判断是否配置的property或者constructor标签,如果配置了就获取标签的name和ref属性,实例化该bean对象,并通过ref属性从ioc容器中获取要注入的对象,并通过反射的形式将对象注入。如果这个bean没有配置property或者constructor标签,但是开启了byType,就获取该bean中所有的属性,遍历判断容器中有多少个该属性的实现类,如果有多个抛出一样,如果为1个,就自动注入。(代码没有判断为0的情况,如果为0,可以提示该属性的实现类找不到)。整套逻辑也是和spring一样,手动配置优先于自动配置,如果在bean标签配置了property或者构造注入的,优先于自动配置的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值