Spring 学习笔记

Spring Node

概述

  • 目的: 解决企业应用开发的复杂性
  • 功能: 使用基本的JavaBean代替EJB(Enterprise Service Bus,), 并提供更多的企业应用功能
    • ESB提供了连接企业内部及跨企业间新的和现有软件应用程序的功能,以一组丰富的功能启用管理和监控应用程序之间的交互。
  • 范围: 任何范围的Java应用

特性

  1. 非嵌入式: 基于Spring开发的应用中的对象可以不依赖Spring的API
  2. 控制反转(Ioc): 对象由Spring去创建, 不需要程序员去new
  3. 依赖注入(DI): 依赖的对象不需要手动调用setXXX()方法去设置, 而是通过配置赋值
  4. 面向切面(AOP)
  5. Spring是一个容器, 其包含并且管理应用对象的生命周期
  6. 组件化: Spring可以实现使用简单的组件配置组合成衣蛾复杂的应用
  7. 一站式: 在IoC和AOP的基础上可以整合各种企业应用的开源框架和第三方类库
  • 总结: Spring是一个轻量级控制反转(IOC)和面向切面(AOP)的容器框架

三层架构

  • 表现层 --> web层 (MVC是表现层的一个设计模型)
  • 业务层 --> service层
  • 持久层 --> dao层

体系结构

核心容器

