Spring注解开发

news/2024/4/24 9:51:00/

定义bean

我们先直接通过一张图来理解注解在Spring开发中如和定义bean:
注解

那么我们既然加了注解,相当于定义了bean可是Spring的配置文件怎么知道他的存在,于是我们引入component-scan进行包扫描即为了让Spring框架能够扫描到写在类上的注解,我们必需要在配置文件上进行包扫描

<context:component-scan base-package="。。。"/

component-scan

  • component:组件,Spring将管理的bean视作自己的一个组件
  • scan:扫描

base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。

  • 包路径越多[如:com.taro.dao.impl],扫描的范围越小速度越快
  • 包路径越少[如:com.taro],扫描的范围越大速度越慢
  • 一般扫描到项目的组织名称即Maven的groupId下[如:com.taro]即可。

@Component注解如果不起名称,会有一个默认值就是当前类名首字母小写,所以也可以按照名称获取

对于@Component注解,还衍生出了其他三个注
@Controller : 表现层、@Service :业务层、@Repository :数据层
来定义bean。

纯注解开发

顾名思义架空配置文件(建一个配置类),把权力掌握在我们自己手里,一张图理解一下

配置注解

-@Configuration注解用于设定当前类为配置类
-@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式(用花括号把路径加起来)

可是问题来了主程序怎么知道配置在哪捏?

  • 只需要重新建一个启动类加载配置类就好啦
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

我们注意一下下面这些小点哦

  • 记住@Component、@Controller、@Service、@Repository这四个注解
  • applicationContext.xml中< context:component-san />的作用是指定扫描包路径,注解为@ComponentScan
  • @Configuration标识该类为配置类,使用类替换applicationContext.xml文件
  • ClassPathXmlApplicationContext是加载XML配置文件
  • AnnotationConfigApplicationContext是加载配置类

注解开发时bean的生命周期控制

众所周知我们的Spring在创建bean时默认都是单例的,这个我们在之前的文章也进行过演示,当我们需要在注解开发时,使bean的创建变成非单例,只需要在其类上添加@Scope(“prototype”)注解

当然我们之前也在配置文件中提到过init-method等属性来定义初始化方法与销毁方法,那么我们现在通过注解开发,没有了配置文件该怎么解决?

  • @PostConstruct //在构造方法之后执行,替换 init-method
  • @PreDestroy //在销毁方法之前执行(容器关闭时执行),替换 destroy-method

@PostConstruct和@PreDestroy注解如果找不到,需要导入javax.annotation-api这个jar包,因为jdk9版本开始删掉了这个包

<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> 
</dependency>

我们小小通过一张图总结下bean的注解:
注解示意图


依赖注入

Spring为了使用注解简化开发,并没有提供构造函数注入、setter注入对应的注解,只提供了自动装配的注解实现。

自动装配

@Autowired(他是按类型装配的);如果类型相同使用@Qualifirt(“名称”),来制定名称注入

  • @Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是写在属性上并将 setter方法删除掉,因为自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值;普通反射只能获取public修饰的内容,暴力反射除了获取public修饰的内容还可以获取private修改的内容所以此处无需提供setter方法
  • @Autowired默认按照类型自动装配,如果IOC容器中同类的Bean找到多个,就按照变量名和Bean的名称匹配。因为变量名叫bookDao而容器中也有一个booDao,所以可以成功注入。
    🍊个🌰:
    按名称找不到
    这样呢就会报错,因为按照类型会找到多个bean对象,此时会按照bookDao名称去找,因为IOC容器只有名称叫bookDao1和bookDao2 ,所以找不到,会报NoUniqueBeanDefinitionException

指定名称注入

@Qualifier
明明就这一个为啥还要单独放一个标题捏?
@Qualifier注解后的值就是需要注入的bean的名称。

  • 注意:@Qualifier不能独立使用,必须和@Autowired一起使用

🍊个🌰:

@Service
public class BookServiceImpl implements BookService {@Autowired@Qualifier("bookDao1")private BookDao bookDao;public void save() {System.out.println("book service save ...");bookDao.save();}
}

当然我们现在提到的都是应用类型的注入那么。。。。

简单类型的注入

@Value(“…”)

🍊个🌰:

@Repository("bookDao")
public class BookDaoImpl implements BookDao {@Value("taro")private String name;public void save() {System.out.println("book dao save ..." + name);}
}

很明显明明加在name直接给name赋值更方便,那为什么还要专门注入捏?有没有一种可能,这个值还可以来自配置文件。

注解读取properties配置文件

主要也就是针对@Value
1、准备配置文件
2、在配置类使用注解加载properties配置文件(@PropertySource)
3、使用@Value读取配置文件中的内容

🍊个🌰:
1、准备配置文件

我们准备一个名为jdbc.properties的配置文件并添加“name=taro”

2、使用注解加载properties配置文件(@PropertySource)

@Configuration
@ComponentScan("com.itheima")
//@PropertySource加载properties配置文件
@PropertySource({"jdbc.properties"})
public class SpringConfig {
}

3、使用@Value读取配置文件中的内容

@Repository("bookDao")
public class BookDaoImpl implements BookDao {//@Value:注入简单类型(无需提供set方法)@Value("${name}")private String name;public void save() {System.out.println("book dao save ..." + name);}
}

运行结果

  • 如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个
    🍊个🌰:
    @PropertySource({"jdbc.properties","xxx.properties"})

  • @PropertySource注解属性中可以把classpath:加上,代表从当前项目的根路径找文件

  • 🍊个🌰:
    @PropertySource({"classpath:jdbc.properties"})

稍微总结一下注入的注解吧:

@Autowired

名称@Autowired
类型属性注解 或 方法注解(了解) 或 方法形参注解(了解)
位置属性定义上方 或 标准set方法上方 或 类set方法上方 或 方法形参前面
作用为引用类型属性设置值
属性required:true/false,定义该属性是否允许为null

@Qualifier

名称@Qualifier
类型属性注解 或 方法注解(了解)
位置属性定义上方 或 标准set方法上方 或 类set方法上方
作用为引用类型属性指定注入的beanId
属性value(默认):设置注入的beanId

@Value

名称@Value
类型属性注解 或 方法注解(了解)
位置属性定义上方 或 标准set方法上方 或 类set方法上方
作用为 基本数据类型 或 字符串类型 属性设置值
属性value(默认):要注入的属性值

@PropertySource

名称@PropertySource
类型类注解
位置类定义上方
作用加载properties文件中的属性值
属性value(默认):设置加载的properties文件对应的文件名或文件名组成的数组

注解开发管理第三方bean

@Bean

名称@Bean
类型方法注解
位置方法定义上方
作用设置该方法的返回值作为spring管理的bean
属性value(默认):定义bean的id

@Import

名称@Import
类型类注解
位置类定义上方
作用导入配置类
属性value(默认):定义导入的配置类类名,
当配置类有多个时使用数组格式一次性导入多个配置类

嗯。。。其实就这俩
值得注意的是@Import 只能写一次,需要导入多个就跟在后面用数组格式

注解开发实现为第三方bean注入资源

提个问题:在使用@Bean创建bean对象的时候,如果这个方法在创建的过程中需要其他资源捏?我们怎么把其他资源给他捏?
公布答案:注入咯,所以既然是注入,那么一样的,也就分两种简单类型和引用类型咯。

简单类型

其实看一下这个🌰就明白了:
使用@Value注解引入值


public class JdbcConfig {@Value("com.mysql.jdbc.Driver")private String driver;@Value("jdbc:mysql://localhost:3306/spring_db")private String url;@Value("root")private String userName;@Value("password")private String password;@Beanpublic DataSource dataSource(){DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;}
}

引用类型

提出需求:假设在构建DataSource对象的时候,需要用到BookDao对象,该如何把BookDao对象注入进方法内让其使用呢?
如下图所示:

