SpringFramework

news2024/12/23 22:09:26

🏡个人主页 :@ 守夜人st
🚀系列专栏:Spring
…持续更新中敬请关注…
🙉博主简介:软件工程专业,在校学生,写博客是为了总结回顾一些所学知识点

目录

  • Spring
    • spring概述
      • 1 Spring定义
      • 2 Spring核心
      • 3 Spring Framework的特点
    • 入门案例
      • 1 环境要求
      • 2 构建工程
        • 2.1 构建子工程first-spring
        • 2.2 入门案例
        • 2.3 对象存储
    • IoC容器
      • 1 控制反转IoC
      • 2 依赖注入DI
      • 3 IoC容器实现
      • 4 基于XML管理bean
        • 4.1 环境准备
        • 4.2 获取bean方式
        • 4.3 基于setter依赖注入
        • 4.4 基于构造器依赖注入
        • 4.5 特殊值处理注入
          • 4.5.1 字面量赋值
          • 4.5.2 null值
          • 4.5.3 xml实体
          • 4.5.4 CDATA区
        • 4.6 对象类型属性注入
          • 4.6.1 引用外部bean
          • 4.6.2 内部bean
          • 4.6.3 级联属性赋值(了解)
        • 4.7 数组类型属性注入
        • 4.8 集合类型属性注入
          • 4.8.1 List集合属性注入
          • 4.8.2 Map集合属性注入
          • 4.8.3 引用集合类型bean注入
        • 4.9 p命名空间
        • 4.10 引入外部属性文件
        • 4.11 bean的作用域
        • 4.12 bean的生命周期
          • 4.12.1 bean的完整生命周期
          • 4.12.2 生命周期验证
          • 4.12.3 bean生命周期扩展
        • 4.13 基于xml自动装配
      • 5 基于注解管理bean
        • 5.1 创建子工程
        • 5.2 开启组件扫描
        • 5.3 使用注解定义Bean
        • 5.4 @Autowired注入
          • 5.4.1 属性注入
          • 5.4.2 set注入
          • 5.4.3 构造方法注入
          • 5.4.4 形参上注入
          • 5.4.5 只有一个构造函数,无注解
          • 5.4.6 @Autowire注解和@Qualifier注解联合
        • 5.5 @Resource注入
        • 5.6 Spring全注解开发

Spring

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GhZmSmVg-1683689348961)(./images/spring-16827607184382.jpg)]

spring概述

1 Spring定义

​ Spring是一款主流的Java EE 轻量级开源框架,目的是用于简化Java企业级引用的开发难度和开发周期。从简单性、可测试性和松耦合度的角度而言,任何Java应用都可以从Spring中受益。Spring框架提供自己提供功能外,还提供整合其他技术和框架的能力。

​ Spring自诞生以来备受青睐,一直被广大开发人员作为Java企业级应用程序开发的首选。时至今日,Spring俨然成为了Java EE的代名词,成为了构建Java EE 应用的事实标准。

​ 自2004年4月,Spring1.0 版正式发布以来,Spring已经步入到了第6个大版本,即 Spring6,本课程采用Spring5.3.24正式版本。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qlfn7pTh-1683689348962)(./images/image-20230429191815500.png)]

2 Spring核心

​ Spring指的是Spring Framework,通常我们称之为Spring框架。Spring框架是一个分层的面向切面的Java应用程序的一站式解决框架,它是Spring技术栈的核心和基础,是为了解决企业级引用开发的复杂性而创建的。

​ Spring有两个核心模块:IoC和AOP。

​ Ioc:Inverse of Control的简写,为 控制反转,指把创建对象交给Spring进行管理。

​ AOP:Aspect Oriented Programming 的简写,为 面向对象编程。AOP用来封装多个类的公共行为,将那些与业务无关,却为业务模块共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP还解决一些系统层面上的问题,比如日志、事务、权限等。

3 Spring Framework的特点

  • 控制反转:IoC,反转资源获取方向;把自己创建的资源、向环境索取资源变为环境将资源准备好,我们享受资源注入。

  • 面向切面编程:AOP,在不修改源代码的基础上增强代码功能。

  • 容器:Spring IoC是一个容器,因为它包含并管理组件对象的生命周期;组件享受到了容器化的管理,替程序员屏蔽了组件创建过程中的大量细节,极大降低了使用门槛,大幅度提高了开发效率。

  • 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方库,而且在Spring旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在Spring Framework 的基础上全部使用Spring来实现。

入门案例

1 环境要求

  • JDK:Java8-15
  • Spring:5.3.24

2 构建工程

2.1 构建子工程first-spring

​ 在my-spring中创建子工程 spring-first

  1. New - Module

  2. 点击 Next

2.2 入门案例

① 在spring-first/pom.xml中引入相关依赖,并 刷新maven

<dependencies>
    <!-- spring context依赖
             当引入此依赖后,表示将Spring的基础依赖引入了
         -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.24</version>
    </dependency>

</dependencies>

② 在工程中创建包 cn.tedu.spring.begin

③ 创建类 User

④ User类中定义方法

public class User {
    
    public void add(){
        System.out.println("添加方法...");
    }
}

⑤ 创建spring配置文件:resources目录下创建bean.xml

⑥ 在bean.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.xsd">

    <!--完成user对象创建
        id属性:唯一标识
        class属性:要创建的对象所在类的绝对路径
    -->
    <bean id="user" class="cn.tedu.spring.User"></bean>
    
</beans>

⑦ 创建测试类cn.tedu.spring.TestUser进行测试

public class TestUser {

    public static void main(String[] args) {
        // 1.加载spring配置文件,进行对象创建
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        // 2.获取spring创建好的对象
        User user = (User) context.getBean("user");
        // 3.使用对象调用方法测试
        System.out.println("user = " + user);
        user.add();
    }
}

2.3 对象存储

存放到容器中,查看源码,DefaultListableBeanFactory.java,第164行

key:唯一标识

value:类的定义(描述信息)

可以查看 BeanDefinition 的源码,有类的描述信息,是否初始化的状态等等

IoC容器

​ IoC 是 Inversion of Control 的简写,译为 控制反转。

​ Spring通过IoC容器来管理所有的Java对象的实例化和初始化,控制着对象与对象之间的依赖关系。我们将由IoC容器管理的Java对象成为 Spring Bean,它与使用关键字 new 创建的Java对象没有任何区别。

​ IoC容器是Spring框架中最重要的核心组件之一,它贯穿了Spring从诞生到成长的整个过程。

1 控制反转IoC

  • 控制反转是一种思想

    • 将对象的创建权利交出去,交给第三方容器负责
    • 将对象和对象之间的关系维护权交出去,交给第三方容器负责
  • 如何实现

    通过依赖注入DI的方式实现

