Spring 框架(Spring Framework)概述及 IOC(控制反转)详解

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: Spring 框架(Spring Framework)概述及 IOC(控制反转)详解

概述

Spring 体系概述

  • Spring 是于2003年兴起的一个 full-stack 轻量级的 Java 开源框架,由 Rod Johnson 创建,使用 Spring 可以更快、更轻松、更安全地进行 Java 编程
  • Spring 是一个生态体系,或一个超级粘合平台,常见的 Spring 项目有:Spring Boot,Spring Framework,Spring Data,Spring Cloud,Spring Cloud Data Flow,Spring Security,Spring GraphQL,Spring Session 和 Spring Web Services 等
  • Spring 提供了展现层 Spring MVC、持久层 Spring JDBC、业务层事务管理等众多的企业级应用技术,Spring 还能整合开源世界众多的第三方框架和类库,逐渐成为使用最多的 Java EE企业应用开源框架
  • Spring 并不等同于 Spring 框架(Spring Framework),这是常见的误区


Spring 框架(Spring Framework)

概述

  • Spring 框架,即 Spring Framework 框架,是 Spring 生态的其中一个重要项目,也是其他 Spring 全家桶(SpringMVC、SpringBoot、SpringCloud、SpringData等)的基础和核心
  • Spring 框架分为多个模块,应用程序可以选择需要的模块。Spring 框架的核心是 Core Container(核心容器)模块,包括配置模型和依赖注入机制
  • Spring 框架为不同的应用程序架构提供基础支持,包括消息传递、事务数据和持久性以及 Web
  • Spring 框架还包括基于 Servlet 的 Spring MVC Web 框架,以及并行的 Spring WebFlux 反应式 Web 框架
  • Spring 框架是分层的JavaSE/EE一站式轻量级开源框架,以 IOC(控制反转)和 AOP (面向切面编程)为核心


Spring 框架的特点

  • 方便解耦,简化开发:将所有对象的创建和依赖关系维护交给Spring管理
  • 方便集成各种优秀框架:Spring内部提供了对各种优秀框架(Struts2、Hibernate、MyBatis)的直接支持
  • 降低了Java EE API 使用难度:对 JAVA EE开发中一些API( JDBC、JavaMail、远程调用)都提供了封装
  • 方便程序测试:支持 JUnit4,可以通过注解方便地测试 Spring 程序
  • AOP变成支持:面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能
  • 声明式事务:通过配置就可以完成对事务的管理,无需编程


Spring 框架的架构和模块说明

image-20220324215518020

