您的位置:首页 > 编程语言 > Java开发

Spring IoC

2021-12-02 21:04 573 查看

[TOC]


Spring 介绍

框架的作用

Spring 是什么?

Spring 体系结构

Spring 发展历史

Spring 优势

  • 方便解耦,简化开发
  • 方便集成各种优秀框架
  • 方便程序的测试
  • AOP 编程的支持
  • 声明式事务的支持
  • 降低 JavaEE API 的使用难度
  • Java 源码是经典学习范例

IoC 介绍

耦合与内聚

  • 耦合(Coupling)
    :代码书写过程中所使用技术的结合紧密度,用于衡量软件中各个模块之间的互联程度。

  • 内聚(Cohesion)
    :代码书写过程中单个模块内部各组成部分间的联系,用于衡量软件中各个功能模块自身内部的功能联系。

程序书写的目标:

高内聚,低耦合
。即同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密。

工厂模式发展史

Spring 发展历程

IoC 概念

  • IoC(Inversion Of Control)控制反转:Spring 反向控制应用程序所需要使用的外部资源。

  • Spring 控制的资源全部放置在 Spring 容器中,该容器称为 IoC 容器。

DI 概念

  • DI(Dependency Injection)依赖注入:应用程序运行依赖的资源由 Spring 为其提供,资源进入应用程序的方式称为注入。

  • IoC 与 DI 的关系:同一件事站在不同角度看待问题。


入门案例

模拟三层架构中,表现层调用业务层功能。案例步骤如下:

1)导入 spring 坐标

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>

2)编写业务层接口与实现类:

  • UserService.java
public interface UserService {

// 业务方法
void save();
}
  • UserServiceImpl.java
import com.service.UserService;

public class UserServiceImpl implements UserService {

@Override
public void save() {
System.out.println("UserService running...");
}
}

3)创建 spring 配置文件:配置所需资源(UserService)为 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 创建spring控制的资源 -->
<bean id="userService" class="com.service.impl.UserServiceImpl"/>

</beans>

4)表现层(UserApp)通过 Spring 获取资源(Service 实例)

import com.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {

public static void main(String[] args) {
// 加载配置文件,创建Spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取资源
UserService userService = (UserService)context.getBean("userService");
userService.save();
}
}

IoC 配置

