spring(一)spring概述、spring体系结构、IOC详解、手写简单IOC容器、bean的自动装配

本文详细介绍了Spring框架,从Spring的核心模块、体系结构到IOC(控制反转)概念,包括BeanFactory和ApplicationContext容器。通过示例展示了如何通过配置文件管理Bean,如依赖注入、Bean的自动装配等,最后探讨了IOC容器的功能和实现。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

1、Spring概述

官网相关

spring概述

  ①Spring是一个开源框架
  ②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
③Spring是一个IOC(DI)和AOP容器框架。
④Spring的优良特性
  [1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
  [2]控制反转:IOC——Inversion of Control,指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。
  [3]依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设置,而是通过配置赋值。
  [4]面向切面编程:Aspect Oriented Programming——AOP
  [5]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
   [6]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
   [7]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。

2、Spring体系结构

Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。下面的部分对在 Spring 框架中所有可用的模块给出了详细的介绍。

Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用。
在这里插入图片描述

核心容器

  1. 核心容器由核心,Bean,上下文和表达式语言模块组成,它们的细节如下: 核心模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

2 Bean 模块提供 BeanFactory,它是一个工厂模式的复杂实现。

3 上下文模块建立在由核心和 Bean 模块提供的坚实基础上,它是访问定义和配置的任何对象的媒介。ApplicationContext
接口是上下文模块的重点。

4 表达式语言模块在运行时提供了查询和操作一个对象图的强大的表达式语言。

数据访问/集成

  1. 数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

  2. JDBC 模块提供了删除冗余的 JDBC 相关编码的 JDBC 抽象层。

  3. ORM 模块为流行的对象关系映射 API,包括 JPA,JDO,Hibernate 和 iBatis,提供了集成层。

  4. OXM 模块提供了抽象层,它支持对 JAXB,Castor,XMLBeans,JiBX 和 XStream 的对象/XML 映射实现。

  5. Java 消息服务 JMS 模块包含生产和消费的信息的功能。

  6. 事务模块为实现特殊接口的类及所有的 POJO 支持编程式和声明式事务管理。

Web
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

  1. Web 模块提供了基本的面向 web 的集成功能,例如多个文件上传的功能和使用 servlet 监听器和面向 web
    应用程序的上下文来初始化 IoC 容器。
  2. Web-MVC 模块包含 Spring 的模型-视图-控制器(MVC),实现了 web 应用程序。
  3. Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web
    应用程序中提供了客户端和服务器端之间通信的两种方式。
  4. Web-Portlet 模块提供了在 portlet 环境中实现 MVC,并且反映了 Web-Servlet 模块的功能。

其他

还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

  1. AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,它实现了应该分离的功能。
  2. Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
  3. Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
  4. Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket
    子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
  5. 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

Spring框架分为四大模块:

  Core核心模块。负责管理组件的Bean对象
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar

  面向切面编程
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar

  数据库操作
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-oxm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
spring-jms-4.0.0.RELEASE.jar

  Web模块
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar
spring-websocket-4.0.0.RELEASE.jar
spring-webmvc-portlet-4.0.0.RELEASE.jar

依赖注入(DI)

  Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

  当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用额可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。

  到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。

  依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。

面向方面的程序设计(AOP):

Spring 框架的一个关键组件是面向方面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。

Spring 框架的 AOP 模块提供了面向方面的程序设计实现,允许你定义拦截器方法和切入点,可以实现将应该被分开的代码干净的分开功能。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。

环境搭建

1 、下载 Spring5
在这里插入图片描述

(1)使用 Spring 最新稳定版本 5.2.6
(2)下载地址
https://repo.spring.io/release/org/springframework/spring/
在这里插入图片描述在这里插入图片描述

2 、打开 idea 工具,创建普通 Java 工程
在这里插入图片描述

3 、导入 Spring5 相关 jar 包
在这里插入图片描述在这里插入图片描述首先创建实体类

public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String phone;
    //省略getset方法,构造器,tostring方法
    }

写配置文件一般叫做applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <bean id="person" class="com.zy.entity.User">
        <property name="id" value=" 21"/>
        <property name="name" value=" 小脑斧"/>
        <property name="age" value=" 21"/>
        <property name="phone" value=" 2291689267"/>
    </bean>