Spring 框架的主要模块

  • Core Container(核心容器)

    是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成

    • Core(spring-core):封装了Spring框架的底层部分,包括资源访问、类型转换以及Spring 框架基本的核心工具类

      Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,也可以在自己的应用系统中使用这些工具类

      • 外部依赖:Commons Logging, (Log4J)
      • jar包:org.springframework spring-core 4.3.7.RELEASE
    • Beans(spring-beans):提供了框架的基础部分,包括访问配置文件、控制反转(IOC)和依赖注入(DI)

      • 外部依赖:spring-core
      • jar包:org.springframework spring-beans 4.3.7.RELEASE
    • SpEL(spring-expression):提供了强大的表达式语言支持,用于在运行时查询和处理对象图。该语言支持设置和获取属性值;属性赋值,方法调用,访问数组的内容,收集和索引器,逻辑和算术运算,命名变量,并从Spring的IOC容器的名字对象检索,它也支持列表选择和投影以及常见的列表聚合

      • jar包:org.springframework spring-expression 4.3.7.RELEASE
    • Context(spring-context):上下文模块,建立在 Core 和 Beans 模块的基础之上,集成Beans模块并添加资源绑定、数据验证、国际化、Java EE支持、容器生命周期、事件传播等

      为Spring 核心提供了大量扩展。可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。

      • 外部依赖:spring-core,spring-beans,spring-expression,spring-aop
      • jar包:org.springframework spring-context 4.3.7.RELEASE

    依赖关系:

    img

  • Data Access/Integration(数据访问与集成)

    包含模块:JDBC、ORM、OXM、JMS、Transaction

    • JDBC(spring-jdbc):包含对Spring 对JDBC 数据访问进行封装的所有类

      • jar包:org.springframework spring-jdbc 4.3.7.RELEASE
    • ORM(spring-orm):提供了与“对象-关系”映射框架集成的API,包括 JPA、JDO、Hibernate、MyBatis等。
    • OXM(spring-oxm):提供了 Object/XML 映射的抽象层实现,如 JAXB、Castor、XMLBean、JiBX、XStream

      将 java对象映射成为XML数据,或者将 XML 数据映射成java对象

    • JMS(spring-jms):java消息服务,提供了一套“消息生产者、消息消费者”模板,JMS用于两个应用程序之间,或者分布式系统中发送消息,进行异步通信
    • Transaction(spring-tx):事务控制,为JDBC、Hibernate、JDO、JPA、Beans等提供的一致的声明式和编程式事务管理支持

      • jar包:org.springframework spring-tx 4.3.7.RELEASE

    依赖关系:

    img

  • Web

    包括模块:Web、servlet、websocket、portlet

    • Web(spring-web):提供了基本web集成特性,例如:多文件上传、使用 Servlet 监听器的 IOC 容器初始化以及 web 应用上下文

      包含Web 应用开发时,用到Spring 框架时所需的核心类,包括自动载入Web ApplicationContext 特性的类、Struts 与JSF 集成类、文件上传的支持类、Filter 类和大量工具辅助类

      • jar包:org.springframework spring-web 4.3.7.RELEASE
    • servlet(spring-webmvc):提供了 SpringMVC Web 框架实现。SpringMVC 提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等以及一套非常简易的 JSP 标签

      包含Spring MVC 框架相关的所有类,包括框架的Servlets,Web MVC框架,控制器和视图支持

      如果应用使用了独立的MVC 框架,则无需这个JAR 文件里的任何类

      • jar包:org.springframework spring-webmvc 4.3.7.RELEASE
    • WebSocket:提供了简单的接口,用户只需要实现接口就可以快速搭建 websocket server,从而实现双向通讯
    • Portlet(spring-webmvc-portlet):提供了Portlet环境中MVC实现

    依赖关系:

    img

  • AOP、aspects、spring-instrument 、messaging

    aop部分包含4个模块

    • AOP(spring-aop):提供了面向切面编程,提供了比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态把这些功能添加到需要的代码中

      • jar包:org.springframework spring-aop 4.3.7.RELEASE
    • Aspects(spring-aspects):提供与AspectJ的集成,是一个功能强大且成熟的面向切面编程框架

      以便可以方便的将面向方面的功能集成进IDE中,比如Eclipse AJDT

      • jar包:org.springframework spring-aspects 4.3.7.RELEASE
    • InStrumentation(spring-instrument):检测,提供了类工具的支持和类加载器的实现
    • Messaging(消息处理):提供了对消息传递体系结构和协议的支持

    依赖关系:

    img

  • Test:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能。


Spring 框架 的 API 体系

Spring Framework 的API体系异常庞大,暂时只介绍 BeanFactory 和 ApplicationContext:

  • BeanFactory

    • BeanFactory 是 Spring 的"心脏",IOC 容器的核心接口,定义了IOC的基本功能
    • Spring 使用它来配置文档,管理bean的加载,实例化并维护bean之间的依赖关系,负责bean的声明周期
  • ApplicationContext

    • ApplicationContext 由 BeanFactory 派生而来,可以比喻为Spring的躯体
    • ApplicationContext 在 BeanFactory 的基础上添加了很多功能:

      • 支持了 aop 功能和 web 应用
      • MessageSource,提供国际化的消息访问
      • 通过配置来实现 BeanFactory 中很多编码才能实现的功能
    • ApplicationContext 的常用实现类:

      • ClassPathXmlApplicationContext:从classpath目录读取配置文件
      • FileSystemXmlApplicationContext:从文件系统或者url中读取配置文件
      • AnnotationConfigApplicationContext:读取注解。当使用注解配置容器对象时,需要使用此类来创建 spring
        容器