2 依赖注入DI

DI (Dependency Injection):依赖注入,依赖注入实现了控制反转的思想,是指Spring创建对象的过程中,将对象依赖属性通过配置进行注入。

依赖注入常见的实现方式有两种:

  1. set注入
  2. 构造注入

所以 IoC 是一种控制反转的思想,而 DI 是对IoC的一种具体实现。

Bean管理:指Bean对象的创建,以及Bean对象中属性的赋值(或Bean对象之间关系的维护)

3 IoC容器实现

Spring中的IoC容器就是IoC思想的一个落地产品实现。IoC容器中管理的组件也叫做bean。在创建bean之前,首先需要创建IoC容器,Spring提供了IoC容器的两种实现方式

① BeanFactory

​ 这是IoC容器的基本实现,是Spring内部使用的接口。面向Spring本身,不提供给开发人员使用。

② ApplicationContext

​ BeanFactory的子接口,提供了更多高级特性,面向Spring的使用者,几乎所有场合都使用 ApplicationContext,而不是底层的BeanFactory

源码说明:

③ ApplicationContext的主要实现类

类型说明
ClassPathXmlApplicationContext通过读取类路径下的xml格式配置文件创建IoC容器对象
FileSystemApplicationContext通过文件系统路径读取xml格式配置文件创建IoC容器对象

4 基于XML管理bean

4.1 环境准备

① 创建子工程 spring-ioc-xml

② pom.xml中引入spring依赖,并刷新maven

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.24</version>
    </dependency>
</dependencies>

③ 创建spring配置文件:resources/bean.xml

④ 在工程目录java下创建类 cn.tedu.spring.iocxml.User

public class User {
    private String username;
    private String password;
    
    public void userMethod(){
        System.out.println("userMethod执行~~");
    }
}

4.2 获取bean方式

  • 根据id获取

    id属性是bean的唯一标识,所以根据bean标签的id属性可以精确获取到一个组件对象。

    ① bean.xml

    <bean id="user" class="cn.tedu.spring.iocxml.User"></bean>
    

    ② 创建测试类UserTest

    public class UserTest {
    
        public static void main(String[] args) {
            // 1.加载配置文件
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
            // 2.根据id获取bean
            User user1 = (User) context.getBean("user");
            System.out.println("1-根据id获取对象:" + user1);
            user1.userMethod();
        }
    }
    
  • 根据类型获取

    User user2 = context.getBean(User.class);
    System.out.println("2-根据类型获取bean:" + user2);
    user2.userMethod();
    
  • 根据id和类型获取

    User user3 = context.getBean("user", User.class);
    System.out.println("3-根据id和类型获取bean:" + user3);
    user3.userMethod();
    
  • 注意

    当根据类型获取bean时,要求IoC容器中指定类型的bean只能有一个,当配置两个时会抛出异常

    <bean id="user" class="cn.tedu.spring.iocxml.User"></bean>
    <bean id="user2" class="cn.tedu.spring.iocxml.User"></bean>
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQP6Ez9J-1683689348980)(./images/image-20230429232828166.png)]

4.3 基于setter依赖注入

类有属性,创建对象过程中,向属性注入具体的值