核心容器由 spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OMDKhMAC-1623500113933)(https://i.loli.net/2021/03/20/z2keoLWXZ9r1iIx.png)]

  • Spring-core模块提供了框架的基本组成部分, 包括IoC和依赖注入
  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦
  • context 模块建立在由 core和 beans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。
  • spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。

其完整的依赖关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KPmzazgm-1623500113948)(https://i.loli.net/2021/03/28/UsuicNKYH29k3Me.png)]

拓展:

  • Spring Boot:

    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速开发单个微服务
  • Spring Cloud

    • SpringCloud 是基于SpringBoot实现的微服务开发框架

依赖:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.3</version>
</dependency>

IoC 容器

容器将创建对象, 把它们连接在一起, 配置它们, 并管理它们的在整个生命周期.
通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML,Java 注释或 Java 代码来表示。

IOC理论推导

不使用Spring框架实现一个业务的准备工作:

  1. UserDao 接口
  2. UserDaoImpl 实现类
  3. UserService 业务接口
  4. UserServiceImpl 业务实现

弊端: 用户的需求可能会影响原来的代码, 如果直接根据用户需求去修改原来的代码, 在大型项目中, 这种修改成本非常昂贵

IoC的本质

控制反转IoC(Inversion of Control)是一种设计思想, DI(依赖注入)是实现IoC的一种方法, 没有IoC的程序中, 我们使用面向对象编程, 对象的创建与对象间的依赖完全写在程序中, 对象的创建由程序自己控制, 控制反转后将对象的创建转移给第三方(所以获得依赖对象的方式反转了)

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式. 在spring中实现控制反转的是Ioc container, 其实现方法是注入依赖(Dependency Injection, DI)

控制: 谁来控制对象的创建, 传统应用程序的对象是由程序本身控制创建的, 使用Spring后,对象由Spring来创建
反转: 程序本身不创建对象, 而变成被动的接收对象

依赖注入: 就是通过setXXX()方法来进行注入的

所以, 对IoC的理解: 对象的来创建, 管理, 装配由Spring来实现

Spring Bean

Bean 是一些被实例化, 组装, 并通过Spring IoC所管理的对象, 这些Bean是由容器提供的配置元数据创建的
Bean 定义常用的属性:

id: Bean 对象的唯一标识符
class: bean 对象所对应的全限定名
name: 别名, 可以同时区多个别名
scope: 指定特定的Bean定义创建对象的作用域

Spring 定义元数据

Spring IoC容器完全由实际编写的配置元数据的格式解耦
把配置元数据提供给Spring容器:

  • 基于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">
    
     <!-- A simple bean definition -->
     <bean id="..." class="...">
         <!-- collaborators and configuration for this bean go here -->
     </bean>
    
     <!-- A bean definition with lazy init set on -->
     <bean id="..." class="..." lazy-init="true">
         <!-- collaborators and configuration for this bean go here -->
     </bean>
    
    
  • 基于注解的配置

  • 基于Java的配置

Spring Bean 的作用域

作用域描述
singleton(default)在Spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境

Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton 作用域是 Spring 中的缺省作用域

Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象

Spring Bean 生命周期

初始化回调

<bean id="exampleBean" 
         class="examples.ExampleBean" init-method="init"/>
         <!-- init是ExampleBean中的一个方法 -->

销毁回调

<bean id="exampleBean"
         class="examples.ExampleBean" destroy-method="destroy"/>
         <!-- destroy是ExampleBean中的一个方法 -->

Spring Bean 定义继承

Spring Bean定义继承于java的继承无关, 但概念是一样的. 可以通过定义一个父Bean的定义作为模板和其他子Bean 就可以从bean中继承所需的配置.

使用基于XML的配置元数据时, 指定父Bean作为该属性的值来表明子Bean的定义

 <bean class="Parent" id="parent" name="parent">
        <property name="message1" value="parent message1"/>
        <property name="message2" value="parent message2"/>
    </bean>

    <!-- 使用parent属性建立Bean之间的继承关系  -->
    <bean class="Child" id="child" name="child" parent="parent">
        <property name="message2" value="child message2"/>
        <property name="message3" value="child message3"/>
   </bean>

</beans>
public class TestMain {
  public static void main(String[] args) {
      ApplicationContext acx = new ClassPathXmlApplicationContext("Bean.xml");

      Parent parent = (Parent) acx.getBean("parent");
      Child child = (Child) acx.getBean("child");

      System.out.println(parent.toString());
      System.out.println(child.toString());

      // Parent{message1='parent message1', message2='parent message2'}
      // Child{message1='parent message1', message2='child message2', message3='child message3'}
  }
}

Spring的核心机制

管理bean

程序主要是通过Spring容器来访问容器中的Bean, ApplicationContext是Spring容器最常用的接口,该interface有以下两个实现类:

  • ClassPathXmlApplicationContext: 从类加载路径下搜索配置文件, 并根据配置文件来创建Spring容器.
  • FileSystemXmlApplicationContext: 从文件系统的相对路径或绝对路径下去搜索配置文件, 并根据配置文件来创建Spring容器
public class TestMain {

    public static void main(String[] args) {

        // 创建Spring上下文(加载bean.xml)得到Spring容器
        ApplicationContext acx = new ClassPathXmlApplicationContext("spring-config.xml");

        // 在Spring容器中获取Student实例
        Student student = acx.getBean("student", Student.class);

        // 调用方法
        System.out.println(student.toString());
    }
}

依赖注入

Spring框架的核心功能:

  • Spring容器作为超级工厂, 负责创建,管理所有的Java对象, 这些对象也就是容器中的Bean
  • Spring容器管理容器中Bean之间的依赖关系, Spring使用"依赖注入"来管理Bean之间的依赖关系

依赖注入:

  • 依赖: Bean对象的创建依赖于容器
  • 注入: Bean对象中的所有属性值, 由容器注入

使用依赖注入, 不仅可以为Bean注入普通的属性值, 还可以注入其他Bean之间的依赖关系
依赖注入是一种优秀的解耦方式, 其可以让Bean以配置文件组织在一起, 而不是以硬编码的方式耦合在一起

依赖注入的方式:

类型描述
Constructor-based dependency injection当容器调用带有多个参数的构造函数类时,实现基于构造函数的 DI,每个代表在其他类中的一个依赖关系
Setter-based dependency injection基于 setter 方法的 DI 是通过在调用无参数的构造函数或无参数的静态工厂方法实例化 bean 之后容器调用 beans 的 setter 方法来实现的

Spring 基于构造函数的依赖注入

  1. 使用无参构造器创建

  2. 使用有参构造

     <!--  通过无参构造创建(必须声明类的无参构造函数)  -->
    <bean class="com.example.Human" id="human" name="human"/>
    
    <!--  通过参数类型传递参数  -->
    <bean class="com.example.Human" id="human1" name="human1">
        <constructor-arg type="String" value="张三"/>
        <constructor-arg type="int" value="18"/>
    </bean>
    <bean class="com.example.Student" id="student" name="student">
        <constructor-arg ref="human" />
        <constructor-arg name="age" value="1"/>
    </bean>
    
    
    <!--  通过索引传入参数值(注意从零开始)  -->
    <bean class="com.example.Human" id="human2" name="human2">
        <constructor-arg index="0" value="张三"/>
        <constructor-arg index="1" value="18"/>
    </bean>
    
    
    <!--  通过参数名称传入参数值  -->
    <bean class="com.example.Human" id="human3" name="human3">
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="18"/>
    </bean>
    

使用这种方式, 使用的类必须要定义构造函数

Spring 基于设值函数的依赖注入

 <bean class="example.Human" id="human1">
        <property name="name" value="张三"/>
        <property name="age" value="18"/>
    </bean>

    <bean class="example.Student" id="student1">
        <property name="human" ref="human1" />
        <property name="age" value="18" />
    </bean>

    <!-- 简写(注意 P 需要在beans 里面定义) -->
    <!--  xmlns:p="http://www.springframework.org/schema/p" -->
    <bean class="example.Student" id="student2"
        p:human-ref="human1"
        p:age="20" />

使用这种方式注入依赖, 使用的类必须定义setter方法

两种依赖注入方式的对比

唯一的区别就是在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素,而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素

Spring 注入集合

 <!-- Definition for javaCollection -->
   <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">

      <!-- results in a setAddressList(java.util.List) call -->
      <property name="addressList">
         <list>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
         </list>
      </property>

      <!-- results in a setAddressSet(java.util.Set) call -->
      <property name="addressSet">
         <set>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
        </set>
      </property>

      <!-- results in a setAddressMap(java.util.Map) call -->
      <property name="addressMap">
         <map>
            <entry key="1" value="INDIA"/>
            <entry key="2" value="Pakistan"/>
            <entry key="3" value="USA"/>
            <entry key="4" value="USA"/>
         </map>
      </property>

      <!-- results in a setAddressProp(java.util.Properties) call -->
      <property name="addressProp">
         <props>
            <prop key="one">INDIA</prop>
            <prop key="two">Pakistan</prop>
            <prop key="three">USA</prop>
            <prop key="four">USA</prop>
         </props>
      </property>

   </bean>

Spring Bean 自动装配

  • 使用autowire="byName" 自动装配: 这种模式由属性名称指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

      <bean class="example.Human" id="human1">
          <property name="name" value="张三"/>
          <property name="age" value="18"/>
      </bean>
      <bean class="example.Student" id="student1">
          <property name="human" ref="human1" />
          <property name="age" value="18" />
      </bean>
      
      <!-- 使用byName自动装配 -->
      <bean class="example.Human" id="human2" name="human">
          <property name="name" value="张三"/>
          <property name="age" value="18"/>
      </bean>
      <bean class="example.Student" id="student2" autowire="byName">
          <property name="age" value="18" />
      </bean>
    
  • 使用autowire="byType" 自动转配: 这种模式由属性类型指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

    <!-- 使用byType自动装配 -->
      <bean class="example.Human" id="human">
          <property name="name" value="张三"/>
          <property name="age" value="18"/>
      </bean>
      <bean class="example.Student" id="student3" autowire="byType">
          <property name="age" value="18" />
      </bean>
    

Spring 基于注解的配置

使用注解来配置依赖注入, 可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。

别名

<alias>

Bean的配置

import

用于导入多个xml文件, 将各个文件中的bean合并

结尾

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值