BeanFactory 和 ApplicationContext 的区别:

  • beanFactory 主要是面向 Spring 框架的基础设施,也就是供 spring 自身内部调用

    Applicationcontext 主要面向 Spring 的使用者

  • BeanFactroy 是在第一次使用到某个Bean(调用getBean()方法)时,才对该Bean进行加载实例化

    ApplicationContext 是在容器启动时,一次性创建并加载了所有的Bean

image-20220324220229054


Spring Boot 框架概述

  • Spring Boot 也是 Spring 生态中一个极其重要的项目,Spring Boot 是对 Spring Framework 的扩展,也可以说它是一个服务于框架的框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程
  • Spring Boot 的服务范围是简化配置文件,它消除了设置 Spring 应用程序所需的XML配置,即尽可能的自动配置 Spring 应用
  • Spring Boot 直接嵌入了 Tomcat、Jetty 或 Undertow(无需部署WAR文件),并且提供生产就绪功能,例如指标、运行状况检查和外部化配置等等,为更快和更高效的开发应用程序铺平了道路


IOC(控制反转)

IOC概述、IOC 容器工作原理

IOC(控制反转)是一种设计思想,目的是指导设计出更加松耦合的程序:

  • 控制:指的是对象控制权,在 java 中可以简单理解为对象的控制权限(比如对象的创建、销毁等权限)
  • 反转:指的是将对象的控制权由原来的程序员在类中主动控制反转到由 Spring 容器来控制
  • 主要功能:解耦


Spring IOC 容器 是对 IOC 思想的一种实现:

  • 对象的创建交由 Spring 框架管理,需要对象时从 Spring IOC 容器中获取即可
  • 底层原理:反射


Spring 的 IOC容器 工作原理:

  1. 当 Spring 的 IOC 容器加载时,会读取配置文件中的诸多 bean 配置
  2. 根据 bean 的 class 的值寻找对应的 Class 字节码文件
  3. 通过反射技术,创建出一个个对象
  4. 创建的对象会被存放到内部的一个 Map 结构中,等待被使用
  5. 当需要使用具体的对象时就无须手动创建,而是直接从 Spring 的IOC容器中


Spring IOC 的入门案例(xml)

案例:通过Spring中内置的容器获取对象

操作步骤:

  • 创建工程导入依赖
  • 配置接口和实现类
  • 编写Spring的配置文件
  • 测试:从容器中获取对象

创建工程导入依赖

    <dependencies>
        <!--spring的坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

创建Dao接口和实现类(略)

创建Spring配置文件

  • spring配置文件约定俗称:applicationContext.xml
  • spring配置文件放置到:resource目录下
  • spring配置文件,需要引入名称空间(约束)
  • 在spring的配置文件中通过 <bean>标签,定义对象id和实现类全类名

在resource目录下创建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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <!--
        定义配置信息
            id:唯一标志(获取的时候,调用容器的getBean("id"))
            class:实现类的全限定类名
    -->
    <!--把数据库连接池对象放入IOC容器-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <!--把QueryRunner放入到IOC容器中-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="dataSource"/>
    </bean>
    <!--把dao对象交给IOC容器-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="queryRunner" ref="queryRunner"/>
    </bean>
    <!--把service交给IOC容器-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
</beans>

测试

import cn.test.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 测试从容器中获取对象
 */
public class UserDaoTest {

    public static void main(String[] args) {
        //1、根据配置文件获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、调用容器的方法,获取对象
        UserDao userDao = (UserDao)ac.getBean("userDao");
        //3、测试
        userDao.save();
    }
}

执行过程分析

image-20200720114143623

初始化 Spring Bean 对象(xml)

方式1:默认无参构造函数

IOC容器通过反射调用,根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。

<bean id="userDao" class="cn.test.dao.impl.UserDaoImpl"></bean>


方式2:工厂模式创建对象

在Spring中还可以通过工厂模式来创建对象。工厂模式又分两种:

  • 静态工厂:不产生工厂的实例,直接调用工厂的静态方法创建对象
  • 实例工厂:先产生工厂的实例,再调用工厂实例的方法创建对象

(1)java代码编写工厂类

public class FactroyCreateBean {
    // 静态工厂
    public static UserDao createUserDao(){
        return new UserDaoImpl();
    }
    // 实例工厂
    public UserDao createUserDaoSimple(){
        return new UserDaoImpl();
    }
}