bean 标签

  • 类型:标签

  • 归属:beans 标签

  • 作用:定义 spring 中的资源,受此标签定义的资源将受到 spring 控制

  • 基本属性:

    id
    :bean 的名称,通过 id 值获取 bean 。
  • class
    :bean 的类型。
  • name
    :bean 的名称,可以通过 name 值获取 bean,用于多人配合时给 bean 起别名。
  • 示例:

  • <beans>
    <bean id="beanId" name="beanName1,beanName2" class="ClassName" />
    </beans>

    scope 属性

    • 类型:属性

    • 归属:bean标签

    • 作用:定义 bean 的作用范围

    • 示例:

    <!-- scope用于控制bean创建后的对象是否是单例的 -->
    <bean id="userService" scope="prototype" class="com.service.impl.UserServiceImpl" />
    • 取值:
      singleton
      :设定创建出的对象保存在 spring 容器中,是一个单例的对象。
    • prototype
      :设定创建出的对象不保存在 spring 容器中,是一个非单例的对象。
    • request、session、application、websocket(四者不常用):设定创建出的对象放置在 web 容器对应的位置。

    bean 生命周期配置

    • 名称:init-method,destroy-method

    • 类型:属性

    • 归属:bean 标签

    • 作用:定义 bean 对象在初始化或销毁时完成的工作

    • 示例:

    <!-- inti-method 与 destroy-method 用于控制 bean 的生命周期 -->
    <bean id="userService" scope="prototype" init-method="init" destroy-method="destroy" class="com.service.impl.UserServiceImpl" />
    • 取值:

      当 scope="singleton" 时,spring 容器中有且仅有一个对象,init 方法在创建容器时仅执行一次。

    • 当 scope="prototype" 时,spring 容器要创建同一类型的多个对象,init 方法在每个对象创建时均执行一次。

    • 当 scope="singleton" 时,关闭容器会导致 bean 实例的销毁,调用 destroy 方法一次。

    • 当 scope="prototype" 时,对象的销毁由垃圾回收机制 gc() 控制,destroy 方法将不会被执行。


    set 方法注入 bean(主流方式)

    • 名称:property

    • 类型:标签

    • 归属:bean 标签

    • 作用:使用 set 方法的形式为 bean 提供资源

    • 示例:

    <bean>
    <property name="propertyName" value="propertyValue" ref="beanId"/>
    </bean>
    • 基本属性:

      name
      :对应 bean 中的属性名,要求该属性必须提供可访问的 set 方法(严格规范为此名称是 set 方法对应名称)

    • value
      :设定非引用类型属性对应的值,不能与 ref 同时使用。

    • ref
      :设定引用类型属性对应 bean 的 id ,不能与value同时使用。

  • 注意:一个 bean 可以有多个 property 标签。

  • 代码示例:

    • UserDaoImpl.java:
    public void save(){
    System.out.println("user dao running...");
    }
    • UserServiceImpl.java:
    import com.dao.UserDao;
    import com.service.UserService;
    
    public class UserServiceImpl implements UserService {
    
    private UserDao userDao;
    private int num;
    
    // 对需要进行注入的变量(基本数据类型)添加set方法
    public void setNum(int num) {
    this.num = num;
    }
    
    // 对需要进行注入的变量(引用数据类型)添加set方法
    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }
    
    public void save() {
    System.out.println("user service running..." + num);  // user dao running...666
    userDao.save();  // user dao running...
    }
    }
    • applicationContext.xml:
    <bean id="userService" class="com.service.impl.UserServiceImpl">
    <!-- 2. 将要注入的引用类型的变量通过property属性进行注入,对应的name是要注入的变量名,使用ref属性声明要注入的bean的id -->
    <property name="userDao" ref="userDao"/>
    <property name="num" value="666"/>
    </bean>
    
    <!-- 1. 将要注入的资源声明为bean -->
    <bean id="userDao" class="com.dao.impl.UserDaoImpl"/>

    集合类型数据注入

    • 名称:array、list、set、map、props

    • 类型:标签

    • 归属:property 标签或 constructor-arg 标签

    • 作用:注入集合数据类型属性

    示例:

    • BookDaoImpl.java:
    package com.dao.impl;
    
    import com.dao.BookDao;
    
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    import java.util.Set;
    
    public class BookDaoImpl implements BookDao {
    
    private List al;
    private Properties properties;
    private int[] arr;
    private Set hs;
    private Map hm ;
    
    public void setAl(List al) {
    this.al = al;
    }
    
    public void setProperties(Properties properties) {
    this.properties = properties;
    }
    
    public void setArr(int[] arr) {
    this.arr = arr;
    }
    
    public void setHs(Set hs) {
    this.hs = hs;
    }
    
    public void setHm(Map hm) {
    this.hm = hm;
    }
    
    @Override
    public void save() {
    System.out.println("book dao running...");
    System.out.println("ArrayList:"+al);
    System.out.println("Properties:"+properties);
    for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
    }
    System.out.println("HashSet:"+hs);
    System.out.println("HashMap:"+hm);
    }
    }
    • UserServiceImpl.java:
    package com.service.impl;
    
    import com.dao.BookDao;
    import com.service.UserService;
    
    public class UserServiceImpl implements UserService {
    
    private BookDao bookDao;
    
    public UserServiceImpl() {
    }
    
    public UserServiceImpl(BookDao bookDao) {
    this.bookDao = bookDao;
    }
    
    public void setBookDao(BookDao bookDao) {
    this.bookDao = bookDao;
    }
    
    @Override
    public void save() {
    bookDao.save();
    }
    
    }
    • 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
    https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 创建spring控制的资源 -->
    <bean id="userService" class="com.service.impl.UserServiceImpl">
    <property name="bookDao" ref="bookDao"/>
    </bean>
    
    <bean id="bookDao" class="com.dao.impl.BookDaoImpl">
    <property name="al">
    <list>
    <value>value1</value>
    <value>value2</value>
    </list>
    </property>
    <property name="properties">
    <props>
    <prop key="name">xiaoming</prop>
    <prop key="age">17</prop>
    </props>
    </property>
    <property name="arr">  <!-- 不常用 -->
    <array>
    <value>12</value>
    <value>34</value>
    </array>
    </property>
    <property name="hs">  <!-- 不常用 -->
    <set>
    <value>value1</value>
    <value>value2</value>
    </set>
    </property>
    <property name="hm">  <!-- 不常用 -->
    <map>
    <entry key="name" value="xiaoming"/>
    <entry key="age" value="19"/>
    </map>
    </property>
    </bean>
    
    </beans>
    • UserApp.java(控制层):
    package com.servlet;
    
    import com.service.UserService;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class UserApp {
    
    public static void main(String[] args) {
    // 加载配置文件
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 获取资源
    UserService userService = (UserService)context.getBean("userService");
    userService.save();
    }
    }
    • 执行结果:
    book dao running...
    ArrayList:[value1, value2]
    Properties:{age=17, name=xiaoming}
    12
    34
    HashSet:[value1, value2]
    HashMap:{name=xiaoming, age=19}

    加载 properties 文件

    Spring 提供了读取外部 properties 文件的机制,使用读取到的数据为 bean 的属性赋值。

    • resource 目录下的 data.properties:
    username=xiaoming
    password=admin123
    • 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 1.加载context命名空间的支持 -->
    <!-- xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    -->
    <!-- 2.加载配置文件:*表示加载全部文件 -->
    <context:property-placeholder location="classpath:*.properties"/>
    
    <!-- 创建spring控制的资源 -->
    <bean id="userService" class="com.service.impl.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
    </bean>
    
    <bean id="userDao" class="com.dao.impl.UserDaoImpl">
    <!-- 读取数据使用 ${propertiesName} 格式进行,其中 propertiesName 指 properties 文件中的属性值 -->
    <property name="userName" value="${username}"/>
    <property name="password" value="${password}"/>
    </bean>
    
    </beans>
    • UserDaoImpl.java:
    package com.dao.impl;
    
    import com.dao.UserDao;
    
    public class UserDaoImpl implements UserDao {
    
    private String userName;
    private String password;
    
    public void setUserName(String userName) {
    this.userName = userName;
    }
    
    public void setPassword(String password) {
    this.password = password;
    }
    
    @Override
    public void save() {
    System.out.println("userDao running:"+userName+" "+password);
    }
    }
    • UserServiceImpl.java:
    package com.service.impl;
    
    import com.dao.BookDao;
    import com.dao.UserDao;
    import com.service.UserService;
    
    public class UserServiceImpl implements UserService {
    
    private UserDao userDao;
    
    public UserServiceImpl() {
    }
    
    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }
    
    @Override
    public void save() {
    userDao.save();
    }
    
    }
    • UserApp.java(控制层):
    package com.servlet;
    
    import com.service.UserService;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class UserApp {
    
    public static void main(String[] args) {
    // 加载配置文件
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 获取资源
    UserService userService = (UserService)context.getBean("userService");
    userService.save();
    }
    }
    • 运行结果:
    userDao running:juno admin123

    团队开发:import 导入配置文件

    • 名称:import

    • 类型:标签

    • 归属:beans 标签

    • 作用:在当前配置文件中导入其他配置文件中的项

    示例:在 applicationContext.xml 中加载其他配置文件

    <import resource="applicationContext-user.xml"/>
    <import resource="applicationContext-book2.xml"/>
    <import resource="applicationContext-book.xml"/>

    Spring 容器加载多个配置文件

    new ClassPathXmlApplicationContext("config1.xml", "config2.xml");

    Spring 容器中 bean 定义冲突问题

    • 同 id 的 bean,后定义的覆盖先定义的。

    • 导入配置文件可以理解为将导入的配置文件复制粘贴到对应位置。

    • 导入配置文件的顺序与位置不同可能会导致最终程序运行结果不同。


    ApplicationContext 分析

    1. ApplicationContext 是一个接口,提供了访问 Spring 容器的 API 。

    2. ClassPathXmlApplicationContext 是一个类,实现了上述功能。

    3. ApplicationContext 的顶层接口是 BeanFactory 。

    4. BeanFactory 定义了 bean 相关的最基本操作。

    5. ApplicationContext 在 BeanFactory 基础上追加了若干新功能。

    ApplicationContext 对比 BeanFactory

    1. BeanFactory 创建的 bean 采用延迟加载形式,使用才创建;

    2. ApplicationContext 创建的 bean 默认采用立即加载形式。

    FileSystemXmlApplicationContext

    可以加载文件系统中任意位置的配置文件,而 ClassPathXmlApplicationContext 只能加载类路径下的配置文件。

    示例:BeanFactory 创建 Spring 容器

    Resource res = new ClassPathResource("applicationContext.xml");
    BeanFactory bf = new XmlBeanFactory(res);
    UserService userService = (UserService)bf.getBean("userService");

    案例:整合 Mybatis

    案例工程地址

    案例介绍

    使用 Spring 整合 Mybatis 技术,完成账户模块(Account)的基础增删改查功能。

    账户模块对应字段:

    • 编号:id
    • 账户名:name
    • 余额:money

    案例分析

    非 Spring 环境:

    1. 实体类与表
    2. 业务层接口与实现
    3. 数据层接口
    4. Mybatis 核心配置
    5. Mybatis 映射配置
    6. 客户端程序测试功能

    Spring 环境:

    1. 实体类与表
    2. 业务层接口与实现(提供数据层接口的注入操作)
    3. 数据层接口
    4. Mybatis 核心配置(交给 Spring 控制,该文件省略)
    5. Mybatis 映射配置
    6. 客户端程序测试功能(使用 Spring 方式获取 bean)
    7. Spring 核心配置文件
    8. Druid 连接池(可选)
    9. Spring 整合 MyBatis

    基础准备工作

    • 环境准备

        导入 Spring 坐标、MyBatis 坐标、MySQL 坐标、Druid 坐标
    • 业务类与接口准备

        创建数据库表,并制作相应的实体类 Account

      1. 定义业务层接口与数据层接口

      2. 在业务层调用数据层接口,并实现业务方法的调用

    • 基础配置文件

        jdbc.properties

      1. MyBatis 映射配置文件

    整合准备工作

    1. Spring 配置文件,加上 context 命名空间,用于加载 properties 文件

    2. 开启加载 properties 文件

    3. 配置数据源 druid(备用)

    4. 定义 service 层 bean,注入 dao 层 bean

    5. dao 的 bean 无需定义,使用代理自动生成

    整合工作

    整合工作:

    1. 导入 Spring 整合 MyBatis 坐标

    2. 将 mybatis 配置成 spring 管理的 bean(SqlSessionFactoryBean)

        将原始配置文件中的所有项,转入到当前配置中

      • 数据源转换

      • 映射转换

    3. 通过 spring 加载 mybatis 的映射配置文件到 spring 环境中

    4. 设置类型别名

    测试结果:

    1. 使用 spring 环境加载业务层 bean,执行操作
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: