【Spring进阶系列丨第六篇】Spring的Bean管理(基于注解)

文章目录

  • 一、说明
  • 二、用于创建对象的
    • 2.1、Component注解
      • 2.1.1、定义Bean
      • 2.1.2、主配置文件配置扫描注解
      • 2.1.3、测试
      • 2.1.4、Component注解总结
    • 2.2、Controller注解
    • 2.3、Service注解
    • 2.4、Repository注解
  • 三、用于注入数据的
    • 3.1、Autowired注解
      • 3.1.1、定义Bean
      • 3.1.2、主配置文件配置扫描注解
      • 3.1.3、测试
      • 3.1.4、改造
      • 3.1.5、总结
    • 3.2、Qualifier注解
      • 3.2.1、定义Bean
      • 3.2.2、总结
    • 3.3、Resource注解
      • 3.3.1、定义Bean
      • 3.3.2、总结
    • 3.4、Value注解
      • 3.4.1、案例1
        • 3.4.1.1、定义Bean
        • 3.4.1.2、测试
      • 3.4.2、案例2
        • 3.4.2.1、创建db.properties文件
        • 3.4.2.2、主配置文件需要将properties文件引入进来
        • 3.4.2.3、定义Bean
        • 3.4.2.4、测试
      • 3.4.3、总结
    • 3.5、大总结
  • 四、用于改变Bean的作用域的
    • 4.1、定义Bean
    • 4.2、测试
    • 4.3、总结
  • 五、和Bean的生命周期相关的
    • 5.1、定义Bean
    • 5.2、测试
    • 5.3、总结

在这里插入图片描述

一、说明

回顾一下基于xml配置的Spring对Bean的管理 ,对Bean的完整管理如下所示:

<bean id="" class="" init-method="" destroy-method="" scope="">
    <property name="" value=""/>
    <property name="" ref=""/>
</bean>

分析可以发现:我们对Bean的管理就四个方面,分别是:

  • 用于创建对象的
  • 用于注入数据的
  • 用于改变Bean的作用域的
  • 和Bean的生命周期相关的

其实对于注解来说,也是包括了这四个方面,换句话说,使用注解的方式管理Bean和使用xml的方式管理Bean作用是完全一样的,区别仅仅在于配置的形式不同而已。

二、用于创建对象的

2.1、Component注解

2.1.1、定义Bean

@Component
public class DogService {
    
}

2.1.2、主配置文件配置扫描注解

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

    <!-- 告诉spring在创建容器时要扫描的包   -->
    <context:component-scan base-package="cn.bdqn"/>

</beans>

2.1.3、测试

 @Test
public void testDogServiceImpl() throws Exception{
        // 1、读取主配置文件信息,获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

        DogServiceImpl dogService = (DogServiceImpl) ac.getBean("dogServiceImpl");

        System.out.println(dogService);
}

2.1.4、Component注解总结

  • 作用

    ​ 用于把对当前修饰的类创建出来,并存放到Spring容器中。

  • 属性

    ​ a. 用该注解所创建的对象默认的id名称是当前类名,且首字母改小写

    ​ b. 可以通过value属性手动的指定bean的id。

2.2、Controller注解

​ 一般用在表现层,例如SpringMVC、Struts2

2.3、Service注解

​ 一般用在业务层,例如Service层

2.4、Repository注解

​ 一般用在持久层7.2.5、总结

  • Controller、Service、Repository这三个注解他们的作用和属性与Component是一模一样。
  • 既然一模一样,之所以Spring框架还要提供,主要是Spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰。
  • 他们的作用就和在XML配置文件中编写一个标签实现的功能是一样的

三、用于注入数据的

3.1、Autowired注解

作用:

​ 自动按照类型注入。

3.1.1、定义Bean

// 用户service接口
public interface UserService {
	public void printUserDao();
}
// 用户service接口实现,bean的名称改为:userService
@Service("userService")
public class UserServiceImpl implements UserService {
	
  	@Autowired
    private UserDao userDao;

    // 打印UserDao,看是否可以将值打印出来,如果打印出来说明值真的注入成功了
    public void printUserDao(){
        System.out.println(userDao);
    }
}
// 用户UserDao接口
public interface UserDao {

}
// 用户UserDao接口实现,bean的名称改为:userDao01
@Repository("userDao01")
public class UserDaoImpl01 implements UserDao {

}

3.1.2、主配置文件配置扫描注解

<beans>
	<!-- 告诉spring在创建容器时要扫描的包   -->
    <context:component-scan base-package="cn.bdqn"/>
</beans>

3.1.3、测试

@Test
public void testUserServiceImpl() throws Exception{
        // 1、读取主配置文件信息,获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

        UserService userService = (UserService) ac.getBean("userService");

        userService.printUserDao();	// cn.bdqn.dao.impl.UserDaoImpl@7a52f2a2
}