(2)xml配置文件配置

<!--使用静态工厂创建对象-->
<bean id="userDao1" class="cn.test.factory.FactroyCreateBean" factory-method="createUserDao"/>
<!--使用实例工厂创建对象-->
<bean id="factroyCreateBean" class="cn.test.factory.FactroyCreateBean"/>
<bean id="userDao2" factory-bean="factroyCreateBean" factory-method="createUserDaoSimple"/>


Spring Bean 的生命周期

概述、生命周期流程图

Bean对象生命周期指的是Bean创建到销毁的这么一段时间。

粗粒度生命周期:

  • spring中单例对象的生命周期为:

    出生:IOC容器加载时出生

    存活:IOC容器运行时存活

    死亡:IOC容器销毁时死亡

  • spring中多例对象的生命周期为:

    出生:使用对象时出生

    存活:一直存活

    死亡:由java垃圾回收器负


细粒度生命周期:

出生过程

  1. 实例化bean对象【IOC】
  2. 为对象属性赋值【DI】
  3. 处理实现的Aware接口

    ① 如果这个Bean已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String beanId) 方法,此处传递的就是Spring配置文件中Bean的id值。

    ② 如果这个Bean已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory() 方法,传递的是Spring工厂自身。

    ③ 如果这个Bean已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext(ApplicationContext) 方法,传入Spring上下文。

  4. 通过 BeanPostProcessor 接口的 postProcessBeforeInitialization 方法对bean对象进行预处理
  5. 通过 InitializingBean 接口的 afterPropertiesSet 方法对bean对象进行处理
  6. 通过指定 init-method 方法对bean对象进行处理
  7. 通过 BeanPostProcessor 接口的 postProcessAfterInitialization 方法对bean对象进行后处理,这一步bean对象已经彻底创建成功了,可以做一些类似缓存的工作

死亡过程

  1. 如果Bean实现了 DisposableBean 接口,会调用其实现的 destroy() 方法。
  2. 如果指定 destroy-method 方法,可以在bean对象销毁前自动执行。

生命周期流程图

image-20220326135037855

测试案例:

public class UserDaoImpl implements UserDao, BeanNameAware, BeanFactoryAware,ApplicationContextAware, InitializingBean, DisposableBean {
    public UserDaoImpl() {
        System.out.println("IOC");
    }
    
    private Integer id;
        public void setId(Integer id) {
        System.out.println("DI");
        this.id = id;
    }
    
    @Override
    public void setBeanName(String s) {
        System.out.println("BeanNameAware:"+s);
    }
    
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware");
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean的afterPropertiesSet");
    }

    public void initMethod(){
        System.out.println("init-method");
    }
    
    @Override
    public void save() {
        System.out.println("保存成功!");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean的destroy");
    }
    
    public void destroyMethod(){
        System.out.println("destroy-method");
    }
}
public class MyBeanProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor的before");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor的after");
        return bean;
    }
}
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="initMethod" destroy method="destroyMethod">
        <property name="id" value="1"/>
    </bean>
    <bean class="com.itheima.processor.MyBeanProcessor"/>
</beans>
// 测试类
public class UserDaoImplTest {
    @Test
    public void save() {
        ClassPathXmlApplicationContext ac = new
        ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = ac.getBean(UserDao.class);
        userDao.save();
        ac.close();
    }
}


Spring Bean 的作用域

参考:https://blog.csdn.net/weixin_38676276/article/details/90382350

  • singleton:单例。在Spring IOC容器中仅存在一个共享的Bean实例。默认值

    当spring创建applicationContext容器的时候,spring会初始化所有的该作用域实例,加上lazy-init则可以避免预处理

  • prototype:原型(多例)

    每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()相当于执行new XxxBean()

    创建后spring将不再对其管理

    (下面是在web项目下才用到的作用域)

  • request:仅在当前HTTP request内有效

    每次HTTP请求都会创建一个新的Bean

    spring创建后会继续监听,当处理请求结束后销毁实例

  • session:仅在当前HTTP Session内有效

    同一个HTTP Session共享一个Bean,不同Session使用不同Bean

    spring创建后会继续监听,当HTTP Session最终被废弃时,在该HTTP Session作用域内的bean也会被废弃掉

  • global-session:全局的web域。类似于servlet中的application。一般用于Portlet应用环境