</beans>

最后测试

 @Test
    public void test(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        User user = context.getBean(User.class);
        System.out.println(user);
    }

在这里插入图片描述

3.IOC

1、什么是IOC(控制反转)

​ a)把对象创建和对象之间的调用过程,交给Spring进行管理

​ b)使用IOC目的:为了降低耦合度

​ 2、IOC底层

​ a)xml解析、工厂模式、反射
3、两种实现: 依赖查找(DL)和依赖注入(DI)。

ioc容器

​ Spring提供的IOC容器实现的两种方式(两个接口)
  BeanFactory 粗暴简单,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。

  ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。

例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。

该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。

当然,除了这两个大接口,还有其他的辅助接口

BeanFactory容器

  是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。 BeanFactory 和相关的接口,比如,BeanFactoryAware、 DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。

  在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

  在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。

@Test
    public void test1(){
        XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("ApplicationContext.xml"));
        User user = factory.getBean(User.class);
        System.out.println(user);
    }

注意:
XmlBeanFactoty(new ClassPathResource)这种获取工厂对象再获取bean的方式有点过时,不建议使用

  1. 第一步利用框架提供的 XmlBeanFactory() API 去生成工厂 bean 以及利用 ClassPathResource()
    API 去加载在路径 CLASSPATH 下可用的 bean 配置文件。XmlBeanFactory() API
    负责创建并初始化所有的对象,即在配置文件中提到的 bean。
  2. 第二步利用第一步生成的 bean 工厂对象的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID
    来返回一个真正的对象,该对象最后可以用于实际的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。

在这里插入图片描述

ApplicationContext 容器

  Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件从解析文本信息和将事件传递给所指定的监听器。这个容器在 org.springframework.context.ApplicationContext interface 接口中定义。

  ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会被推荐使用。BeanFactory 仍然可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

最常被使用的 ApplicationContext 接口实现:

  1. FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的
    bean。在这里,你需要提供给构造器 XML 文件的完整路径
  2. ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供
    XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
  3. WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
@Test
    public void test2(){
        ApplicationContext context = new FileSystemXmlApplicationContext("E:\\daima1\\frame\\spring\\spring-01\\src\\main\\resources\\ApplicationContext.xml");
        User person = (User) context.getBean("person");
        System.out.println(person);
    }

注意

  1.   第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的
    FileSystemXmlApplicationContext API 去生成工厂
    bean。FileSystemXmlApplicationContext 负责生成和初始化所有的对象,比如,所有在 XML bean
    配置文件中的 bean。
  2.   第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的
    bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。

ClassPathXmlApplicationContext 类

  为了更直观的展示 “低级容器” 和 “高级容器” 的关系,我这里通过常用的 ClassPathXmlApplicationContext 类,来展示整个容器的层级 UML 关系。

在这里插入图片描述

下面的 3 个绿色的,都是功能扩展接口,这里就不展开讲。

  看下面的隶属 ApplicationContext 粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承哦。他依赖着 “低级容器” 的 getBean 功能。而高级容器有更多的功能:支持不同的信息源头,可以访问文件资源,支持应用事件(Observer 模式)。

  通常用户看到的就是 “高级容器”。 但 BeanFactory 也非常够用啦!

  左边灰色区域的是 “低级容器”, 只负载加载 Bean,获取 Bean。容器其他的高级功能是没有的。例如上图画的 refresh 刷新 Bean 工厂所有配置。生命周期事件回调等。

  好,解释了低级容器和高级容器,我们可以看看一个 IoC 启动过程是什么样子的。说白了,就是 ClassPathXmlApplicationContext 这个类,在启动时,都做了啥。

ClassPathXmlApplicationContext 的构造过程

下图是 ClassPathXmlApplicationContext 的构造过程,实际就是 Spring IoC 的初始化过程。

在这里插入图片描述

注意,这里为了理解方便,有所简化。

这里再用文字来描述这个过程:

①、用户构造 ClassPathXmlApplicationContext(简称 CPAC)