3.1.4、改造

假设系统中存在两个UserDao的实现,现在再添加一个。现在再添加测试:

@Repository("userDao02")
public class UserDaoImpl02 implements UserDao {

}

再次运行程序,会发现,程序报错:

No qualifying bean of type 'cn.bdqn.dao.UserDao' available: expected single matching bean but found 2: userDao01,userDao02

翻译:没有找到一个可用的UserDao,期望能够匹配一个,但是发现了2个。换句话说,由于是根据类型匹配的,而userDao01,userDao02都是符合注入的类型的,不知道要用哪个了.

该如何解决呢?既然Spring不知道具体要用哪个了,那我们由开发者来去指定其中的一个告诉Spring你就用这个注入就可以了,那么实现方式就是:通过名称告诉即可

解决方案:

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

  	// 将变量的名称修改为userDao01,那么依赖注入的时候就使用UserDaoImpl01
    @Autowired
    private UserDao userDao01;
}

再次测试,程序正常执行。

3.1.5、总结

  • 该注解是根据类型自动注入,假如只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。
  • 如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
  • 如果容器中有多个bean对象类型和要注入的变量类型匹配,则可能会发生错误,解决办法就是修改变量的名称为其中的某一个bean的名称

3.2、Qualifier注解

​ 在7.3.1章节使用Autowired注解的时候,会存在一个问题,就是如果系统中存在多个类型的Bean都匹配的时候,就会找不到到底要使用哪个Bean对象了,会报错,我们采取的解决办法是:修改变量名即可解决 , 但是这种做法实际上是挺菜的,我现在就想使用userDao这个变量名,那么能否有一种更好的解决办法呢?答案是肯定的,即使用Qualifier注解。

3.2.1、定义Bean

​ Bean的定义,仍然采用7.3.1章节所定义好的Bean,唯一的区别是UserServiceImpl这个Bean,修改如下:

public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier(value = "userDao01")	// 通过此注解中的value属性明确指定要用哪个name的bean
    private UserDao userDao;
}

3.2.2、总结

  • 在按照类型注入的基础之上再按照名称注入,它在给类的成员变量注入时不能单独使用,需要搭配Autowired注解。

3.3、Resource注解

3.3.1、定义Bean

​ Bean的定义,仍然采用7.3.1章节所定义好的Bean,唯一的区别是UserServiceImpl这个Bean,修改如下:

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

    @Resource(name = "userDao01")
    private UserDao userDao;
}

3.3.2、总结

  • 该注解采用的是直接按照bean的id注入,它可以独立使用,name用于指定bean的id。

注意:

使用Autowired、Qualifier以及Resource这三个注解都只能注入其他bean类型的数据,对于基本数据类型和String类型是无法通过使用该3个注解实现。同时,对于集合数据类型的注入只能通过XML来实现。


3.4、Value注解

作用:

​ 用于注入基本类型和String类型的数据。

3.4.1、案例1

3.4.1.1、定义Bean
@Component("jdbcUtils")
public class JdbcUtils {

    @Value("com.mysql.jdbc.Driver")
    private String driverClass;
}
3.4.1.2、测试
@Test
public void testJdbcUtils() throws Exception{
    // 1、读取主配置文件信息,获取核心容器对象
    ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

    JdbcUtils utils = (JdbcUtils) ac.getBean("jdbcUtils");

    System.out.println(utils);	// com.mysql.jdbc.Driver
}

3.4.2、案例2

如果Value注解用于案例1,那这样太菜了,我们要为driverClass这个变量赋值,那岂不是直接赋值得了,还需要搞一个Value直接赋值吗?显然是没有必要的,所以一般来说,Value注解常用于对配置文件内容的读取。

3.4.2.1、创建db.properties文件
driverClass=com.mysql.jdbc.Driver
port=3306
3.4.2.2、主配置文件需要将properties文件引入进来
<beans>
	
  	<!-- 告诉spring在创建容器时要扫描的包   -->
    <context:component-scan base-package="cn.bdqn"/>
    
  	<!-- 将properties文件引入到Spring框架中-->
    <context:property-placeholder location="classpath:db.properties"/>
</beans>
3.4.2.3、定义Bean
@Component("jdbcUtils")
public class JdbcUtils {

    @Value("${driverClass}")
    private String driverClass;

    @Value("${port}")
    private Integer port;
}
3.4.2.4、测试
@Test
public void testJdbcUtils() throws Exception{
    // 1、读取主配置文件信息,获取核心容器对象
    ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

    JdbcUtils utils = (JdbcUtils) ac.getBean("jdbcUtils");

    System.out.println(utils);	// com.mysql.jdbc.Driver,3306
}

3.4.3、总结