定义 Bean 的配置信息(xml)

  • id:唯一标志(获取的时候,调用容器的getBean("id"))
  • class:实现类的全限定类名
  • scope:对象作用域(singleton(默认) | prototype | request | session | global-session)
  • init-method:对象创建成功之后,指定的初始化方法
  • destroy-method:容器关闭对象销毁之前,执行的销毁方法

    只有在scope=singleton(单例)的时候,才有效

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" scope="prototype" 
      init-method="init" destroy-method="destroy"/>


依赖注入(xml)

依赖注入:Dependency Injection(DI)。 它是 spring 框架核心 IOC 的具体实现。在编写程序时, 通过控制反转,把对象的创建交给了 spring,然后在代码中需要对象时,进行依赖对象的注入。

IOC 具有两个功能:依赖查找,依赖注入

本质:向对象中的私有属性赋值

  • 构造方法
  • set方法调用


构造方法注入

  • 向对象中添加有参构造方法
public class UserServiceImpl implements UserService {

    private String name;
    private Integer age;

    public UserServiceImpl(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void save() {
        System.out.println(name + age);
    }
}
  • 在spring的配置文件中,通过bean标签配置对象创建(需要添加构造方法参数)
    <!--
        constructor-arg 设置对象的构造方法参数 (一个参数配置一个constructor-arg标签)
            name:构造参数名
            type:构造参数类型
            index:构造参数,参数索引位置(从0开始)
            以上三个属性,用于定位构造方法参数位置(三选一即可)
            value: 对基本数据类型的参数赋值(8大数据类型 + String)
            ref: 对对象属性的参数赋值。即必须得是在配置文件中配置过的bean
            以上两个属性,用于对构造参数赋值
     -->
    <bean id="userService" class="cn.test.service.impl.UserServiceImpl">
        <constructor-arg name="age" value="12"></constructor-arg>
        <constructor-arg name="name" value="王者荣耀"></constructor-arg>
    </bean>


set 方法注入

  • 提供属性的set方法
  • 在spring配置文件中,通过bean结合property配置set方法调用

    <bean id="book" class="com.itheima.spring.Book">
        <!--    name:找的是类中 set 方法后面的部分
                ref:给属性赋值(其他bean类型)
                value:给属性赋值(8大基本数据类型 + string类型)
        -->
        <property name="name" value="程序员" />
        <property name="price" value="1" />
        <property name="publishDate" ref="date" />
    </bean>


注入复杂类型(集合)

给类中的集合成员传值,它用的也是 set方法注入的方式,只不过变量的数据类型都是集合。 这里介绍注入数组、List、Set、Map、Properties。

(1) 注入数组数据

配置set方法

public class UserServiceImpl implements UserService {

    /**
     * 注入数组(array数组,list集合,set集合)
     */
    private String [] names;
    private List<String> lists;
    private Set<String> sets;

    public void setNames(String[] names) {
        this.names = names;
    }

    public void setLists(List<String> lists) {
        this.lists = lists;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }

    @Override
    public void save() {
    }
}

spring配置文件

<bean id="book" class="com.itheima.spring.Book">
    <!-- List -->
    <property name="list">
        <list>
            <value>1</value>
            <value>2</value>
        </list>
    </property>

    <!--Set-->
    <property name="set">
        <set>
            <value>3</value>
            <value>4</value>
        </set>
    </property>

    <!--数组-->
    <property name="array">
        <array>
            <value>5</value>
            <value>6</value>
        </array>
    </property>

    <!--Map-->
    <property name="map">
        <map>
            <entry key="7" value="7-1" />
            <entry key="8" value="8-1" />
        </map>
    </property>

    <!--Properties-->
    <property name="properties">
        <props>
            <prop key="9">9-1</prop>
            <prop key="10">10-1</prop>
        </props>
    </property>
</bean>


Spring 框架中的注解配置

介绍、注解和 xml 配置对应关系

