Spring的IOC容器分析

15 篇文章 0 订阅
11 篇文章 2 订阅

Spring的IOC从入门到深入

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

在这里插入图片描述

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

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

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

<?xml version="1.0" encoding="utf-8" ?>
<!--上面是:文档声明是xml文档-->
<!--XML有且仅有一个根标签: objs,由于是自定义的xml,标签可以任意定义-->
<objs>
    <!--子标签: obj
       id: 唯一标识,一般建议使用类名,首字母小写
       class:类的全路径
    -->
    <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. 总结

在这里插入图片描述

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

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

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.16.RELEASE</version>
    </dependency>

依赖解释:
在这里插入图片描述

第二步: 创建spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<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标签,不能写其它?
    因为上述头中spring-beans.xsd: 这个是约束文件,规定了标签的名称以及属性的书写
    id: 唯一标识
    scope: 作用范围, 比如: 创建单例对象(只创建一个对象)
    lazy-init: 是否立即创建对象,比如: false 懒加载,什么时候调用方法,什么时候创建对象
    -->
    <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字节码,存储该类的对象
    在这里插入图片描述

7. Spring的注解开发

核心思路:

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

    • 通过set方法DI依赖注入

    • 比如:
      在这里插入图片描述

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

评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值