该注解通过可以实现对基本数据类型和String类型的注入,并且是支持使用Spring的EL表达式。那么对于Spring的EL表达式的语法就是:${表达式}。

3.5、大总结

以上注解的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的

四、用于改变Bean的作用域的

方式:

  • 使用Scope注解,作用是用于指定bean的作用范围。该注解有一个value属性,可以指定范围的取值,常用取值:singleton、 prototype
  • 该Scope注解默认的value值就是单例的【singleton】

4.1、定义Bean

Bean的定义,仍然采用7.3.1章节所定义好的Bean,唯一的区别是UserServiceImpl这个Bean修改作用域,修改如下:

@Service("userService")
@Scope("singleton")
public class UserServiceImpl implements UserService{
  
}

4.2、测试

@Test
public void testUserServiceImpl() throws Exception{
        // 1、读取主配置文件信息,获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

        UserService userService = (UserService) ac.getBean("userService");
        UserService userService2 = (UserService) ac.getBean("userService");

        System.out.println(userService == userService2); // true
}

改造一下:如果将上例的UserServiceImpl中的Scope改为prototype,则再次测试的时候会返回false。

4.3、总结

Scope该注解的作用就和在bean标签中使用scope属性实现的功能是一样的

五、和Bean的生命周期相关的

5.1、定义Bean

​ Bean的定义,仍然采用7.3.1章节所定义好的Bean,唯一的区别是UserServiceImpl这个Bean添加了一个初始化方法和销毁方法。

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

    @PostConstruct
    public void init(){
        System.out.println("对象初始化了");
    }
    
    @PreDestroy
    public void destroy(){
        System.out.println("对象销毁了");
    }
}

5.2、测试

@Test
public void testUserServiceImpl() throws Exception{
        // 1、读取主配置文件信息,获取核心容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

        ac.close();
}

// 对象初始化了
// 对象销毁了

5.3、总结

这个两个注解作用就和在bean标签中使用init-method和destroy-methode的作用是一样的。


在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Selenium-java元素等待三种方式

第二种方式需要写在创建driver时的代码下面 第三种则是对每个定位元素进行配置

探索Commons Exec管理外部进程

第1章&#xff1a;引言 咱们在日常的Java开发中&#xff0c;经常会遇到需要调用外部进程或命令的场景。比如说&#xff0c;可能需要在Java程序中启动一个外部的脚本&#xff0c;或者执行一个系统命令。Java虽然提供了Runtime和ProcessBuilder类来处理这类需求&#xff0c;但说…

Docker Linux快速安装及Nginx部署

前言 最近正在部署一套新的Linux服务器环境&#xff0c;基于Docker来部署所有的应用&#xff0c;顺便整理了一套经过验证的操作手册&#xff0c;以便大家遇到类似需求时&#xff0c;可以直接拿来用。 本文会涉及以下知识点&#xff1a;Docker的Linux安装和卸载、Docker用户组…

【网络安全】Nessus部署自动更新和端口权限开放

文章目录 Nessus 自动更新配置Nessus服务端口开放Nessus profession 版本需要开放端口Sensor ProxyTenable Security Center (TSC)Tenable OT Security (TOT)Tenable OT Security Enterprise Manager (IEM)Tenable OT Security Industrial Core Platform (ICP)Tenable OT Secur…

基于卷积神经网络的回归分析