  • 注解和 xml 是Spring提供的两种配置形式,二者的功能是完全一样的,都是要降低程序间的耦合
  • 注解的好处是配置简单,xml的好处是修改配置不用改动源码,企业开发中两种方式灵活使用
  • Spring中注解配置

    1. 注解 + xml 配置(开启注解的功能支持)
    2. 纯注解(Spring Boot + cloud))
  • 注意:在spring中使用注解开发,需要开启注解的功能支持(ioc注解,aop注解,事务注解)


注解和xml配置对应关系

xml配置 注解配置 说明
< bean id="" class="" > @Component @Controller @Service @Repository 将类的实例化对象放入Spring容器管理
< property name="" ref=""> @Autowired @Qualifier @Resource 从Spring容器中获取对象注入属性
< property name="" value=""> @Value bean的简单属性注入
< bean scope=""> @Scope 控制bean的作用范围
< bean init-method="init"
destroy method="destory" />
@PostConstruct @PreDestroy bean创建之后和销毁之前分别调用的方法


开启包扫描(开启 IOC 注解支持)

开启包扫描(即 开启对 IOC 注解的支持):

  1. 扫描指定包下的所有 java 类中的 Spring 注解
  2. 如果扫描到类上有 IOC 注解,就会把当前类交给 IOC 容器管理,当容器启动时,自动创建对象存入容器
  3. 如果扫描到属性上有 DI 注解,则依据依赖注入的规则,给属性注入值

方式1:xml配置方式 开启包扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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.xsd">

    <!-- 开启包扫描
         - base-package:包名(自动扫描此包以及此包下的所有子包)
    -->
    <context:component-scan base-package="cn.test"></context:component-scan>
</beans>

方式2:配置类注解方式 开启包扫描

/**
 * 1、声明配置类:@Configuration
 * 2、开启包扫描:@ComponentScan
 */
@Configuration
@ComponentScan(basePackages = "cn.test")
public class SpringConfig {
}


IOC 注解(对象创建的注解)

IOC 注解(对象创建的注解)说明:

  • 标注在想要被 IOC 容器管理的类上,表明创建对象交给容器管理
  • 当 Spring 容器启动时,根据包扫描配置自动的扫描到 IOC 注解,反射创建注解标注的对象,存入容器,委托容器管理
  • 默认存入容器的 id(唯一标识)为当前类名首字母小写。可以通过 value 属性自定义存入容器中对象的 id

一共有四个:

  • @Controller:一般标注在表现层(web层)的类上
  • @Service: 一般标注在业务层(service层)的类上
  • @Repository: 一般标注在持久层(dao层)的类上
  • @Component:组件, 非三层模式范围的类上使用

相当于xml中的如下配置

<bean id="userDaoImpl" class="cn.test.dao.impl.UserDaoImpl"></bean>


生命周期的相关注解

  • @Scope : 在类上配置对象的作用域

    通过value属性指定作用范围(singleton|prototype),默认为 singleton(单例)

  • @PostConstruct : 配置对象创建后的触发动作

    当对象创建完成之后,自动执行的方法。相当于 xml 配置文件中的 init-method

  • @PreDestroy :配置对象销毁前的触发动作(仅在 Scope = singleton 时有效)

    容器关闭,对象销毁之前执行的方法。相当于 xml 配置文件中的destory-method

示例:

@Repository
@Scope(value="singleton")
public class UserDaoImpl implements UserDao {

    public UserDaoImpl() {
        System.out.println("创建UserDaoImpl");
    }

    @Override
    public void save() {
        System.out.println("调用dao保存数据");
    }


    //初始化方法:在对象创建完成之后执行
    @PostConstruct
    public void init() {
        System.out.println("执行init方法");
    }

    //销毁方法:在容器关闭对象销毁之前执行
    @PreDestroy
    public void destory() {
        System.out.println("执行destory方法");
    }
}


DI 注解(依赖注入的注解)

DI 注解都相当于直接给属性赋值,而无需借助于 set 方法或构造方法

@Autowired

