Spring 全家桶之 Spring Framework 5.3(三)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Spring 全家桶之 Spring Framework 5.3(三)

一、Bean生命周期

生命周期:即Bean从初始化到销毁的整个过程 在Tesla实体中增加两个方法,初始化方法和销毁方法

public class Tesla {
    private String name;
    private String battery; // 电池
    private String engine; // 电机
    private String chassis; //底盘
    private String bodywork; // 车身
    private String owner; // 车主
    public void init(){
        System.out.println(this.getClass().getName() + "init方法被调用");
    }
    public void destroy(){
        System.out.println(this.getClass().getName() + "destroy方法被调用");
    }
    // 此处省略getter/setter/toString方法
}    
复制代码

在bean_life_cycle.xml中配置Tesla,初始化方法使用init-method属性表示,销毁方法使用destroy-method表示

<?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:util="http://www.springframework.org/schema/util"
       xmlns:p = "http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-4.3.xsd">
    <bean id="tesla" class="com.citi.entity.Tesla" init-method="init" destroy-method="destroy">
        <property name="name" value="tesla"></property>
        <property name="owner" value="musk"></property>
    </bean>
</beans>
复制代码

新增测试类BeanLifeCycleTest,增加测试方法

public class BeanLifeCycleTest {
    @Test
    public void testGetBean(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean_life_cycle.xml");
        System.out.println("IoC容器创建完成");
        Tesla tesla = context.getBean("tesla",Tesla.class);
        System.out.println(tesla);
        context.close();
    }
}
复制代码

控制台打印,初始化方法和销毁方法都被调用

image.png

修改xml中Bean的配置为多实例

<bean id="tesla" scope="prototype" class="com.citi.entity.Tesla" init-method="init" destroy-method="destroy">
    <property name="name" value="tesla"></property>
    <property name="owner" value="musk"></property>
</bean>
复制代码

执行测试方法,控制台打印如下,多实例情况下只会调用初始化方法,不会调用销毁方法

image.png

  • 多实例获取Bean的时候才会调用初始化方法,容器关闭不会调用destroy方法
  • 单实例容器创建完成之前会调用初始化方法,Bean会在容器创建前创建,容器关闭时会调用Bean的destroy方法

Bean的后置处理器

BeanPostProcessor后置处理器接口可以定义Bean初始化前后执行的方法,新增config包,增加自定义的BeanPostProcessor

public class CustBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "初始化前调用该方法");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "初始化后调用该方法");
        return bean;
    }
}
复制代码

在bean_life_cycle.xml增加CustBeanPostProcessor的xml配置,再增加一个 Person实体类的bean xml配置

<bean id="stark" class="com.citi.entity.Person">
    <property name="lastName" value="stark"></property>
</bean>
<bean class="com.citi.config.CustBeanPostProcessor"></bean>
复制代码

执行测试方法,每个Bean初始化前后都调用了后置处理器,后置处理器对容器中的每一个Bean都起作用

image.png

管理连接池及引用外部配置文件

以数据库连接池为例,数据库连接池最好是单例模式的,一个连接池中有多个数据库连接.

使用Spring Bean配置文件创建和管理数据库连接池

首先增加数据驱动及连接池的依赖

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.16</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.14</version>
</dependency>
复制代码

在connection_config.xml中增加数据库连接池的配置

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
    <property name="initialSize" value="5"/>
    <property name="maxActive" value="20"/>
</bean>
复制代码

增加测试类

public class JdbcConnectionTest {
    @Test
    public void testGetBean() throws SQLException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:connection_config.xml");
        System.out.println("IoC容器创建完成");
        DruidDataSource dataSource = context.getBean("dataSource",DruidDataSource.class);
        System.out.println(dataSource);
        System.out.println(dataSource.getConnection());
    }
}
复制代码

数据库连接被成功创建

image.png

引用外部配置文件

在resources目录下创建数据库信息配置文件datasource.properties

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username=root
password=root
initialSize=5
maxActive=20
复制代码

修改connect_config.xml中的配置,增加引用外部配置文件的配置,并修改连接池的配置

<!--引用外部配置文件-->
<context:property-placeholder location="classpath:database.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${driverClassName}"/>
    <property name="url" value="${url}" />
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
    <property name="initialSize" value="${initialSize}"/>
    <property name="maxActive" value="${maxActive}"/>
</bean>
复制代码

执行测试方法,成功获取数据库连接

image.png

基于XML的自动装配

在之前章节中为各种属性正确赋值都是通过property标签进行手动赋值,使用bean标签中的autowire属性可以设置自动赋值,autowire配置的含义

  • default:不自动装配,默认配置
  • byName:以属性名作为ID进行赋值
  • byType: 按照类型进行自动赋值,如果有多个相同类型的Bean在容器中会会报错
  • constructor: 使用有参构造器进行赋值,先按照够再起的参数类型进行装配,如果容器中不存在car,直接赋值null,存在多个使用属性名作为区分

byName

在autowire.xml中增加配置

