zoukankan      html  css  js  c++  java
  • Spring依赖注入原理

        接触过spring 的同学应该都知道依赖注入,依赖注入又称控制反转,其内涵就是,将创建某个bean的控制权力,由原来需要引用这个bean的bean转移(反转)到外部的spring IOC容器,由IOC容器统一创建,并且注入到需要引用的bean中去。 那么spring是怎么做到依赖注入的,我们来看看spring是怎么做的吧!

        其实,spring的本质是一个工厂(beanFactory)或者说bean容器,它按照我们的要求,生产我们需要的各种各样的bean,提供给我们使用。只是在生产bean的过程中,需要解决bean之间的依赖问题,才引入了依赖注入(DI)这种技术。也就是说依赖注入是beanFactory生产bean时为了解决bean之间的依赖的一种技术而已。但是,我们一般都不直接用BeanFactory,而是用它的实现类ApplicationContext,这个类会自动解析我们配置的applicationContext.xml,然后根据我们配置的bean来new对象,将new好的对象放进一个Map中,键就是我们bean的id,值就是new的对象。

        我们来看一下beanFactory的代码:

     1 package org.springframework.beans.factory;
     2 
     3 public interface BeanFactory {
     4     String FACTORY_BEAN_PREFIX = "&";
     5 
     6     Object getBean(String var1) throws BeansException;
     7 
     8     <T> T getBean(String var1, Class<T> var2) throws BeansException;
     9 
    10     <T> T getBean(Class<T> var1) throws BeansException;
    11 
    12     Object getBean(String var1, Object... var2) throws BeansException;
    13 
    14     <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
    15 
    16      ...
    17 }

    beanFactory是一个接口,其中定义了各种getBean()方法,我们可以看到返回的是一个object对象,因此通过上下文对象ApplicationContext对象拿到的对象都必须通过强转能变成指定的类型的对象。

    我们再来模拟ClassPathXmlApplicationContext的是怎么拿到bean的:

     1 package com.spring.Context;
     2 
     3 import java.util.HashMap;
     4 import java.util.List;
     5 import java.util.Map;
     6 
     7 import org.dom4j.Document;
     8 import org.dom4j.DocumentException;
     9 import org.dom4j.Element;
    10 import org.dom4j.io.SAXReader;
    11 
    12 
    13 public class ClassPathXmlApplicationContext implements BeanFactory {
    14     private Map<String, Object> beanMap = new HashMap<String, Object>();   //map的value是object
    15     public ClassPathXmlApplicationContext(String fileName) throws Exception{
    16         SAXReader reader = new SAXReader();
    17         Document document = reader.read(this.getClass().getClassLoader().getResourceAsStream(fileName));  //SAX解析对应的xml配置文件
    18         List<Element> elements = document.selectNodes("/beans/bean");
    19         for (Element e : elements) {
    20             String id = e.attributeValue("id");
    21             String value = e.attributeValue("class");
    22             Object o = Class.forName(value).newInstance();   //利用反射通过类名拿到的类的一个实例对象
    23             beanMap.put(id, o);
    24         }
    25     }
    26     
    27     public Object getBean(String id) {
    28         return beanMap.get(id);
    29     }
    30 
    31 }

    我们可以发现,通过spring  getBean()拿到的对象实例,都是通过读取applicationContext.xml文件,再通过反射拿到的类的实例对象。

    因此,spring注入的对象必须可以实例化,也就是说,接口和抽象类是不能通过spring实现注入的,因为两者都不能实例化。

    这就让人很不能理解了,因为在做spring-mybatis整合的时候,我们有一个常见的做法就是在service层通过注解注入dao层接口,在这里不是可以注入接口吗?为什么又说spring不能注入接口呢?

    其实,这里注入的接口,并不是真正的接口,我们不妨吧这个注入的“接口”打印出来看看,到底是个什么东西:

    1 the dao is:  org.apache.ibatis.binding.MapperProxy@33e4ae3b
    2 the dao class is : class com.sun.proxy.$Proxy21

    输出显示,其实注入的并不是接口,而是mybatis中的mapper对象的代理类。

    至于这个里面的玄机,还是等下次去探讨吧!

  • 相关阅读:
    从零到有模拟实现一个Set类
    node+express+mysql 实现登陆注册
    从路由原理出发,深入阅读理解react-router 4.0的源码
    linux rsyncserver文件同步
    为什么说Python是一门动态语言--Python的魅力
    python基础教程_学习笔记11:魔法方法、属性和迭代器
    list,set,map,数组间的相互转换
    TCP/IP协议族
    宿舍更换的新淋浴喷头"水温vs旋钮角度"关系的研究(曲线)
    单元測试中 Right-BICEP 和 CORRECT
  • 原文地址:https://www.cnblogs.com/jy107600/p/7483610.html
Copyright © 2011-2022 走看看