方式1:使用set方法完成(使用xml中的标签实现

方式2:基于构造器完成

案例

① 创建Package名为dibase,创建Book类

package cn.tedu.spring.DI;

public class Book {
    private String bookName;
    private String bookAuthor;

    // 无参构造函数
    public Book() {}
    
    // 全参构造函数
    public Book(String bookName, String bookAuthor) {
        this.bookName = bookName;
        this.bookAuthor = bookAuthor;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookAuthor() {
        return bookAuthor;
    }

    public void setBookAuthor(String bookAuthor) {
        this.bookAuthor = bookAuthor;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookName='" + bookName + '\'' +
                ", bookAuthor='" + bookAuthor + '\'' +
                '}';
    }
}

② 创建spring配置文件:resources目录下创建 bean-di.xml

<!-- set方法注入 -->
<bean id="book" class="cn.tedu.spring.DI.Book">
    <!--2.使用property标签注入-->
    <property name="bookName" value="java"></property>
    <property name="bookAuthor" value="tedu"></property>
</bean>

③ 创建测试类TestBook进行测试

public class BookTest {
    // spring的set方法注入
    @Test
    public void springSetTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
        Book book = context.getBean("book", Book.class);
        System.out.println("book = " + book);
    }
}

4.4 基于构造器依赖注入

  • 说明

    通过构造器方式实现依赖注入

  • 操作步骤说明

    1. 创建类,定义属性,生成有参数构造方法
    2. 进行xml配置
    3. 创建测试类测试

① 创建电影信息类Film,定义属性并生成全参构造方法

public class Film {
    // 电影名称、主演
    private String title;
    private String actor;

    // 全参构造
    public Film(String title, String actor) {
        System.out.println("Film的有参构造已经执行~~");
        this.title = title;
        this.actor = actor;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getActor() {
        return actor;
    }

    public void setActor(String actor) {
        this.actor = actor;
    }

    @Override
    public String toString() {
        return "Film{" +
                "title='" + title + '\'' +
                ", actor='" + actor + '\'' +
                '}';
    }
}

② 在bean-di.xml中进行注入配置

<!-- 构造器注入演示:Film类 -->
<bean id="film" class="cn.tedu.spring.DI.Film">
    <constructor-arg name="title" value="霸王别姬"></constructor-arg>
    <constructor-arg name="actor" value="张国荣"></constructor-arg>
</bean>

③ 创建测试类TestFilm测试

public class FilmTest {

    @Test
    public void FilmConsDITest(){
        // 1.加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
        // 2.获取指定bean
        Film film = context.getBean("film", Film.class);
        // 3.输出测试
        System.out.println("film = " + film);
    }
}

4.5 特殊值处理注入

4.5.1 字面量赋值

string number = 10;

声明一个变量number,初始化为 10,此时number就不代表字符number了,而是作为一个变量的名字。当引用number时,实际拿到的结果是 10。

而如果number是带引号的 “number” ,则它不是一个变量,而代表 number 本身这个字符串。

这就是字面量,所以字面量没有引申含义,就是我们看到的这个数据本身。

<!-- 使用value属性给bean的属性赋值时,spring会把value的属性值看作是字面量 -->
<property name="number" value="1016"></property>
4.5.2 null值

使用 标签,或者 标签 实现注入。

① Film类中增加电影描述属性

// 1.电影描述
private String description;
// 2.生成对应的 set() get() 方法,重新生成toString()方法
// 3.重新生成全参构造方法

② bean-di.xml配置文件调整

<!-- 构造器注入演示:Film类 -->
<bean id="film" class="cn.tedu.spring.DI.Film">
    <constructor-arg name="title" value="霸王别姬"></constructor-arg>
    <constructor-arg name="actor" value="张国荣"></constructor-arg>
    <!-- 电影描述注入空值null -->
    <constructor-arg name="description">
        <null></null>
    </constructor-arg>
</bean>

③ 执行测试类进行测试

  • 课堂练习

    cn.tedu.spring下创建包exercise,在包下创建商品表 Product,类属性如下:

    商品标题:title

    商品库存:num

    商品销量:sales

    商品描述:comment

    1. 实现 商品Product类的创建,setter() getter() toString(),

    2. 通过配置文件bean-product.xml

      通过set方式注入一组数据(商品描述为null值);

      通过构造参数方式注入一组数据(商品描述为null值);

    3. 创建测试类TestProduct进行测试。

  • 练习答案

① Product类

public class Product {
    private String title;
    private Integer num;
    private Integer sales;
    private String comment;
    // 无参构造函数、有参构造函数  setter() getter() toString() 
}

② bean-product.xml

<!-- set方法注入 -->
<bean id="product" class="cn.tedu.spring.exercise.Product">
    <property name="title" value="手机"></property>
    <property name="num" value="100"></property>
    <property name="sales" value="1000"></property>
    <property name="comment">
        <null></null>
    </property>
</bean>

<!-- 构造参数方法注入 -->
<bean id="productCons" class="cn.tedu.spring.exercise.Product">
    <constructor-arg name="title" value="电脑"/>
    <constructor-arg name="num" value="2"/>
    <constructor-arg name="sales" value="3"/>
    <constructor-arg name="comment">
        <null></null>
    </constructor-arg>
</bean>

③ ProductTest测试类

@Test
public void testProduct(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-product.xml");
    Product product = context.getBean("product", Product.class);
    System.out.println("product = " + product);
}
4.5.3 xml实体
  • 说明

    < > 小于号、大于号在XML文档中用来定义标签的开始,具有特殊含义,在注入属性值时不能够随便使用,

    可以使用XML实体 &lt; &gt; 来代替

  • 表示方式

    普通字符xml实体
    <<
    >>

查看示例 bean-di.xml:

<!-- xml实体 -->
<bean id="filmEntity" class="cn.tedu.spring.DI.Film">
    <constructor-arg name="title" value="霸王别姬"></constructor-arg>
    <constructor-arg name="actor" value="张国荣"></constructor-arg>
    <!--xml实体表示-->
    <constructor-arg name="description" value="&lt;真好看啊电影&gt;"></constructor-arg>
</bean>
4.5.4 CDATA区

CDATA区,是xml中一种特有的写法,在CDATA区中可以包含特殊符号

表示方式:

<![CDATA[内容]]> ,在内容区域可以存放普通字符和特殊符号

CDATA区存放特殊符号演示

<!-- xml实体-CDATA区 -->
<bean id="filmCdata" class="cn.tedu.spring.DI.Film">
    <constructor-arg name="title" value="霸王别姬"></constructor-arg>
    <constructor-arg name="actor" value="张国荣"></constructor-arg>
    <!--xml实体表示-->
    <constructor-arg name="description">
        <!-- CDATA区存放数据,可通过 CD + Tab键自动补全格式 -->
        <value><![CDATA[<真好看啊>]]></value>
    </constructor-arg>
</bean>

4.6 对象类型属性注入

需要注入的数据类型为对象,而不是一个字面量。

  • 环境准备

    准备一个一对多案例,比如部门Dept和员工Emp是一对多的关系。

① 创建包diobj,并创建部门类Dept

public class Dept {
    // 部门名称
    private String dName;

    // 定义方法,用于测试输出
    public void deptFunc(){
        System.out.println("Dept部门名称:" + dName);
    }

    public void setdName(String dName) {
        this.dName = dName;
    }

    public String getdName() {
        return dName;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dName='" + dName + '\'' +
                '}';
    }
}

② 创建员工类Emp,创建setter() getter() 和 toString()方法

public class Emp {
    // 员工所属部门的对象、姓名、工资
    private Dept dept;
    private String eName;
    private Double salary;

    // 定义方法测试
    public void work(){
        System.out.println(eName + "薪资:" + salary);
        dept.deptFunc();
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void seteName(String eName) {
        this.eName = eName;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public Dept getDept() {
        return dept;
    }

    public String geteName() {
        return eName;
    }

    public Double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                ", eName='" + eName + '\'' +
                ", salary=" + salary +
                '}';
    }
}

4.6.1 引用外部bean

说明:

​ 可以通过在当前bean标签中通过 ref属性引用外部bean的方式实现。

 <bean id="xxx" class="xxx"><property name="yyy" ref="外部bean的id属性值">
 <bean>

示例:通过使用外部bean方式,在员工中注入部门对象

① 配置文件 bean-diobj.xml

<!--在Emp中注入Dept
    方式1:引用外部bean
        1.创建两个类对象:dept 和 emp
        2.在emp的bean标签中,通过property标签注入dept的bean
    -->
<bean id="dept1" class="cn.tedu.spring.diobj.Dept">
    <property name="dName" value="开发部"></property>
</bean>

<bean id="emp1" class="cn.tedu.spring.diobj.Emp">
    <!-- 普通属性注入 -->
    <property name="eName" value="张三丰"></property>
    <property name="salary" value="50000.0"></property>
    <!-- 对象类型注入,使用ref属性 -->
    <property name="dept" ref="dept1"></property>
</bean>

② 创建测试类测试 TestDept

public class TestDept {

    // 对象类型注入测试用例
    @Test
    public void testObjDI(){
        // 1.加载xml配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
        // 2.获取bean对象
        Emp emp1 = context.getBean("emp1", Emp.class);
        // 3.测试(调用员工emp对象的方法)
        System.out.println("emp1 = " + emp1);
        emp1.work();
    }
}

4.6.2 内部bean

在需要注入对象的bean标签中内嵌 对象类型属性的 bean标签即可。

> <bean id="xxx" class="xxx">
>
> ​	<property name="yyy">
>
> ​			  <bean id="xxx" class="xxx">内嵌bean</bean>
>
> ​	</property>
>
> </bean>

① bean-diobj.xml进行属性注入配置

<!--在Emp中注入Dept
        方式2:引用内部bean
            在emp的bean标签中,通过内嵌部门bean标签方式实现
        -->
<bean id="emp2" class="cn.tedu.spring.diobj.Emp">
    <property name="eName" value="张无忌"/>
    <property name="salary" value="8000.0"/>
    <!--对象注入-->
    <property name="dept">
        <bean id="dept2" class="cn.tedu.spring.diobj.Dept">
            <property name="dName" value="销售部"/>
        </bean>
    </property>
</bean>

② 使用测试类测试

// 对象类型注入:内嵌bean
@Test
public void testObjDi2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
    Emp emp2 = context.getBean("emp2", Emp.class);
    System.out.println("emp2 = " + emp2);
    emp2.work();
}
4.6.3 级联属性赋值(了解)

可以在标签中给需要注入对象的属性重新赋值!

① 配置文件编写

<!--方式3:级联属性(需要注入的属性)赋值-->
<bean id="dept3" class="cn.tedu.spring.diobj.Dept">
    <property name="dName" value="市场部"/>
</bean>

<bean id="emp3" class="cn.tedu.spring.diobj.Emp">
    <!-- 普通属性注入 -->
    <property name="eName" value="赵敏"/>
    <property name="salary" value="5000.0"/>
    <!-- 对象类型注入 -->
    <property name="dept" ref="dept3"/>
    <!-- 级联属性(Dept)赋值 -->
    <property name="dept.dName" value="客服部"></property>
</bean>

② 测试类测试

// 对象类型注入:级联属性赋值
@Test
public void testObjDi3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
    Emp emp3 = context.getBean("emp3", Emp.class);
    System.out.println("emp3 = " + emp3);
    emp3.work();
}

4.7 数组类型属性注入

使用 标签和子标签实现。

说明:一个人除了姓名、年龄等属性外,还会有爱好,一个人的爱好可能有多个,可以把多个爱好存入数组中。

创建包:cn.tedu.spring.diarray

① 在diarray包中创建类:Person

public class Person {
    // 姓名、年龄、爱好
    private String name;
    private String age;
    private String[] hobby;

    // 定义测试方法
    public void run(){
        System.out.println("Persen is running...");
        // 打印数组测试
        System.out.println(Arrays.toString(hobby));
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", hobby=" + Arrays.toString(hobby) +
                '}';
    }
}

新建配置文件:bean-diarray.xml 进行注入

<!-- 创建Person对象并注入属性 -->
<bean id="person" class="cn.tedu.spring.diarray.Person">
    <!-- 普通属性注入 -->
    <property name="name" value="孙悟空"/>
    <property name="age" value="36"/>
    <!-- 数组属性注入,使用<array>标签 -->
    <property name="hobby">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
</bean>

③ 编写测试类TestPerson测试

public class TestPerson {

    // 数组注入测试用例
    @Test
    public void testArray(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean-diarray.xml");
        Person person = context.getBean("person", Person.class);
        System.out.println("person = " + person);
        person.run();
    }
}

4.8 集合类型属性注入

4.8.1 List集合属性注入

场景1:使用 标签下的 子标签和 子标签实现。

场景2:使用 标签下的 子标签和子标签实现。ref标识引用其他的bean

环境说明:创建老师类Student和学生类Student,一个老师可以有多个学生,在老师类中存入所教学生的对象,将其存入List集合中。

环境准备

① 创建包 dimap

② Teacher类

public class Teacher {

    // 老师姓名
    private String tName;
    // 老师所教学生的对象,放到List集合中
    private List<Student> studentList;

    public String gettName() {
        return tName;
    }

    public void settName(String tName) {
        this.tName = tName;
    }

    public List<Student> getStudentList() {
        return studentList;
    }

    public void setStudentList(List<Student> studentList) {
        this.studentList = studentList;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "tName='" + tName + '\'' +
                ", studentList=" + studentList +
                '}';
    }
}

③ Student类

public class Student {
    // 学生姓名、年龄
    private String sName;
    private String age;

    public String getsName() {
        return sName;
    }

    public void setsName(String sName) {
        this.sName = sName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sName='" + sName + '\'' +
                ", course='" + course + '\'' +
                '}';
    }
}

④ 创建配置文件:bean-dilistmap.xml 进行注入

<!-- 创建2个Student对象,用于Teacher对象的注入 -->
<bean id="stu1" class="cn.tedu.spring.dimap.Student">
    <property name="sName" value="梁山伯"/>
    <property name="age" value="43"/>
</bean>
<bean id="stu2" class="cn.tedu.spring.dimap.Student">
    <property name="sName" value="祝英台"/>
    <property name="age" value="33"/>
</bean>

<!-- 创建Teacher类的bean对象,并注入属性 -->
<bean id="teacher" class="cn.tedu.spring.dimap.Teacher">
    <!-- 普通属性注入 -->
    <property name="tName" value="沙师弟"/>
    <!-- List集合属性注入 -->
    <property name="studentList">
        <list>
            <ref bean="stu1"/>
            <ref bean="stu2"/>
        </list>
    </property>
</bean>

⑤ 测试类TestTeacher测试

public class TestTeacher {

    @Test
    public void testListMap(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean-dilistmap.xml");
        Teacher teacher = context.getBean("teacher", Teacher.class);
        System.out.println("teacher = " + teacher);

        List<Student> list = teacher.getStudentList();
        for (Student student: list) {
            System.out.println(student);
        }
    }
}
4.8.2 Map集合属性注入

使用标签下的 子标签、子标签、子标签 子标签 子标签实现

<bean id="xxx" class="xxx">
	<property name="xxx">
        <map>
            <!-- 第1条数据-字面量值演示 -->
			<entry>
            	<key><value>xxx</value></key>
                <value>xxx</value>
            </entry>
            <!-- 第2条数据-对象演示 -->
			<entry>
            	<key><value>xxx</value></key>
                <ref bean="xxx"></ref>
            </entry>
        </map>
	</property>
</bean>

说明:使用上述的老师类和学生类,一个学生也可以有多个老师,在学生类Student中添加老师的属性,放到Map集合中。

① 调整Student类

// 1.学生的老师:可以有多个,放到Map集合中
private Map<String,String> teacherMap;

// 2.生成setter() getter()方法,重新生成toString()方法

② 创建配置文件:bean-dimap.xml

<!--Map集合属性注入-->
<bean id="stuMap" class="cn.tedu.spring.dilistmap.Student">
    <property name="sName" value="步惊云"/>
    <property name="age" value="36"/>
    <property name="teacherMap">
        <map>
            <entry>
                <key>
                    <value>1111</value>
                </key>
                <value>雄霸</value>
            </entry>
            <entry>
                <key>
                    <value>2222</value>
                </key>
                <value>断浪</value>
            </entry>
            <entry>
                <key>
                    <value>3333</value>
                </key>
                <value>大空翼</value>
            </entry>
        </map>
    </property>
</bean>

③ 创建测试类进行测试 TestMap

@Test
public void testMap(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-dimap.xml");
    Student student = context.getBean("stuMap", Student.class);
    System.out.println("student = "  + student);
}
4.8.3 引用集合类型bean注入
  • 说明

    通过使用 标签实现

  • 使用步骤

    • 在xml配置文件中引入util约束

      <beans
      	xmlns:util="http://www.springframework.org/schema/util"
      	xsi:schemaLocation="
             http://www.springframework.org/schema/util
             http://www.springframework.org/schema/util/spring-util.xsd"
      >
                          
      </beans>
      
    • 使用util标签进入注入

      <!-- Map集合util标签 -->
      <util:map id="xxx"></util:map>
      
      <!-- List集合util标签 -->
      <util:list id="xxx"></util:list>
      

环境准备及操作步骤

添加课程类,一个学生可以上多门课程

① 在Student类中添加List集合属性

// 1.一个学生可以上多门课程,把课程名称放到List集合中
    private List<String> courseList;
// 2.生成get和set方法
// 3.重新生成toString()方法

② 创建spring配置文件:bean-diref.xml,引入util约束

<!-- 添加3行带有util的配置 -->

<?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"

       xsi:schemaLocation="
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd

       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

③ 配置xml文件完成注入

<!--引用集合类型bean注入-->
<bean id="stuUtil" class="cn.tedu.spring.dilistmap.Student">
    <property name="sName" value="孔慈"/>
    <property name="age" value="36"/>
    <property name="teacherMap" ref="teacherMap"></property>
    <property name="courseList" ref="courseList"></property>
</bean>

<util:map id="teacherMap">
    <entry>
        <key>
            <value>10000</value>
        </key>
        <value>小泽老师</value>
    </entry>
    <entry>
        <key>
            <value>10001</value>
        </key>
        <value>王老师</value>
    </entry>
</util:map>

<util:list id="courseList">
    <value>Spring</value>
    <value>SpringMVC</value>
    <value>MyBatis</value>
</util:list>

④ 创建测试方法进行测试

// 引用集合类型bean注入(util)
@Test
public void testRefBean(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-diref.xml");
    Student student = context.getBean("stuUtil", Student.class);
    System.out.println("student = " + student);
}

4.9 p命名空间

这也是一种注入方式,可以在xml中定义命名空间或者叫名称空间,可以简化xml代码。

在bean-diref.html中操作

① 在xml配置文件中定义命名空间

xmlns:p="http://www.springframework.org/schema/p"

② 在xml文件进行命名空间属性注入

<!-- p命名空间注入: 注入学生属性 -->
<bean id="studentp" class="cn.tedu.spring.iocxml.dimap.Student" p:sid="100" p:sname="铁锤妹妹" p:courseList-ref="courseList" p:teacherMap-ref="teacherMap">

③ 测试

// p命名空间注入测试用例
@Test
public void testRefP(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-diref.xml");
    Student studentp = context.getBean("studentp", Student.class);
    System.out.println("studentp = " + studentp);
}

4.10 引入外部属性文件

  • 说明

    ​ 当前所有的配置和数据都在xml文件中,一个文件中有很多bean,修改和维护起来很不方便,生产环境中会把特定的固定值放到外部文件中,然后引入外部文件进行注入,比如数据库连接信息。

  • 示例

    将外部文件中的数据引入xml配置文件进行注入

① pom.xml中引入数据库相关依赖,并刷新maven

<!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.15</version>
</dependency>

<!-- 数据源,连接池依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.21</version>
</dependency>

② resources目录下创建外部属性文件,一般为properties格式,定义数据库信息,比如:jdbc.properties

jdbc.user=root
jdbc.password=root
jdbc.url=jdbc://mysql://localhost:3306/spring
jdbc.driver=com.mysql.cj.jdbc.Driver

③ 创建spring配置文件bean-jdbc.xml,引入context的命名空间

使用context可以为XML外部实体注入定义,使得解析器在解析XML文档时可以正确地识别外部实体

<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/context 
       http://www.springframework.org/schema/context/spring-context.xsd
       
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    
    <!-- 引入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!-- 完成数据库信息注入 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
    </bean>
</beans>

④ 创建包jdbc,包中创建测试类 TestJdbc

public class TestJdbc {

    // 外部文件属性引入测试用例
    @Test
    public void demo02(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean-jdbc.xml");
        DruidDataSource druidDataSource = context.getBean("druidDataSource", DruidDataSource.class);
        System.out.println(druidDataSource.getUrl());
    }
}

4.11 bean的作用域

  • 说明

    ​ bean的作用域,是指在交给spring创建bean对象时,可以指定是单实例还是多实例,通过bean标签中的scope属性来指定,默认是单实例。

  • 单实例和多实例

    • 单实例

      单实例(Singleton)是指某个类只能创建唯一的一个实例对象,并且该类提供一个全局的访问点(静态方法)来让外界获取这个实例,常常用在那些只需要一个实例来处理所有任务的场景下,例如配置类或数据库连接池等。

    • 多实例

      多实例(Multiple Instance)则是指可以在同一个类的定义下,创建多个实例对象。每个对象都是相互独立的,有自己的状态和行为;常常用于需要同时处理多个任务的场景。

在Spring中可以通过配置bean标签的scope属性来之地那个bean的作用域范围,具体如下

取值含义创建对象时机
singleton(默认在IoC容器中,这个bean的对象为单实例IoC容器初始化时
prototype这个bean在IoC容器中有多个实例获取bean时

案例演示

① 创建包scope,并在包下创建类Sku

public class Sku {
    
}

② 创建spring的配置文件:bean-scope.xml

<!-- singleton:单实例 -->
<!-- 之后改为prototype多实例测试 -->
<bean id="sku" class="cn.tedu.spring.scope.Sku" scope="singleton"></bean>

③ 创建测试类TestOrders

@Test
public void testOrders(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-scope.xml");
    Orders orders = context.getBean("orders", Orders.class);
    System.out.println("orders = " + orders);
    Orders orders1 = context.getBean("orders", Orders.class);
    System.out.println("orders1 = " + orders1);
}
// 单实例,sku1和sku2地址相同
// 多实例,sku1和sku2地址不同

4.12 bean的生命周期

是指一个bean对象从创建到销毁的整个过程。

4.12.1 bean的完整生命周期
  1. 实例化阶段(bean对象创建)

    在这个阶段中,容器会创建一个Bean的实例,并为其分配空间。这个过程可以通过构造方法完成。

  2. 属性赋值阶段

    在实例化完Bean之后,容器会把Bean中的属性值注入到Bean中,这个过程可以通过set方法完成。

  3. 初始化阶段(bean对象初始化)

    在属性注入完成后,容器会对Bean进行一些初始化操作;

    • 初始化之前:bean的后置处理器可以接收到bean,此处可以对bean做相关操作。
    • 初始化之后:bean的后置处理器可以接收到bean,此处可以对bean做相关操作。
  4. 使用阶段

    初始化完成后,Bean就可以被容器使用了

  5. 销毁阶段

    容器在关闭时会对所有的Bean进行销毁操作,释放资源。

4.12.2 生命周期验证

① 创建包life,创建类User

package cn.tedu.spring.life;

import org.springframework.beans.BeansException;

public class User {
    private String username;

    // 1.无参数构造
    public User(){
        System.out.println("1-bean对象创建,调用无参数构造。");
    }

    // 3.初始化阶段
    public void initMethod(){
        System.out.println("3-bean对象初始化,调用指定的初始化方法");
    }

    // 5.销毁阶段
    public void destoryMethod(){
        System.out.println("5-bean对象销毁,调用指定的销毁方法");
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
        // 2.给bean对象属性赋值
        System.out.println("2-通过set方法给bean对象赋值。");
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                '}';
    }
}

② 创建spring配置文件 bean-life.xml

<bean id="user" class="cn.tedu.spring.iocxml.life.User" scope="singleton" 
      init-method="initMethod" destroy-method="destroyMethod">
    <property name="username" value="聂风"></property>
</bean>

③ 创建测试类TestUser测试

@Test
public void testUser(){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-life.xml");
    User user = context.getBean("user", User.class);
    // 4.bean对象初始化完成,可以使用
    System.out.println("4-bean对象初始化完成,开发者可以使用了。");
    // 销毁bean
    context.close();
}

④ 后置处理器处理演示,新建类MyBeanPost

public class MyBeanPost implements BeanPostProcessor {
    // BeanPostProcessor接口
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("3之前:bean后置处理器,在初始化之前执行。" + beanName + ":" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("3之后:bean后置处理器,在初始化之后执行。" + beanName + ":" + bean);
        return bean;
    }
}

⑤ 在spring的配置文件bean-life.xml中进行后置处理器配置

<!-- bean的后置处理器需要放到IoC容器中才能生效 -->
<bean id="myBeanPost" class="cn.tedu.spring.life.MyBeanPost"></bean>

⑥ 运行测试类测试

4.12.3 bean生命周期扩展
  • bean的初始化和销毁应用场景

    • 初始化
      • 创建连接池
      • 加载资源文件
      • 进行数据校验
    • 销毁
      • 关闭连接池
      • 保存数据
      • 释放占用的资源
  • 后置处理器

    实现自定义的Bean对象处理逻辑,比如在Bean实例化之前或者之后对Bean对象进行自定义的修改,可以方便地实现自定义逻辑和修改Bean对象的行为。

4.13 基于xml自动装配

自动装配说明:

根据指定的策略,在IoC容器中匹配某一个bean,自动为指定的bean中的所依赖的类类型或者接口类型属性赋值。

环境准备

① 创建包auto,创建部门和员工的两个java类

② 部门类 Dept

public class Dept {
    private String dName;

    @Override
    public String toString() {
        return "Dept{" +
                "dName='" + dName + '\'' +
                '}';
    }

    public String getdName() {
        return dName;
    }

    public void setdName(String dName) {
        this.dName = dName;
    }
}

③ 员工类 Emp

public class Emp {
    private String eName;
    private Dept dept;

    @Override
    public String toString() {
        return "Emp{" +
                "eName='" + eName + '\'' +
                ", dept=" + dept +
                '}';
    }

    public String geteName() {
        return eName;
    }

    public void seteName(String eName) {
        this.eName = eName;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }
}

④ 创建spring配置文件bean-auto.xml

<!--通过byType和byName自动装配-->
<bean id="dept" class="cn.tedu.spring.iocxml.auto.Dept">
    <property name="dName" value="技术部"></property>
</bean>

<!--autowire="byType" 或者 autowire="byName"-->
<bean id="emp" class="cn.tedu.spring.iocxml.auto.Emp" autowire="byType">
    <property name="eName" value="步惊云"></property>
</bean>

⑤ 创建测试类测试TestAuto

@Test
public void testAuto(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean-auto.xml");
    Emp emp = context.getBean("emp", Emp.class);
    System.out.println("emp = " + emp);
}

使用bean标签的autowire属性设置自动装配效果;

自动装配方式:byType

​ byType: 根据类型匹配IoC容器中的某个兼容类型的bean,为属性自动赋值;

​ 1. 如果在IoC中,没有任何一个兼容类型的bean能够为属性赋值,则改属性不装配,默认值为null;

​ 2. 如果在IoC中,有多个兼容类型的bean能够为属性赋值,则抛出异常 NoUniqueBeanDefinitionException

自动装配方式:byName

​ byName:将自动装配的属性名,作为bean的id在IoC容器中匹配相对应的bean进行赋值

5 基于注解管理bean

​ 从Java5开始,Java增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。

​ Spring从2.5版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化Spring的xml配置。

Spring通过注解实现自动装配:

  1. 引入依赖
  2. 开启组件扫描
  3. 使用注解定义Bean
  4. 依赖注入

5.1 创建子工程

子工程:spring-ioc-annotation

在pom.xml中添加springframework的依赖,刷新maven

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.24</version>
    </dependency>
</dependencies>

5.2 开启组件扫描

​ Spring默认不使用注解装配Bean,因此需要在Spring的xml配置中,通过context:component-scan元素开启Spring Beans的自动扫描功能。开启此功能后,Spring会自动从扫描指定的包(base-package属性设置)及其子包下的所有类,如果类上使用了@Component注解,就将该类装配到容器中。

① 工程下创建包:cn.tedu.spring.bean

② resources目录下创建spring配置文件 bean.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/context
       http://www.springframework.org/schema/context/spring-context.xsd

       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 2.开启组件扫描,让spring可以通过注解方式实现bean管理,包括创建对象、属性注入 -->
    <!-- base-package:扫描哪个包中的注解,在cn.tedu的包或者子包中建了类,在
     类上、属性上、方法上加了spring的@Component注解,这里就能扫描到-->
    <context:component-scan base-package="cn.tedu.spring"></context:component-scan>
    
</beans>

5.3 使用注解定义Bean

Spring提供了以下多个注解,这些注解可以直接标注在java类上,将它们定义成Spring Bean。

注解说明
@Component该注解用于描述Spring中的Bean,它是一个泛化的概念,仅仅标识容器中的一个组件(Bean),并且可以作用在任何层次,例如Service层、Dao层等,使用时只需将该注解标注在相应的类上即可。
@Respository该注解用于数据访问层(Dao层)的类标识为Spring中的Bean,功能与@Component相同。
@Service该注解通常作用在业务层(Service层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同。
@Controller该注解通常作用在控制层(如SpringMVC的Controller),用于将控制层的类标识为Spring中的Bean,其功能与@Component相同。

③ 创建User类,并添加注解

// value可以不写,默认为类名首字母小写
//@Component(value = "user")  // <bean id="user" class="xxx">
//@Repository
//@Service
@Controller
public class User {

}

④ 创建测试类测试TestUser

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

5.4 @Autowired注入

单独使用@Autowired注解,默认根据类型装配(byType)

@Autowired注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须存在,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在就注入,不存在也不报错。

5.4.1 属性注入

① cn.tedu.spring下创建包autowired,并在autowired下创建两个包:controller包 和 service包

② 控制器层controller.UserController

public class UserController {
    private UserService userService;
    
    public void addController(){
        System.out.println("controller is running...");
        userService.addService();
    }
}

③ 服务层service.UserService接口

public interface UserService {
    public void addService();
}

④ 服务层service.UserServiceImpl接口的实现类

public class UserServiceImpl implements UserService {
    @Override
    public void addService() {
        System.out.println("service is running...");
    }
}

⑤ 在UserController和UserSerivceImpl中添加@Controller注解和@Service注解

⑥ 在UserController中注入UserServiceImpl

@Controller
public class UserController {
    // 注入service
    // 第一种方式:属性注入
    @Autowired // 根据类型找到对象,完成注入
    private UserService userService;
}

⑦ 测试类测试autowired.TestUserController

public class TestUserController {

    @Test
    public void testUserController(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        UserController controller = context.getBean(UserController.class);
        controller.addController();
    }
}
5.4.2 set注入

① 修改UserController类

// 方式二:通过set方法注入
private UserService userService;

@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}

② 测试

5.4.3 构造方法注入

① 修改UserController类

// 第三种方式:构造方法注入
private UserService userService;

@Autowired
public UserController(UserService userService) {
    this.userService = userService;
}

② 测试

5.4.4 形参上注入

① 修改UserController类

// 第四种方式:形参注入
private UserService userService;

public UserController(@Autowired UserService userService) {
    this.userService = userService;
}

② 测试

5.4.5 只有一个构造函数,无注解

① 修改UserController类

// 第五种方式:只有一个有参数构造函数,无注解
private UserService userService;

public UserController(UserService userService) {
    this.userService = userService;
}

② 测试

5.4.6 @Autowire注解和@Qualifier注解联合

① 再创建一个UserService接口的实现类service.UserServiceImpl2

@Service
public class UserServiceImpl2 implements UserService{
    @Override
    public void addService() {
        System.out.println("service2 is running...");
    }
}

② 测试发现报错

​ 因为UserService有两个实现类,而@Autowired注解根据byType定位,所以找到了两个实现类

③ 解决:修改UserController (使用两个注解)

// 1.第六种方式:根据类型和名称一起注入
@Autowired
@Qualifier(value = "userServiceImpl2")  // 类名首字母小写
private UserService userService;

// 2.将构造函数注释

5.5 @Resource注入

@Resource注解也可以完成属性注入。它和@Autowired注解的区别如下

  • @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该解释是标准注解,更加具有通用性,而@Autowired注解是Spring框架自己的。
  • @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name,通过name找不到的话会自动启动通过类型byType装配。而@Autowired注解默认根据类型装配byType,如果想根据名称匹配,需要配合@Qualifier注解一起使用。
  • @Resource注解用在属性上、setter方法上
  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

案例演示

① 工程下创建包 resource,和之前一样,创建controller和service两个包,并创建UserController类和UserService接口以及该接口的实现类UserServiceImpl

② 修改UserController

@Controller("myUserController")
public class UserController {
    // 根据名称进行注入
    @Resource(name="myUserService")
    private UserService userService;

    public void add(){
        System.out.println("controller...");
        userService.add();
    }
}

③ 修改ServiceControllerImpl1

@Service("myUserService")
public class UserServiceImpl implements UserService {

⑤ 测试

  1. 指定@Resource中的name,则根据名称装配
  2. 未指定name时,则根据属性名装配
  3. 未指定name,属性名也不一致,则根据类型装配

5.6 Spring全注解开发

全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件。

① 工程下创建包:config,创建类SpringConfig

// 配置类
@Configuration
// 开启组件扫描
@ComponentScan("cn.tedu.spring")
public class SpringConfig {
}

② 在resource下创建测试类进行测试

public class TestUserControllerAnno {
    public static void main(String[] args) {
        // 加载配置类
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        UserController controller = context.getBean(UserController.class);
        controller.add();
    }
}

在这里插入图片描述

感觉不错的话,动手点个赞吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/508700.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我的创作纪念日(2)设置飞机进行调优

文章目录 前言 2.1 电池设置 2.2 电机设置 2.3 PID控制器初始设置 前言 以下参数应根据你的飞机的规格正确设置。每一个都会影响调优过程的质量。 2.1 电池设置 确保你的 VTOL 电机的推力曲线尽可能的线性是非常重要的。一个线性的推力曲线意味着电机产生的实际推力的变化…

GuassDB数据库的GRANT REVOKE

目录 一、GaussDB的权限概述 二、GaussDB权限设计建议 三、GaussDB的GRANT命令 1.功能说明 2.注意事项 3.常用语法 四、GaussDB的REVOKE命令用法 1.功能说明 2.注意事项 3.常用语法 五、GaussDB示例 1.GRANT 语句示例 2.REVOKE 语句示例 一、GaussDB的权限概述 在…

电气设备绝缘在线监测系统的原理

摘要&#xff1a;在线监测是控制好电气设备绝缘的重要方式&#xff0c;为电力系统稳定奠定重要基础。在线监测电气设备时&#xff0c;要利用检测技术促进电力系统运行效率提升&#xff0c;让电气设备在具体工作过程中发挥更大作用。本次研究中主要分析了电气设备绝缘在线监测系…

单开网页应用利器 - BroadcastChannel

前言 前段时间在做一个基于 psd 模板生成图片的应用&#xff0c;其中重要的功能就是打开编辑器页面来设计出图。但是有个问题&#xff0c;每当我点击一个模板&#xff0c;就会新开一个浏览器页签。现代浏览器是以空间换时间的运行思路来提高效率&#xff0c;这就导致了内存开销…

单片机c51中断 — 中断键控流水灯

项目文件 文件 关于项目的内容知识点可以见专栏单片机原理及应用 的第五章&#xff0c;中断 在第4章的实例2中&#xff0c;按键检测是采用查询法进行的&#xff0c;其流程图如图所示 问题是这样的&#xff1a;由于查询法 -按键查询、标志位修改及彩灯循环几个环节是串联关系…

微信小程序从入门到精通

目录 前言一&#xff0c;初学小程序1.1 小程序概述1.2 基础配置1.2.1 注册开发账号1.2.2 获取AppID1.2.3 微信开发者工具1.2.4 修改代理模式 1.3 第一个小程序1.4 开发文档1.5 机型1.6 项目基本结构1.6.1 页面内部文件1.6.2 app.json1.6.3 project.config.json1.6.4 sitemap.js…

开关电源基础07:离线式开关电源变压器设计(1)

说在开头&#xff1a;关于第六届索尔维会议&#xff08;2&#xff09; 爱因斯坦一天都挺开心的&#xff0c;反正难题出给了玻尔&#xff0c;他还在自己的房间里拉起了小提琴&#xff0c;有人说爱因斯坦小提琴拉的跟锯木头一样&#xff0c;那也不至于那么夸张&#xff0c;但是水…

RK3568平台开发系列讲解(Linux内存篇)Linux内存管理框架

🚀返回专栏总目录 文章目录 一、内核态内存分配二、用户态内存分配三、内存篇章更新哪些内容沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们一起将整个内存管理的体系串起来。 对于内存的分配需求,可能来自内核态,也可能来自用户态。 一、内核态内存分配…

Spring Boot集成ShardingSphere实现读写分离 | Spring Cloud 43

一、读写分离 1.1 背景 面对日益增加的系统访问量&#xff0c;数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说&#xff0c;将数据库拆分为主库和从库&#xff0c;主库负责处理事务性的增删改操作&#xff0c;从库负责处理查询操…

NetApp 利用适用于混合云的实时解决方案解决芯片设计方面的数据管理挑战

电子设计自动化 (EDA) 成本持续增加&#xff0c;而周期时间缩短。这些都为 EDA 设计带来了前所未有的挑战&#xff0c;对现代高性能工作流的需求变得从未如此巨大。 联想凌拓芯片设计行业存储解决方案及最佳实践 联想凌拓芯片行业数据存储与管理解决方案&#xff0c;针对EDA…

驱动设计的思想:面向对象/分层/分离(以LED操作为例)

1. 面向对象 字符设备驱动程序抽象出一个file_operations结构体&#xff1b; 对于LED&#xff0c;写的程序针对硬件部分抽象出led_operations结构体。 2. 分层 上下分层&#xff0c;之前写的LED驱动程序就分为2层&#xff1a; ① 上层实现硬件无关的操作&#xff0c;比如注册…

一文搞懂——MySQL索引事务JDBC

目录 一、索引 1.1 索引是什么&#xff1f; 1.2 怎样创建索引&#xff1f; 1.3 索引使用的数据结构是什么&#xff1f; 1.4 索引相关的概念 1.5 索引失效的原因 二、事务 2.1 事务是什么&#xff1f; 2.2 为什么要使用事务&#xff1f; 2.3 事务的使用 2.4 事务的特性…

黑马头条(学习笔记)

​ 目录 一. 项目概述 二、项目初始化 移动端 REM 适配&#xff1a; 关于 PostCSS 配置文件&#xff1a; Autoprefixer 插件的配置 &#xff1a; postcss-pxtorem 插件的配置&#xff1a; 关于字体图标: 配置路由&#xff1a; 封装请求模块: 三&#xff1a;登录注册&…

ChatGPT有话说:虚拟现实 VS 增强现实

以下内容均为ChatGPT根据用户引导和提示作出的阐述和说明。 一、引言 虚拟现实和增强现实是当前最受瞩目的创新技术。虚拟现实是指利用计算机生成的虚拟环境&#xff0c;用户可以通过佩戴VR头戴式显示器等设备完全沉浸在其中&#xff0c;感受到身临其境的感觉。而增强现实则是…

三分钟上手安全渗透系统Kali Linux

kali linux系统集成了常用的安全渗透工具&#xff0c;省去了安装工具的时间&#xff0c;做安全相关的工作是非常推荐使用的。 安装Kalii Linux 安装系统 一般使用虚拟机进行安装&#xff0c;Kali Linux基于Debian内核&#xff0c;虚拟机的操作系统选择Debian 7.x 64 选择系统…

【JAVA】用Java实现简易图书管理系统

【JAVA】用Java实现简易图书管理系统 1. 设计背景和系统功能和设计方法1.1设计背景1.2系统功能1.3设计方法 2. 设计思路3. 设计模块和代码实现3.1 Book类的实现3.2 BookList类的实现(书架)3.3 User类的实现&#xff08;用户类&#xff09;3.3.1 AdminUser&#xff08;管理员类&…

家用洗地机好用吗?值得推荐的家用洗地机

谁说家务苦差事&#xff1f;现在有了洗地机&#xff0c;家庭清洁变得更加简单、快捷、干净&#xff0c;让您轻松应对家庭日常清洁的要求。洗地机采用先进的技术&#xff0c;自动感应地面脏污&#xff0c;智能调节出水量和吸力&#xff0c;不仅能够保持地面清洁&#xff0c;更能…

深入理解MapReduce:使用Java编写MapReduce程序【上进小菜猪】

&#x1f4ec;&#x1f4ec;我是上进小菜猪&#xff0c;沈工大软件工程专业&#xff0c;爱好敲代码&#xff0c;持续输出干货。 MapReduce是一种用于处理大规模数据集的并行编程模型。由于其高效性和可扩展性&#xff0c;MapReduce已成为许多大型互联网公司处理大数据的首选方…

隐语v0.8.2版本更新,首次发布TEEU

隐语v0.8.2版本更新&#x1f31f; 应用层 机器学习&#xff1a; - MPC 纵向 LR &#xff08;SSRegression&#xff09;新增 Policy SGD 优化器和 Early Stopping 支持&#xff0c;减少调参成本&#xff0c;加快收敛速度&#xff1b; - WOE 分箱进行了若干优化&#xff0c;性…

HR SaaS市场竞争火热,肯耐珂萨缘何持续领跑? |爱分析调研

摘要&#xff1a; 中国人力资源数字化市场规模快速增长&#xff0c;各路厂商云集&#xff0c;呈现百花齐放的态势。作为人力资源管理一体化云解决方案的龙头服务商&#xff0c;肯耐珂萨坚定执行价值导向的差异化竞争策略&#xff0c;15年引领行业创新&#xff0c;依托行业领先方…