使用方式1:标注在属性上

  • 直接给属性赋值(通过 @Autowired 依赖注入,不需要配置 set 方法)
  • 默认是通过 by Type(根据类型,即接口类型)的形式从 IOC 容器中查找对象并给属性注入值
  • 如果 IOC 容器中存在多个与属性同类型的对象(一个接口有多个实现类),

    • 则会按照属性名(by Name)作为唯一标志从容器中查找对象并给属性注入值
    • 也可以和 @Qualifier 注解共同使用,指定唯一标志从容器中查找对象并给属性注入值

      • value:指定 IOC 容器中对象唯一标志(id)

      注意:@Qualifier 只能结合 @Autowired 一起使用

使用方式2:标注在方法上

  • 表示自动执行当前方法,如果方法有参数,会自动从IOC容器中寻找同类型的对象给参数传值
  • 也可以在参数上添加 @Qualifier("IOC容器中对象id") 注解按照名称寻找对象给参数传值


@Autowired 使用注意事项

  1. 只能在被 Spring 容器托管(标注了 @Controller 等 IOC 注解)的类中使用 @Autowired 注解
  2. 自动注入与权限修饰符无关,即使是 private 修饰的字段也可以自动注入
  3. 默认情况下,使用 @Autowired 注解进行自动注入的属性一定要被装配( Spring 容器托管)

    如果在容器中找不到该类型的bean 进行注入,就会报错

    如果允许不被装配,可以将 @Autowired 的 required 属性为 false

  4. @Autowired 是基于类型的注入,如果当前类型属性在容器中只有一个 Bean,那么属性名不限制,但一般建议遵循类名首字母小写的规则
  5. 如果当前属性类型在容器中有个多个Bean,那么必须要通过属性名或者同时标注 @Qualifier 注解指定 Bean name


示例:

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier(value = "userDao2")        // 从容器中获取指定唯一标志的对象
    private UserDao userDao;

    @Override
    public void save() {
        userDao.save();
    }
}


@value

配置在属性上。可用于简单数据类型的注入,相当于 < property name="" value="" > ,但通常不这么使用

一般用于解析 properties 配置文件或注册中心的配置文件中的内容

  • 根据key值获取对应的 value,语法规则: @Value("${key}")
  • 使用步骤:

    1. properties 配置文件交给Spring容器管理
    2. 通过 @Value,从容器中得到配置项,并注入

示例:

(1) 配置jdbc.properties文件

jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///heima23

(2) 配置文件交给Spring

修改spring配置文件applicationContext.xml

    <!--将properties文件,交给spring管理-->
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>

(3) 属性注入

@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {

    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;

    public void save() {
        System.out.println(username);
        System.out.println(password);
        System.out.println(driver);
        System.out.println(url);
        System.out.println("调用dao11111完成保存");
    }
}


@Reource(了解)

jdk提供的依赖注入的注解,此注解在jdk9及以上版本已经移除

  • 只能放在属性上
  • 表示先按照属性名匹配 IOC 容器中对象id给属性注入值【by name】
  • 若没有成功,会继续根据当前属性的类型匹配IOC容器中同类型对象来注入值 【by type】
  • 若指定了 name 属性 @Resource(name = "对象id"),则只能按照对象 id 注入值

示例:

@Service
public class UserServiceImpl implements UserService {
    @Resource(name = "userDao1")
    private UserDao userDao;

    @Override
    public void save() {
        userDao.save();
    }
}


Configuration 配置类(注解)

配置类中的常用注解:

  • @Configuration:标注在类上,声明该类为 Spring 配置类

    Spring 在启动的时候会自动扫描并加载所有配置类,配置 Spring 容器(应用上下文),将配置类中的 Bean 放入容器管理

  • @Bean:标注在 Spring 配置类中的方法上,注册 bean 对象到 IOC 容器

    • name 属性:给生成的bean指定唯一标志

    在 Spring 容器启动的时候,自动的扫描并执行所有配置了 @Bean 的方法,并将返回值存入Spring容器

    注意:

    • 被标注的方法,需要返回某个实例
    • 被标注的方法,可以配置依赖的属性参数,Spring 会自动从容器中获取到依赖的对象,自动调用方法
  • @ComponentScan:开启包扫描(Spring IOC注解支持),默认扫描当前包及子包下所有类

    • basePackage 属性:指定扫描的包路径。可以减少加载时间

    如果扫描到类上有 IOC 注解,就会把当前类交给 IOC 容器管理,当容器启动时,自动创建对象存入容器

    如果扫描到属性上有 DI 注解,则依据依赖注入的规则,给属性注入值

  • @PropertySource:加载本地 properties 文件交给 Spring 容器管理

    • value 属性:指定本地 properties 路径
  • @Import:在一个配置类中导入其它配置类的内容

    • value 属性:指定其他的配置类的 class 类路径

    Spring 支持多配置类(配置类的模块),若配置类臃肿,可以拆分配置类,然后在主配置类中引入子配置类(子配置类上不用配置注解)