目录 背影 卷积神经网络CNN的原理 卷积神经网络CNN的定义 卷积神经网络CNN的神经元 卷积神经网络CNN的激活函数 卷积神经网络CNN的传递函数 卷积神经网络的回归分析 完整代码:卷积神经网络的回归分析(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.net/download/…

基于深度学习大模型实现离线翻译模型私有化部署使用,通过docker打包开源翻译模型,可到内网或者无网络环境下运行使用,可以使用一千多个翻译模型语言模型进行翻译

基于深度学习大模型实现离线翻译模型私有化部署使用,通过docker打包开源翻译模型,可到内网或者无网络环境下运行使用,可以使用一千多个翻译模型语言模型进行翻译,想要什么语种直接进行指定和修改就行。 环境要求,电脑内存低于8G建议不要尝试了,有无GPU都可以运行,但是有…

秋招复习之栈与队列

前言 1 栈 「栈 stack」是一种遵循先入后出逻辑的线性数据结构。 我们可以将栈类比为桌面上的一摞盘子&#xff0c;如果想取出底部的盘子&#xff0c;则需要先将上面的盘子依次移走。我们将盘子替换为各种类型的元素&#xff08;如整数、字符、对象等&#xff09;&#xff0c…

释放创造力:可视化页面渲染引擎在低代码开发平台的应用

本文由葡萄城技术团队发布。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 什么是页面渲染引擎? 页面渲染引擎是低代码开发平台的核心组件之一&#xff0c;它负责将开发者设计的页面布局和用户…

Docker 存储卷管理

一、存储卷简介 存储卷是一种方便、灵活、高效的Docker容器内数据存储方式。存储卷可以在容器内的不同进程间共享数据&#xff0c;并且可以在容器之间共享和重用。 二、存储卷的优点 可以在容器之间共享和重用&#xff0c;避免了在不同容器之间复制数据的繁琐。对数据卷的修…

Flume基础知识(七):Flume 事务与 Flume Agent 内部原理

1. Flume 事务详解 2. Flume Agent 内部原理 重要组件&#xff1a; 1&#xff09;ChannelSelector ChannelSelector 的作用就是选出 Event 将要被发往哪个 Channel。其共有两种类型&#xff0c; 分别是 Replicating&#xff08;复制&#xff09;和 Multiplexing&#xff08;多…

linux 的直接direct io

目录 什么是 Direct IO java 支持 使用场景 数据库 反思 在之前的文章零拷贝基础上&#xff0c;有一个针对那些不需要在操作系统的 page cache 里保存的情况&#xff0c;即绕过 page cache&#xff0c;对于 linux 提供了 direct io 的功能。 https://blog.csdn.net/zlpzl…

芯课堂 | LVG免费开源GUI图形库

概述 本文介绍目前LVGL的应用小知识&#xff0c;希望对采用MCU设计UI界面的用户有所启发&#xff0c;开发出界面更友好的消费品或者工业产品&#xff0c;造福大众。 01.LVGL系统架构 LVGL系统框架 应用程序创建GUI并处理特定任务的应用程序。 LVGL本身是一个图形库。我们的…

RFID技术在3C家电中的全方位应用

RFID技术在3C家电中的全方位应用 一、RFID技术简述 射频识别&#xff08;RFID&#xff09;技术是一种无线通信技术&#xff0c;已经在各行各业得到广泛应用。在3C家电领域&#xff0c;RFID技术的应用正在逐渐增加&#xff0c;为产品追溯、库存管理、防伪验证等方面提供了许多…

运维:电脑技巧:Win10常见的网络端口大全

目录 一、什么是网络端口&#xff1f; 二、网络传输协议 三、常见的 TCP 和 UDP 默认端口 一、什么是网络端口&#xff1f; 在计算机网络中&#xff0c;端口是通信端点。通常&#xff0c;端口标识分配给它们的特定网络服务。在操作系统中&#xff0c;端口号的主要用途协助是…

Python从入门到网络爬虫(内置函数详解)

前言 Python 内置了许多的函数和类型&#xff0c;比如print()&#xff0c;input()等&#xff0c;我们可以直接在程序中使用它们&#xff0c;非常方便&#xff0c;并且它们是Python解释器的底层实现的&#xff0c;所以效率是比一般的自定义函数更有效率。目前共有71个内置函数&…

Python爬取解放号外包需求案例,利用post参数多页爬取

代码展示&#xff1a; import requests import csv f open(外包数据.csv,modea,encodingutf-8,newline) csv_writer csv.writer(f) csv_writer.writerow([标题,编号,开始时间,结束时间,价格,状态,类型,投标人数,详情页]) def down_load(page): for page in range(1,page…

​电脑技巧:​笔记本电脑电流声的原因和解决方案

目录 一、音频设备接口接触不良 二、笔记本电源问题 三、笔记本电脑驱动程序问题 四、音频硬件问题 五、操作系统内部电磁干扰 六、最后总结 大家在日常生活当中&#xff0c;笔记本电脑已经成为我们工作、学习和娱乐的重要工具。但有时我们在使用过程中可能会遇到一个令人…

React组件之间的8种通讯方式

在 React 社区&#xff0c;遇到最多的其中一个问题是“不同组件之间如何相互通讯”。 在网上搜索了一些答案之后&#xff0c;早晚会有人提到 Flux&#xff0c;随后问题来了&#xff1a;“怎么用Flux解决通讯问题&#xff1f;Flux是必须的吗&#xff1f;”。 有时候 Flux 能解…

C++完成Query执行sql语句的接口封装和测试

1、在LXMysql.h 创建Query执行函数 //封装 执行sql语句 if sqllen 0 strlen获取字符长度bool Query(const char*sql,unsigned long sqllen0); 2、在LXMysql.cpp编写函数 bool LXMysql::Query(const char* sql, unsigned long sqllen){if (!mysql)//如果mysql没有初始化好{c…

C/C++ BM4 合并两个排序的链表

文章目录 前言题目1. 解决方案一1.1 思路概述1.2 源码 2. 解决方案二2.1 思路阐述2.2 源码 总结 前言 这道题采用两种方式&#xff0c;一种是直接插入法&#xff0c;还有一种就是递归调用。 题目 输入两个递增的链表&#xff0c;单个链表的长度为n&#xff0c;合并这两个链表…