public class JdbcConfig {@Beanpublic DataSource dataSource(){DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql://localhost:3306/spring_db");ds.setUsername("root");ds.setPassword("root");return ds;}
}

解决方案:

🍊个🌰:

1、在SpringConfig中扫描BookDao;扫描的目的是让Spring能管理到BookDao,也就是说要让IOC容器中有一个bookDao对象

@Configuration
@ComponentScan("com.taro.dao")
@Import({JdbcConfig.class})
public class SpringConfig {
}

2、在JdbcConfig类的方法上添加参数

@Bean
public DataSource dataSource(BookDao bookDao){System.out.println(bookDao);DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;
}

引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象。


最后对Spring注解开发做个总结吧:
注解总结


http://www.ppmy.cn/news/47749.html

相关文章

C语言模拟银行排队叫号(链队)

一.队列 队列是一种具有先进先出&#xff08;FIFO&#xff09;特性的线性数据结构&#xff0c;它只允许在队列的两端进行插入和删除操作。队列的一端称为队尾&#xff08;rear&#xff09;&#xff0c;另一端称为队头&#xff08;front&#xff09;。新元素总是插入在队列的队…

单例设计模式所有情况解析

单例设计模式解析 &#x1f964;概述&#xff1a;单例设计模式是一种创建型设计模式&#xff0c;旨在确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。 一、饿汉式实现 &#x1f388;介绍&#xff1a;饿汉式是一种单例设计模式的实现方式&#xff0c;…

【LeetCode: 673. 最长递增子序列的个数 | 动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

《面试1v1》HashMap

没有人比中国人更懂 HashMap 我是 javapub&#xff0c;一名 Markdown 程序员从&#x1f468;‍&#x1f4bb;&#xff0c;八股文种子选手。 面试官&#xff1a;HashMap 是Java程序员用得最频繁的集合之一,可以给我简单介绍一下它的内部实现机制吗? 候选人&#xff1a; Hash…

华为OD机试真题(Java),数组合并(100%通过+复盘思路)

一、题目描述 现在有多组整数数组&#xff0c;需要将他们合并成一个新的数组。 合并规则从每个数组里按顺序取出固定长度的内容&#xff0c;合并到新的数组&#xff0c;取完的内容会删除掉。 如果改行不足固定长度&#xff0c;或者已经为空&#xff0c;则直接取出剩余部分的内…

Axios请求(对ajax的二次封装)——Axios API、Axios实例、请求配置、Axios响应结构

axios起步——介绍和使用基本用例post请求 场景复现核心干货axios APIaxios(config)axios(url[,config])请求方式别名 axios实例创建一个axios实例axios.create([config])实例方法 axios请求配置axios响应结构 场景复现 最近学习与前端相关的小程序时&#xff0c;接触了异步请…

@爱打游戏的你,当游戏测试是什么感觉?

爱打游戏的你&#xff0c;当游戏测试是一种什么感觉&#xff1f; 去年《宝可梦朱紫》大火的那段时间&#xff0c;想必各位爱好游戏的友友们都刷到过这样的图吧&#xff1a; &#xff08;量子纠缠&#xff09; &#xff08;天怎么黑了&#xff09; &#xff08;弹簧巨怪&#x…

4-数据结构

数据结构&#xff08;data structure&#xff09; 1. 简介 数据结构是在计算机中组织与存储数据的方式 如果想要表示“一排数字”&#xff0c;自然想到使用「数组」数据结构 数组的存储方式可以表示数字的相邻关系、顺序关系&#xff0c;但至于其中存储的是整数int&#xff0c…

Python并发编程在爬虫中的应用

并发编程在爬虫中的应用 本文将为大家介绍 Python 中的多线程、多进程和异步编程&#xff0c;并且以爬取“360图片”网站的图片并保存到本地为例&#xff0c;为大家分别展示使用单线程、多线程和异步 I/O 编程的爬虫程序有什么区别&#xff0c;同时也对它们的执行效率进行简单…

非计算机专业如何转行成为程序员?我用亲身经历教你用这三种方法

哈喽大家好啊&#xff01;我想分享一下&#xff0c;非计算机专业的学生如何转行成为程序员。首先&#xff0c;我先介绍一下我的情况。我是18年毕业的&#xff0c;大学学的专业是土木工程&#xff0c;与计算机一点关系都没有。但是在大学时&#xff0c;我对程序员比较感兴趣。本…

(包教包会)最强分布式锁工具:Redisson

今天来聊聊分布式锁的最强实现&#xff1a;Redisson 从分布式锁到Redisson实现非常详细&#xff0c;适合慢慢咀嚼~ 一. Redisson概述 1.1 什么是Redisson&#xff1f; Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;。…

八、vue-基础之列表渲染v-for、v-for中的key属性的作用

一、v-for列表渲染 在真实开发中&#xff0c;我们往往会从服务器拿到一组数据&#xff0c;并且需要对其进行渲染。 这个时候我们可以使用v-for来完成&#xff1b;v-for类似于JavaScript的for循环&#xff0c;可以用于遍历一组数据&#xff1b; 二、v-for基本使用 &#xff0…

4.17-4.18学习总结

MD5 MD5: 1、压缩性 2、容易计算 3、抗修改性 4、弱抗碰撞 5、强抗碰撞 为什么需要MD5&#xff1f; 存储一些敏感信息的时候&#xff0c;如果不进行加密会出现安全问题。 例如&#xff1a;系统登录的密码&#xff0c;如果数据库中的密码采用明文&#xff0c;一旦数据库泄…

面了十几家公司测试岗,我终于悟了,面试无非就是这些题

测试岗的面试其实都是大同小异的&#xff0c;这里我收集整理了185道高频面试题&#xff0c;希望对在找工作或者准备跳槽的各位小伙伴有所帮助&#xff01; 一. 测试基础 1.如何制定测试计划 参考答案&#xff1a; 测试计划包括测试目标、测试范围、测试环境的说明、测试类型…

vue nextTick原理详解

vue nextTick Vue.nextTick() 是一个方法&#xff0c;用于在下次 DOM 更新循环结束之后执行延迟回调。它的实现原理是利用浏览器的异步任务队列机制&#xff0c;在 tick 时刻将回调函数放入队列中等待执行。在实现上&#xff0c;nextTick 方法会根据当前环境选择不同的底层实现…

DCQCN学习

主要思想 发送端的拥塞控制主要有两种形式&#xff0c;一种是基于发送窗口的&#xff0c;另一种是基于rate的 DCQCN是一种基于rate的CC&#xff0c;并主要由ECN机制实现 初始设置sending rate为max line rate 接下来CC主要分为三个部分 CP(Congestion Point) 交换机 出端…

MySQL数据库系统学习(从入门到精通)

MySQL数据库系统学习 一&#xff0c;了解数据库 1.什么是数据库 英文单词DataBase&#xff0c;简称DB。按照一定格式存储数据的一些文件的组合。 顾名思义&#xff1a;存储数据的仓库&#xff0c;实际上就是一堆文件。这些文件中存储了具有特定格式的数据。 2.什么是SQL S…

转义字符(\)对JavaScript中JSON.parse的影响概述

转义字符(\)对JavaScript中JSON.parse的影响 按照ECMA262第五版中的解释&#xff0c;JSON是一个提供了stringify和parse方法的内置对象&#xff0c;前者用于将js对象转化为符合json标准的字符串&#xff0c;后者将符合json标准的字符串转化为js对象。json标准参考<a href&q…

Java中的序列化与反序列化(一)

1、概述 大家好&#xff0c;我是欧阳方超。今天来看一下Java序列化与反序列化的问题。 2、序列化与反序列化 2.1、序列化与反序列化的概念 在Java中&#xff0c;序列化是将对象转换为可存储或传输的格式&#xff08;一般为字节流&#xff09;的过程&#xff0c;序列化后的字…

为什么网络安全缺口很大,招聘却很少?

2020年我国网络空间安全人才数量缺口超过了140万&#xff0c;就业人数却只有10多万&#xff0c;缺口高达了93%。这里就有人会问了&#xff1a; 1、网络安全行业为什么这么缺人&#xff1f; 2、明明人才那么稀缺&#xff0c;为什么招聘时招安全的人员却没有那么多呢&#xff1…