②、CPAC 首先访问了 “抽象高级容器” 的 final 的 refresh 方法,这个方法是模板方法。所以要回调子类(低级容器)的 refreshBeanFactory 方法,这个方法的作用是使用低级容器加载所有 BeanDefinition 和 Properties 到容器中。

③、低级容器加载成功后,高级容器开始处理一些回调,例如 Bean 后置处理器。回调 setBeanFactory 方法。或者注册监听器等,发布事件,实例化单例 Bean 等等功能,这些功能,随着 Spring 的不断升级,功能越来越多,很多人在这里迷失了方向 :)。

简单说就是:

④、低级容器 加载配置文件(从 XML,数据库,Applet),并解析成 BeanDefinition 到低级容器中。

⑤、加载成功后,高级容器启动高级功能,例如接口回调,监听器,自动实例化单例,发布事件等等功能。

所以,一定要把 “低级容器” 和“高级容器” 的区别弄清楚。不能一叶障目不见泰山。

getBean 的流程

当我们创建好容器,就会使用 getBean 方法,获取 Bean,而 getBean 的流程如下:
在这里插入图片描述

从图中可以看出,getBean 的操作都是在低级容器里操作的。其中有个递归操作,这个是什么意思呢?

假设:当 Bean_A 依赖着 Bean_B,而这个 Bean_A 在加载的时候,其配置的 ref = “Bean_B” 在解析的时候只是一个占位符,被放入了 Bean_A 的属性集合中,当调用 getBean 时,需要真正 Bean_B 注入到 Bean_A 内部时,就需要从容器中获取这个 Bean_B,因此产生了递归。

为什么不是在加载的时候,就直接注入呢?因为加载的顺序不同,很可能 Bean_A 依赖的 Bean_B 还没有加载好,也就无法从容器中获取,你不能要求用户把 Bean 的加载顺序排列好,这是不人道的。

所以,Spring 将其分为了 2 个步骤:

     ①、加载所有的 Bean 配置成 BeanDefinition 到容器中,如果 Bean 有依赖关系,则使用占位符暂时代替。

     ②、然后,在调用 getBean 的时候,进行真正的依赖注入,即如果碰到了属性是 ref 的(占位符),那么就从容器里获取这个 Bean,然后注入到实例中 —— 称之为依赖注入。

可以看到,依赖注入实际上,只需要 “低级容器” 就可以实现。

这就是 IoC。

所以 ApplicationContext refresh 方法里面的操作不只是 IoC,是高级容器的所有功能(包括 IoC),IoC 的功能在低级容器里就可以实现。

手写一个简单的ioc

package com.zy.ioc;


import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: SimpleIOC
 * @Author: Tiger
 * @Title:  简单的ioc容器
 * @Datetime: 2020/8/17   21:12
 * @Package: com.zy.ioc
 */
public class SimpleIOC {
    private Map<String, Object> beanMap = new HashMap<String, Object>();

    public SimpleIOC(String location) throws Exception {
        loadBean(location);
    }
    public Object getBean(String name) {
        Object bean = beanMap.get(name);
        if (bean != null) {
            throw new IllegalArgumentException("没有这个组件" + name);
        }
        return bean;
    }
    private void loadBean(String location) throws Exception {
        FileInputStream stream = new FileInputStream(location);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(stream);
        Element element = document.getDocumentElement();
        NodeList nodes = element.getChildNodes();
        //遍历<bean>标签
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                String id = ele.getAttribute("id");
                String aClass = ele.getAttribute("class");
                //加载BeanClass标签
                Class beanClass = null;
                try {
                    beanClass = Class.forName(aClass);
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
                //创建bean
                Object bean = beanClass.newInstance();
                //遍历<properties>标签
                NodeList property = ele.getElementsByTagName("property");
                for (int j = 0; j < property.getLength(); j++) {
                    Node propertyNode = property.item(j);
                    if (propertyNode instanceof Element) {
                        Element propertyElement = (Element) propertyNode;
                        String name = propertyElement.getAttribute("name");
                        String value = propertyElement.getAttribute("value");
                        //利用反射将bean相关字段访问设置为可访问
                        Field declaredField = bean.getClass().getDeclaredField(name);
                        declaredField.setAccessible(true);
                        if (value != null && value.length() > 0) {
                            //将属性填充到相关字段中去
                            declaredField.set(bean, value);
                        } else {
                            String ref = propertyElement.getAttribute("ref");
                            if (ref == null || ref.length() == 0) {
                                throw new IllegalArgumentException("ref 配置错误");
                            }
                            //将引用填充到相关字段中去
                            declaredField.set(bean, getBean(ref));
                        }
                        //将bean注册到bean容器中
                        registerBean(id, bean);
                    }
                }
            }
        }
    }

    private void registerBean(String id, Object bean) {
    }
}

