Spring的IOC容器分析

文章目录

  • Spring的IOC从入门到深入
    • 1.分析下面代码开发中存在的问题:
    • 2. 针对上述代码存在的问题,我们该解决,
      • 第一步: 将耦合类配置到xml文件中, 比如: beans.xml
      • 第二步: 创建容器对象,加载配置文件,创建对象存储到容器中
      • 第3步: 测试
    • 4. 总结
    • 5. 下面我们看下spring框架的IOC是如何实现的
      • 第一步: 在创建的maven项目中,导入spring-webmvc依赖
      • 第二步: 创建spring配置文件
      • 第三步: 使用spring核心对象,获取容器中的bean对象
    • 6. 对比spring框架的核心 与自定义的容器
    • 7. Spring的注解开发
    • 8. Spring整合junit进行单元测试

Spring的IOC从入门到深入

1.分析下面代码开发中存在的问题:

Spring的IOC容器分析_第1张图片

2. 针对上述代码存在的问题,我们该解决,

解决方案是: 将测试类与接口的耦合,通过第三方容器来解决
实现步骤分为两步:

第一步: 将耦合类配置到xml文件中, 比如: beans.xml




<objs>
    
    <obj id="dog" class="com.tedu.service.impl.Dog"/>
    <obj id="cat" class="com.tedu.service.impl.Cat"/>
objs>

第二步: 创建容器对象,加载配置文件,创建对象存储到容器中

/**
 * 模拟Spring核心对象:
 * 1.通过解析xml文件,读取到class属性的值
 * 2.利用反射Class.newInstance()创建对象
 * 3.把创建的对象存到map里面(map就是spring容器)
 *  map容器存对象有两种方式:
 *  方式一: map中的key: 类名称(首字母小写), map的value: 类对象
 *  方式二: map中的key: 类的class对象, map的value: 类对象
 */
public class MyApplicationContext {
    //1.引入被加载的xml文件
    private  String resourcesXml;
    //2.创建容器对象, 就是map, 底层是线程安全的map
    private static Map<Object,Object> map = new ConcurrentHashMap<Object,Object>();
    //3.通过构造方法给引入的xml文件赋值
    public MyApplicationContext(String xmlPath){
        this.resourcesXml = xmlPath;
        //解析配置文件,创建对象,存到map容器中
        try{
            //5.解析配置文件的代码: dom4j技术解析xml,
            SAXReader saxReader = new SAXReader();//核心解析器对象
            //6.类加载器获取配置文件字节输入流
            InputStream in = MyApplicationContext.class.getClassLoader().getResourceAsStream(resourcesXml);
            //7.读取配置文件字节输入流,获取xml的文档对象
            Document document = saxReader.read(in);
            //8.根据document获取所有的obj标签对象
            List<Node> list = document.selectNodes("//obj");
            //9.遍历list集合,获取list集合里面的每一个obj标签
            for (Node node : list) {
                //10. 把node节点转换为 element标签
                Element element = (Element)node;
                //11. 根据element标签对象:获取id属性值,获取class属性值
                String idValue   = element.attributeValue("id");//比如:idValue = dog
                String classPath = element.attributeValue("class");//比如:classPath = 包名.Dog
                //12.利用反射创建对象
                Class aClass = Class.forName(classPath);//得到类的字节码对象, 比如: Dog.class
                Object obj = aClass.newInstance();//反射: 默认使用无参数的构造方法创建对象
                //13.把创建好的对象存到容器中
                //13.1比如: 根据 dog名称-- new Dog()对象
                map.put(idValue,obj);
                //13.2比如: 根据 Dog.class-- new Dog()对象
                map.put(aClass,obj);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //4.提供一个根据名称: 也就是根据id的属性值获取 bean对象的方法
    //直接从map容器中获取对象
    public static Object getBean(String idValue){
        return  map.get(idValue);
    }
    //5.提供一个根据名称: 也就是根据Class字节码对象获取 bean对象的方法
    //定义泛型的优点: 避免类型强转
    //直接从map容器中获取对象
    public static <T> T getBean(Class<T> clz){
        return  (T)map.get(clz);
    }
}

第3步: 测试

public class Demo {
    public static void main(String[] args) {
        //1.创建核心对象:
        //核心对象使用类加载器加载配置文件,
        // 类加载器文件在resources根目录下面,所以和beans.xml同一级目录(相对路径写法)
        MyApplicationContext map =
                              new MyApplicationContext("beans.xml");
        //2.根据id属性值: 获取bean对象,这个方法没有使用泛型,需要强转
        //解耦合: 看不到Demo类与 Pet接口,或者Dog实现类有耦合关系
        Pet pet = (Pet)map.getBean("dog");
        //3.根据class值: 获取bean对象,这个方法使用了泛型,不用强转
        Pet pet2 = map.getBean(Dog.class);
        pet.hello();
        pet2.hello();
    }
}

4. 总结

Spring的IOC容器分析_第2张图片

5. 下面我们看下spring框架的IOC是如何实现的

第一步: 在创建的maven项目中,导入spring-webmvc依赖

<dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-webmvcartifactId>
        <version>5.1.16.RELEASEversion>
    dependency>

依赖解释:
Spring的IOC容器分析_第3张图片

第二步: 创建spring配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    <bean id="dog" scope="singleton" lazy-init="false" 
          class="com.tedu.service.impl.Dog"/>
    <bean id="cat" class="com.tedu.service.impl.Cat"/>
beans>

第三步: 使用spring核心对象,获取容器中的bean对象

public class Demo2 {
    public static void main(String[] args) {
        //1.创建容器对象
        //在这里: 为什么直接写文件名称, 因为底层是类加载器加载spring配置文件的
        //类加载器在resources根目录下面: 和spring.xml同一级目录
        ApplicationContext map = new ClassPathXmlApplicationContext("spring.xml");
        //2.根据类的名称获取对象: 这个方法没有使用泛型,必须强转
       Pet pet = (Pet)map.getBean("dog");
        //3.根据Class获取对象: 这个方法使用泛型,不用强转
        Pet pet2 = map.getBean(Dog.class);
    }
}

6. 对比spring框架的核心 与自定义的容器

通过下图我们能分析到一下三点:

  1. Spring框架底层是通过类加载器加载spring的配置文件的,类加载器的位置在resources的根目录下面
    所以和配置文件同一级目录,直接写目录名称

  2. Spring框架的容器底层就是一个map集合

  3. Spring容器在存储对象有两种方式
    第一: 根据类名,存储该类的对象
    第二:根据类的class字节码,存储该类的对象
    Spring的IOC容器分析_第4张图片

7. Spring的注解开发

核心思路:

  1. 通过注解替代配置文件, Spring框架中配置自动扫描包机制,根据扫描的类,创建对象,存到容器中.
  2. Spring容器通过注解开发时,在存储对象依然是下面的两种方式
    第一: 根据类名,存储该类的对象
    第二:根据类的class字节码,存储该类的对象
  3. Spring的DI依赖注入: 其实就是给当前类的成员变量(成员属性)赋值
    常见DI注入方式有两种:
    • 通过构造方法DI依赖注入
      *比如:
      Spring的IOC容器分析_第5张图片

    • 通过set方法DI依赖注入

    • 比如:
      Spring的IOC容器分析_第6张图片

8. Spring整合junit进行单元测试

你可能感兴趣的:(spring,spring,容器,java)