<bean id="car" class="com.citi.entity.Car">
    <property name="carName" value="JAUGAR"></property>
    <property name="color" value="英国绿"></property>
    <property name="price" value="580000"></property>
</bean>
<bean id="stark" class="com.citi.entity.Person" autowire="byName">
    <property name="lastName" value="stark"></property>
</bean>
复制代码

Person实体类中有一个属性名为car,autowire使用byName配置可以自动将容器id为car的Bean自动赋值为Person

增加测试类AutowireBeanTest,测试方法testGetBean()

public class AutowireBeanTest {
    @Test
    public void testGetBean(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:autowire.xml");
        System.out.println("IoC容器创建完成");
        Person stark = context.getBean("stark",Person.class);
        System.out.println(stark);
    }
}
复制代码

已成功将容器中的car自动装配的Person中的car,如果容器中不存在car,则无法自动赋值,Person bean中的car属性为null

image.png

byType

将xml配置中的byName改为byType,再次执行测试,可以将Person实体类中的Car属性及Map中的Car属性都自动装配上以及一些环境变量

image.png

如果容器中有多个Car,在xml中多配置一个Car Bean标签,执行测试

image.png

constructor

Person实体类中增加只包含Car的有参构造器

public Person(Car car) {
    System.out.println("只包含Car的有参构造器被调用");
    this.car = car;
}
复制代码

autowire.xml中只保留一个car的xml配置,将person的xml配置中的autowire属性改为constructor,执行测试方法

image.png

如果存在多个car bean,增加一个car配置

<bean id="car01" class="com.citi.entity.Car">
    <property name="carName" value="F-Type"></property>
    <property name="color" value="英国绿"></property>
    <property name="price" value="580000"></property>
</bean>
复制代码

执行测试,成功赋值name为JAUGAR的car,当存在多个同类型的Bean时,优先按照属性名进行自动赋值

image.png

自动装配即自动赋值

Spring 表达式 (SpEL)

使用#{}表示Spring 表达式

  • 支持使用字面量
  • 支持引用其他Bean及Bean的属性
  • 支持调用静态及非静态方法
  • 支持所有的运算符 xml配置文件中修改Person xml配置
<bean id="stark" class="com.citi.entity.Person" autowire="constructor">
    <property name="lastName" value="stark"></property>
    <property name="age" value="#{1*3*4*5}"></property>
    <property name="car" value="#{car}"></property>
    <!--调用静态方法-->
    <property name="email" value="#{T(java.util.UUID).randomUUID().toString().substring(0,5)}"></property>
    <property name="gender" value="#{car.getCarName()}"></property>
</bean>
复制代码

执行测试方法,各属性使用EL表达式成功赋值

image.png


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7月前
|
Java 开发者 Spring
Spring Framework 中的 @Autowired 注解:概念与使用方法
【4月更文挑战第20天】在Spring Framework中,@Autowired 注解是实现依赖注入(Dependency Injection, DI)的一种非常强大的工具。通过使用 @Autowired,开发者可以减少代码中的引用绑定,提高模块间的解耦能力
731 6
|
4月前
|
安全 Java 网络安全
Spring Framework JDK >= 9 远程代码执行(CVE-2022-22965)
Spring Framework JDK >= 9 远程代码执行(CVE-2022-22965)
|
6月前
|
前端开发 Java 调度
Spring Webflux 是 Spring Framework 提供的响应式编程支持
Spring Webflux 是 Spring Framework 提供的响应式编程支持
88 2
|
5月前
|
Cloud Native Java 开发者
深入解析Spring Framework的核心设计原理
深入解析Spring Framework的核心设计原理
|
5月前
|
安全 Java Apache
如何安装与使用Spring Boot 2.2.x、Spring Framework 5.2.x与Apache Shiro 1.7进行高效开发
【7月更文第1天】在现代Java Web开发领域,Spring Boot以其简化配置、快速开发的特点备受青睐。结合Spring Framework的成熟与Apache Shiro的强大权限控制能力,我们可以轻松构建安全且高效的Web应用。本篇文章将指导你如何安装并使用Spring Boot 2.2.x、Spring Framework 5.2.x以及Apache Shiro 1.7来构建一个具备基础权限管理功能的项目。
92 0
|
7月前
|
设计模式 Java 数据库连接
Spring Framework 6 中的设计模式
Spring Framework 6 中的设计模式
50 1
|
7月前
|
前端开发 Java Spring
Spring Framework五大功能模块
Spring Framework五大功能模块
|
开发框架 安全 Java
Spring Framework远程代码执行漏洞复现(CVE-2022-22965)
Spring Framework存在远程代码执行漏洞,攻击者可通过该漏洞执行系统命令。
466 1
Spring Framework远程代码执行漏洞复现(CVE-2022-22965)
|
前端开发 Java 数据库连接
【面试题精讲】Spring Framework有哪些模块?
【面试题精讲】Spring Framework有哪些模块?
|
安全 Java 测试技术
Spring Framework中的Bean生命周期2
Spring Framework中的Bean生命周期2
83 0