实体类汽车、轮胎

public class Car {
    private String name;
    private String length;
    private String width;
    private String height;
    private Wheel wheel;
    
    // 省略其他不重要代码
}

public class Wheel {
    private String brand;
    private String specification ;
    
    // 省略其他不重要代码
}

配置文件xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <!--
		bean标签配置一个组件类======会由Spring容器来管理
			id 属性给bean添加唯一标识
			class 属性设置 配置的类的全类名
	 -->
<!--    <bean id="person" class="com.zy.entity.User">-->
<!--        <property name="id" value=" 21"/>-->
<!--        <property name="name" value=" 小脑斧"/>-->
<!--        <property name="age" value=" 21"/>-->
<!--        <property name="phone" value=" 2291689267"/>-->
<!--    </bean>-->
    <bean id="wheel" class="com.zy.entity.Wheel">
        <property name="brand" value="Michelin" />
        <property name="specification" value="265/60 R18" />
    </bean>
    <bean id="car" class="com.zy.entity.Car">
        <property name="name" value="Mercedes Benz G 500"/>
        <property name="length" value="4717mm"/>
        <property name="width" value="1855mm"/>
        <property name="height" value="1949mm"/>
        <property name="wheel" ref="wheel"/>
    </bean>

</beans>

测试:

 @Test
    //使用自定义的ioc容器去注册bean
    public void test3() throws Exception {
        String file = SimpleIOC.class.getClassLoader().getResource("ApplicationContext.xml").getFile();
        SimpleIOC simpleIOC = new SimpleIOC(file);
        Car car = (Car) simpleIOC.getBean("car");
        System.out.println(car);
        Wheel wheel = (Wheel)simpleIOC.getBean("wheel");
        System.out.println(wheel);
    }

在这里插入图片描述

ioc实例程序

根据bean的类型从IOC容器中获取bean的实例★

示例程序代码:
当applicationContext.xml配置文件中,只有一个Person.class的对象实例配置的时候,程序是可以正常运行的。

  @Test
    public void test2() {
        ApplicationContext context = new FileSystemXmlApplicationContext("E:\\daima1\\frame\\spring\\spring-01\\src\\main\\resources\\ApplicationContext.xml");
        User person = (User) context.getBean("person");
        System.out.println(person);
    }

当配置文件存在多个同User.Class时
在这里插入图片描述常见错误:
当配置文件存在多个同User.Class时
在这里插入图片描述

通过构造方法参数名注入值

通过构造器为bean的属性赋值

applicationContext.xml配置文件中的内容:

 <bean id="user" class="com.zy.entity.User">
        <!-- constructor-arg 表示有参构造方法中的一个参数 -->
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="name" value="王五"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="phone" value="18610101010"></constructor-arg>
    </bean>

测试结果:
在这里插入图片描述

index属性指定参数的位置

配置文件:

<bean id="user1" class="com.zy.entity.User">
        <!-- index 表示参数的索引位置。索引值从零0开始算 -->
        <constructor-arg index="0" value="4"></constructor-arg>
        <constructor-arg index="1" value="王五"></constructor-arg>
        <constructor-arg index="3" value="18610101010"></constructor-arg>
        <constructor-arg index="2" value="18"></constructor-arg>
    </bean>

测试结果:
在这里插入图片描述

根据参数类型注入

配置文件:

<bean id="user2" class="com.zy.entity.User">
<!--        index表示参数的索引位置,默认从0开始-->
        <constructor-arg index="3" value="18610101010" type="java.lang.String"></constructor-arg>
        <constructor-arg index="1" value="王五" type="java.lang.String"></constructor-arg>
        <!--
           使用类型区分重载的构造函数
            这个地方有一点需要特别注意:
                如果代码中的类型是Integer , 那么type类型是 java.lang.Integer
                如果代码中的类型是int , 那么type类型是int
         -->
        <constructor-arg index="2" value="18" type="java.lang.Integer"></constructor-arg>
        <constructor-arg index="0" value="4" type="java.lang.Integer"></constructor-arg>
    </bean>