示例:

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;

@Configuration        // 声明配置类
@ComponentScan(basePackages = "cn.test")    // 开启包扫描,并指定包扫描路径
@PropertySource(value="jdbc.properties")    // 通过注解将此文件交给spring容器管理
@Import(value=DataSourceConfig.class)        // 引入其他的配置类
public class SpringConfig {

    @Bean
    public QueryRunner getQueryRunner(DataSource dataSource) {
        QueryRunner qr = new QueryRunner(dataSource);
        return qr;
    }
}
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;

// 子配置类
public class DataSourceConfig {

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.driver}")
    private String driver;

    @Bean
    public DataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        return dataSource;
    }
}
# properties文件
jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///heima23


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
安全 Java 开发者
如何在Spring框架中实现横切关注点的集中管理和重用?
【4月更文挑战第30天】如何在Spring框架中实现横切关注点的集中管理和重用?
10 0
|
3天前
|
安全 Java 程序员
Spring框架的核心特性是什么?
【4月更文挑战第30天】Spring 的特性
11 0
|
3天前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
11 0
|
3天前
|
SQL Java 数据库连接
Springboot框架整合Spring JDBC操作数据
JDBC是Java数据库连接API,用于执行SQL并访问多种关系数据库。它包括一系列Java类和接口,用于建立数据库连接、创建数据库操作对象、定义SQL语句、执行操作并处理结果集。直接使用JDBC涉及七个步骤,包括加载驱动、建立连接、创建对象、定义SQL、执行操作、处理结果和关闭资源。Spring Boot的`spring-boot-starter-jdbc`简化了这些步骤,提供了一个在Spring生态中更便捷使用JDBC的封装。集成Spring JDBC需要添加相关依赖,配置数据库连接信息,并通过JdbcTemplate进行数据库操作,如插入、更新、删除和查询。
|
3天前
|
SQL Java 数据库连接
Springboot框架整合Spring Data JPA操作数据
Spring Data JPA是Spring基于ORM和JPA规范封装的框架,简化了数据库操作,提供增删改查等接口,并可通过方法名自动生成查询。集成到Spring Boot需添加相关依赖并配置数据库连接和JPA设置。基础用法包括定义实体类和Repository接口,通过Repository接口可直接进行数据操作。此外,JPA支持关键字查询,如通过`findByAuthor`自动转换为SQL的`WHERE author=?`查询。
|
3天前
|
安全 Java 开发者
在Spring框架中,IoC和AOP是如何实现的?
【4月更文挑战第30天】在Spring框架中,IoC和AOP是如何实现的?
15 0
|
3天前
|
XML Java 程序员
什么是Spring的IoC容器?
【4月更文挑战第30天】什么是Spring的IoC容器?
10 0
|
5月前
|
XML Java 数据格式
④【Spring】IOC - 基于注解方式 管理bean
④【Spring】IOC - 基于注解方式 管理bean
49 0
|
5月前
|
XML Java 数据格式
②【Spring】一文精通:IOC - 基于XML方式管理Bean
②【Spring】一文精通:IOC - 基于XML方式管理Bean
146 0
|
5月前
|
XML Java 数据格式
掌握 Spring IoC 容器与 Bean 作用域:详解 singleton 与 prototype 的使用与配置
在您的应用程序中,由 Spring IoC 容器管理的形成其核心的对象被称为 "bean"。一个 bean 是由 Spring IoC 容器实例化、组装和管理的对象
48 0