测试结果

在这里插入图片描述

通过p名称空间为bean赋值

使用P命名空间
idea使用时需在applicationContext.xml头部配置 xmlns:p=“http://www.springframework.org/schema/p”
为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息。
Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过 元素属性的方式配置 Bean 的属性。
使用 p 命名空间后,基于 XML 的配置方式将进一步简化
配置文件:

<bean id="user3" class="com.zy.entity.User" P:id="6" P:name="小脑i发" P:age="34" P:phone="234456756">

在这里插入图片描述

测试null值的使用

测试使用空值赋值
第一步给实体类的属性给一个默认值
第二步在配置文件中给实体类赋值测试
在这里插入图片描述在这里插入图片描述在这里插入图片描述

ioc之子对象赋值测试

引用其他bean★

创建个新的工程。测试Spring的开发环境。此不重复。请参阅前面,环境搭建。
创建实体类bean
在这里插入图片描述

public class Wheel {
    private String brand;
    private String specification ;
}
 public class Car {
    private String name;
    private String length;
    private String width;
    private String height;
    private Wheel wheel;
}

配置文件:
在这里插入图片描述测试:
在这里插入图片描述

IOC之内部Bean的使用

配置文件

 <bean id="car1" class="com.zy.entity.Car">
        <property name="name" value="Mercedes Benz G 500"/>
        <property name="length" value="4717mm"/>
        <property name="width" value="1855mm"/>
        <property name="height" value="1949mm"/>
        <property name="wheel">
            <bean id="wheel1" class="com.zy.entity.Wheel" P:brand="324" P:specification="265/36"></bean>
        </property>
    </bean>

测试:

   @Test
    public void test5() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Car car = (Car) context.getBean("car1");
        System.out.println(car);
        System.out.println(context.getBean("wheel1"));
    }

内部的bean不能从外面使用
在这里插入图片描述

ioc容器对List、Map、Properties属性的赋值

实体类:

public class Person {
    private int id;
    private String name;
    private int age;
    private String phone;
    private Car car;
    private List<String> phones;
    private Map<String, Object> map;
    private Properties props;
    }

配置文件:

<bean id="person4" class="com.zy.entity.Person">
        <property name="id" value="10" />
        <property name="name" value="perosn10" />
        <property name="age" value="18" />
        <property name="phone" value="0101001" />
<!--        list集合的赋值-->
        <property name="phones">
            <list>
                <value>12423234534</value>
                <value>12443523534</value>
                <value>12465723534</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="11" value="432jty34"></entry>
                <entry key="12" value="43asd234"></entry>
                <entry key="13" value="4323aRTH4"></entry>
            </map>
        </property>
        <!-- map对象 -->
        <property name="props">
            <props>
                <prop key="username">root</prop>
                <prop key="password">root</prop>
                <prop key="drivers">com.mysql.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/spring</prop>
            </props>
        </property>
    </bean>

测试:
在这里插入图片描述

IOC之util 名称空间

添加util名称空间‘
xmlns:util=“http://www.springframework.org/schema/util”
配置文件:

  <util:list id="list1">
        <value>string1</value>
        <value>string2</value>
        <value>string3</value>
    </util:list>
    <bean id="person5" class="com.zy.entity.Person">
        <!--        list集合的赋值-->
        <property name="phones" ref="list1"></property>

测试:
在这里插入图片描述

IOC之级联属性赋值

配置文件:

<bean id="person6" class="com.zy.entity.Person">
        <property name="id" value="10" />
        <property name="name" value="perosn10" />
        <property name="age" value="18" />
        <property name="phone" value="0101001" />
        <!-- list对象 ref表示引用 -->
        <property name="car"  ref="car"/>
        <!-- 级联属性 -->
        <property name="car.name" value="我的爱车"  />
        <property name="car.length" value="13m"  />
        <property name="car.width" value="5m"  />
    </bean>

测试:
在这里插入图片描述

IOC之静态工厂方法创建Bean

配置通过静态工厂方法创建的bean
工厂类:

public class PersonFactory {
    public static Person createPerson(){
        Person person = new Person();
        person.setId(17);
        person .setName("小脑斧");
        person.setAge(22);
        return person;
    }
}

配置文件:

  <!-- 使用静态工厂方法
            class 是工厂 的全类名
            factory-method 这是工厂方法
         -->
    <bean id="person7" class="com.zy.factory.PersonFactory" factory-method="createPerson" />

测试:
在这里插入图片描述

IOC之工厂实例方法创建Bean

工厂类:

public class PersonFactory1 {
    public  Person createPerson(){
        Person person = new Person();
        person.setId(17);
        person .setName("小脑斧");
        person.setAge(22);
        return person;
    }

配置文件:

<!--    工厂实例方法分两步:-->
<!--    第一步  先使用bean标签配置一个bean对象-->
<!--    第二步 使用bean标签配置factory-bean 和factory-method方法-->
<!--    -->
    <bean id="personfactory" class="com.zy.factory.PersonFactory1"></bean>
<!--        factory-bean表示使用哪一个工厂对象的实现-->
<!--        factory-method表示调用对象的哪一个方法去是实现对象实例-->
    <bean id="person8" factory-bean="personfactory" factory-method="createPerson"/>

测试:
在这里插入图片描述

IOC之FactoryBean接口方式创建对象

创建一个FactoryBean实现对象

public class PersonFactoryBean implements FactoryBean<Person> {
    public Person getObject() throws Exception {
        Person person = new Person();
        person.setId(23);
        person.setName("我是由factorybean接口创建出来的");
        person.setAge(22);
        return person;
    }
    public Class<?> getObjectType() {
        return Person.class;
    }
/**
 * 功能描述: 是否是单例模式,tue表示单例,false表示多例
 * @Date:   2020/8/18
 * @Param:  []
 * @Return: boolean
 * @Author: Tiger
 */
    public boolean isSingleton() {
        return true;
    }
}

配置文件:

   <!-- 使用FactoryBean接口方式创建Bean对象 -->
    <bean id="person9" class="com.zy.factorybean.PersonFactoryBean" />

在这里插入图片描述

IOC之继承Bean配置

配置文件:

<!--    先定义一个bean的person对象-->
    <bean id="base" class="com.zy.entity.Person" P:name="basePerson"/>
<!--    然后在另一个bean中,使用parent继承所有-->
    <bean id="person20" class="com.zy.entity.Person" parent="base" P:id="20"/>

测试:
在这里插入图片描述

ioc总结

小结一下:IoC 在 Spring 里,只需要低级容器就可以实现,2 个步骤:

       ①、加载配置文件,解析成 BeanDefinition 放在 Map 里。

       ②、调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入。

上面就是 Spring 低级容器(BeanFactory)的 IoC。

至于高级容器 ApplicationContext,他包含了低级容器的功能,当他执行 refresh 模板方法的时候,将刷新整个容器的 Bean。同时其作为高级容器,包含了太多的功能。一句话,他不仅仅是 IoC。他支持不同信息源头,支持 BeanFactory 工具类,支持层级容器,支持访问文件资源,支持事件发布通知,支持接口回调等等。

可以预见,随着 Spring 的不断发展,高级容器的功能会越来越多。

诚然,了解 IoC 的过程,实际上为了了解 Spring 初始化时,各个接口的回调时机。例如 InitializingBean,BeanFactoryAware,ApplicationListener 等等接口,这些接口的作用,笔者之前写过一篇文章进行介绍,有兴趣可以看一下,关键字:Spring 必知必会 扩展接口。

但是请注意,实现 Spring 接口代表着你这个应用就绑定死 Spring 了!代表 Spring 具有侵入性!要知道,Spring 发布时,无侵入性就是他最大的宣传点之一 —— 即 IoC 容器可以随便更换,代码无需变动。而现如今,Spring 已然成为 J2EE 社区准官方解决方案,也没有了所谓的侵入性这个说法。

参考:简易手动实现aop和ioc

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值