当前位置: 首页 > news >正文

【Spring】注解开发

为了提高开发效率,从 Spring 2.0 开始引入了多种注解,而在 Spring 3.0 中则实现了纯注解的开发方式。

一、注解的使用

在 Spring 2.0 之后,使用注解进行开发主要分为两个步骤:

  1. 定义 Bean:使用 @Component 注解来定义一个 Bean。
  2. 加载 Bean:在核心配置文件中,通过组件扫描功能来加载这些 Bean 所在包。

在定义和使用 Bean 时,我们可以通过指定 Bean 的名称来获取其实现对象,也可以通过类型自动装配来获取对象。

(1)通过指定名称获取 Bean 对象

在使用 @Component 定义 Bean 时,为 Bean 对象起名称。在实际应用时通过名称获取 Bean 对象:

// Bean 的定义
@Component("bookDao")
public class BookDaoImpl implements BookDao {@Overridepublic void save() {}
}
// Bean 的应用
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);

在定义 Bean 后,还需要在配置文件 applicationContext.xml 中指定需要 Spring 扫描的包,Spring 会扫描包下的类并注入相应的 Bean 对象:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.it"/>
</beans>

(2)通过类型自动装配 Bean 对象

这种方式与通过指定名称获取 Bean 对象的方式不同,因为它不需要为每个 Bean 设置唯一的名称。在实际应用中,Spring 会通过类型来自动装配 Bean 对象。虽然这种方法比指定名称更简便,但在存在多个相同类型的 Bean 的情况下,它就不太适用了。在使用时,仍然需要在配置文件中扫描指定的包。

// Bean 的定义
@Component
public class BookServiceImpl implements BookService {private BookDao bookDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}
}
// Bean 的应用
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);

另外,Spring 提供了 @Component 注解的三个衍生注解,分别是:

  • @Controller:用于表现层 bean 定义
  • @Service:用于业务层 bean 定义
  • @Repository:用于数据层 bean 定义

这些注解的功能与 @Component 相同,它们在不同层的使用主要是为了更清晰地表达代码结构。

二、纯注解模式

Spring 3.0 升级了纯注解开发模式,使用 Java 类代替配置文件,提高了 Spring 开发效率。下面是纯注解模式的简单使用过程:

(1)定义配置类

这里在 config 包下创建一个 SpringConfig 类,通过 @Configuration 注解设定当前类为配置类,通过 @ComponentScan 注解设定扫描路径,以此替代配置文件:

@Configuration
@ComponentScan("com.it")
public class SpringConfig {
}

其中,@ComponentScan 注解只能添加一次,但可以使用数组格式来实现多个扫描路径:

@Configuration
@ComponentScan({"com.it.dao", "com.it.service"})
public class SpringConfig {
}

(2)实际应用

在使用纯注解时,通过为 AnnotationConfigApplicationContext 指定配置类来获取上下文,并通过上下文获取需要的 Bean 对象:

ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookDao);
System.out.println(bookService);

2.1 Bean 作用范围

在纯注解模式下,Bean 的作用范围通过 @Scope 指定:

@Repository("bookDao")
@Scope("singleton")
public class BookDaoImpl implements BookDao {@Overridepublic void save() {}
}

2.2 Bean 生命周期

在纯注解模式下,Bean 生命周期中初始化和销毁阶段通过 @PostConstruct@PreDestroy 注解实现。首先,在 pom.xml 文件中引入 javax 库:

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

接着,在定义 Bean 时,实现初始化和销毁操作:

@Repository("bookDao")
public class BookDaoImpl implements BookDao {@Overridepublic void save() {}@PostConstructpublic void init() {System.out.println("Init...");}@PreDestroypublic void destroy() {System.out.println("Destroy...");}
}

在使用时,如果希望看到销毁操作的执行,需要调用 close() 方法:

public class AppForAnnotation {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);BookDao bookDao = (BookDao) ctx.getBean("bookDao");System.out.println(bookDao);ctx.close();}
}

2.3 Bean 依赖注入

与其他注解模式一样,纯注解模式的 Bean 依赖注入也分引用类型注入和简单类型注入。

(1)引用类型注入

在实现引用类型注入的过程中,可以选择自动装配注入,也可以通过指定名称的方式注入。

自动装配使用 @Autowired 注解实现注入。这种方式基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供 setter 方法。另外,
自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,则需提供唯一的构造方法。

// 自动装配
@Component
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;// ...
}

指定名称注入使用 @Qualifier 注解指定装配 Bean 的名称。需要注意的是 @Qualifier 注解无法单独使用,必须配合 @Autowired 注解使用。

// 指定名称
@Component
public class BookServiceImpl implements BookService {@Autowired@Qualifier("bookDao")private BookDao bookDao;// ...
}

(2)简单类型注入

使用 @Value 注解实现简单类型注入:

@Repository("bookDao")
public class BookDaoImpl implements BookDao {@Value("test")private String name;// ...
}

(3)配置文件注入

在引用类型和简单类型注入的基础上,可以使用配置文件完成更加复杂的注入。在 resources 文件夹下创建配置文件 jdbc.properties,其内容为:

name=test

使用 @PropertySource 注解在配置类中加载内容:

@Configuration
@ComponentScan({"com"})
@PropertySource("jdbc.properties")
public class SpringConfig {
}

通过 @Value 注解和 ${} 配合使用完成注入:

@Repository("bookDao") // 起名称为 bookDao
public class BookDaoImpl implements BookDao {@Value("${name}")private String name;@Overridepublic void save() {System.out.println("Book dao save ..." + name);}
}

注意:路径仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符*。

2.4 第三方 Bean 管理

在纯注解模式下,管理自定义 Bean 的过程可以遵循之前提到的定义 Bean 和包扫描的步骤。对于第三方提供的 Bean 对象,管理过程如下:以 Druid 数据库连接池为例。首先,我们需要定义一个方法来获取要管理的对象,也就是 DruidDataSource 对象。然后,在这个方法上添加 @Bean 注解,以表明该方法的返回值是一个 Bean 对象:

public class JdbcConfig {// 1. 定义一个方法获取要管理的对象// 2. 添加 @Bean,表示当前方法的返回值是一个 Bean@Bean("dataSource")public DataSource dataSource () {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql://localhost:3306/db");ds.setUsername("root");ds.setPassword("123456");return ds;}
}

这里将 JDBC 相关的配置类分离出来,并利用 @Import 注解手动加入配置类到核心配置,实现多个配置类的使用:

@Configuration
@Import({JdbcConfig.class})
public class SpringConfig {
}

之后,同样通过 AnnotationConfigApplicationContext 类对象获取上下文,再从上下文中获取指定的 Bean 对象:

public class App {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);DataSource dataSource = ctx.getBean(DataSource.class);System.out.println(dataSource);}
}

2.5 第三方 Bean 依赖注入

在纯注解模式下,当管理第三方 Bean 时,如果涉及到 Bean 对象的依赖注入,简单类型和引用类型的依赖注入可以通过以下方式实现:

(1)第三方简单类型注入

简单类型注入只需要为 Bean 定义对应成员变量,并通过 @Value 注解和变量调用实现注入:

public class JdbcConfig {@Value("com.mysql.jdbc.Driver")private String driver;@Value("jdbc:mysql://localhost:3306/db")private String url;@Value("root")private String userName;@Value("123456")private String password;// 1. 定义一个方法获取要管理的对象// 2. 添加 @Bean,表示当前方法的返回值是一个 Bean@Bean("dataSource")public DataSource dataSource () {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;}
}

(2)第三方引用类型注入

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

public class JdbcConfig {@Value("com.mysql.jdbc.Driver")private String driver;@Value("jdbc:mysql://localhost:3306/db")private String url;@Value("root")private String userName;@Value("123456")private String password;// 1. 定义一个方法获取要管理的对象// 2. 添加 @Bean,表示当前方法的返回值是一个 Bean@Bean("dataSource")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 对象已经注入,即需要确保传入的 Bean 对象被扫描到(添加 @ComponentScan 注解和对应 @Component 注解):

@Configuration
@Import({JdbcConfig.class})
@ComponentScan({"com.it"})
public class SpringConfig {
}
@Repository
public class BookDaoImpl implements BookDao {
}

相关文章:

【Spring】注解开发

为了提高开发效率&#xff0c;从 Spring 2.0 开始引入了多种注解&#xff0c;而在 Spring 3.0 中则实现了纯注解的开发方式。 一、注解的使用 在 Spring 2.0 之后&#xff0c;使用注解进行开发主要分为两个步骤&#xff1a; 定义 Bean&#xff1a;使用 Component 注解来定义…...

数字图像稳定DIS介绍目录

之前用OpenCV做过防抖&#xff0c;OpenCV处理时&#xff0c;先处理一遍&#xff0c;再输出视频。二者相差还是挺大的。 前 言.......................................................................................................................................... …...

【人工智能-基础】SVM中的核函数到底是什么

文章目录 支持向量机(SVM)中的核函数详解1. 什么是核函数?核函数的作用:2. 核技巧:从低维到高维的映射3. 常见的核函数类型3.1 线性核函数3.2 多项式核函数3.3 高斯径向基函数(RBF核)4. 总结支持向量机(SVM)中的核函数详解 支持向量机(SVM,Support Vector Machine)…...

字节青训Marscode——8:找出整形数组中超过一半的数

问题描述 小R从班级中抽取了一些同学&#xff0c;每位同学都会给出一个数字。已知在这些数字中&#xff0c;某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。 测试样例 样例1&#xff1a; 输入&#xff1a;array [1, 3, 8, 2, 3, 1, 3, 3, 3] 输出…...

C++ 异步编程的利器std::future和std::promise

1、背景 在现代计算机系统中&#xff0c;许多任务可能需要花费较长时间才能完成&#xff0c;例如网络请求、文件读取、大规模数据计算等。如果在程序中同步地执行这些任务&#xff0c;会导致主线程被阻塞&#xff0c;整个程序在任务执行期间无法响应其他操作&#xff0c;用户体…...

CRM 系统中的 **知识库功能** 的设计与实现

CRM 系统中的 **知识库功能** 旨在为用户提供一个集中的平台&#xff0c;用于存储、组织和管理有关系统功能、常见问题、使用技巧、操作文档等信息。它能够帮助用户高效解决问题、快速获取所需信息&#xff0c;从而提升使用体验并减少客户支持负担。 ### 一、知识库功能的设计…...

重学设计模式-工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)

在平常的学习和工作中&#xff0c;我们创建对象一般会直接用new&#xff0c;但是很多时候直接new会存在一些问题&#xff0c;而且直接new会让我们的代码变得非常繁杂&#xff0c;这时候就会巧妙的用到设计模式&#xff0c;平常我们通过力扣学习的算法可能并不会在我们工作中用到…...

【C语言】结构体(四)

本篇重点是typedef关键字 一&#xff0c;是什么&#xff1f; typedef用来定义新的数据类型&#xff0c;通常typedef与结构体的定义配合使用。 简单来说就是取别名 ▶ struct 是用来定义新的数据类型——结构体 ▶ typedef是给数据类型取别名。 二&#xff0c;为什么&#xf…...

swift类方法为什么使用表派发?

直接上答案&#xff1a;因为表派发允许子类重写父类的方法&#xff0c;并在运行时根据对象的实际类型调用正确的方法实现。 什么是表派发&#xff1f; 首先我们先知道的是&#xff0c;swift当中函数的派发机制主要分为静态派发和动态派发。动态派发又分为表派发和消息派发。 …...

php实现AES/CBC/PKCS5Padding加密

接口文档 文档给过来的案例是java程序的&#xff0c;参照其思路&#xff0c;造一个php版本 构造aes对称加密 public static function encry($data){$data "要加密的数据";$key 你的256位密钥; // 密钥应该是16字节&#xff08;128位&#xff09;&#xff0c;24字节…...

Anaconda3安装及使用

Anaconda3安装及使用 Linux中安装Anaconda31.安装 Anaconda32.配置环境变量3.验证是否成功 Conda环境和包管理1.Conda 环境初始化2.Conda Env 管理3.Conda 软件包管理 Linux中安装Anaconda3 下面是在Linux中安装Anaconda3-2021.05的教程&#xff0c;其他版本Anaconda更换名字即…...

Argon2-cffi与argon2-cffi-bindings:深入理解及其应用

Argon2-cffi与argon2-cffi-bindings的关系 在Python密码学领域&#xff0c;argon2-cffi和argon2-cffi-bindings是两个经常被提及的库。尽管它们的名字相似&#xff0c;但它们在实现和用途上有所不同。argon2-cffi是一个提供Argon2哈希算法的Python库&#xff0c;而argon2-cffi-…...

spring boot+jpa接入达梦数据库

文章目录 前言依赖配置对应的domain类和repository 前言 最近有一个新项目&#xff0c;由于信息安全等要求只能使用达梦数据库&#xff08;dm8&#xff09;&#xff0c;之前从来没用过&#xff0c;特此开一个笔记记录一下spring bootjpa如何使用达梦数据库完成开发。 依赖 p…...

Vite构建,用NodeJS搭建一个简单的Vite服务

Vite 是一个现代的前端构建工具&#xff0c;由 Vue.js 作者尤雨溪创建。它主要用于开发和构建现代 JavaScript 应用&#xff0c;尤其是单页应用&#xff08;SPA&#xff09;。Vite 相比于传统的构建工具&#xff08;如 Webpack&#xff09;有几个显著的优势&#xff1a; 即时开…...

R语言机器学习论文(六):总结

文章目录 介绍参考文献介绍 本文采用R语言对来自进行数据描述、数据预处理、特征筛选和模型构建。 最后我们获得了一个能有效区分乳腺组织的随机森林预测模型,它的性能非常好,这意味着它可能拥有非常好的临床价值。 在本文中,我们利用R语言对来自美国加州大学欧文分校的B…...

python---面向对象---综合案例(4)

案例描述 实现加减乘法运算 # _*_ encoding:utf-8 _*_# 计算器, 实现一些基本的操作, 加减乘除运算, 以及打印结果操作# ------------------------------------代码1-------------------------------------- def jia(n1, n2):return n1 n2def jian(n1, n2):return n1 - n2de…...

如何参加华为欧拉考试?

华为欧拉考试主要针对的是华为欧拉&#xff08;EulerOS/openEuler&#xff09;操作系统的认证考试&#xff0c;这一认证体系旨在培养和认证具备基于欧拉操作系统进行企业级应用运行基础环境搭建、管理和调测能力的工程师以及云计算架构师。以下是对华为欧拉考试的详细介绍&…...

算法预刷题Day9:BM28 二叉树的最大深度

描述&#xff1a; 描述 求给定二叉树的最大深度&#xff0c; 深度是指树的根节点到任一叶子节点路径上节点的数量。 最大深度是所有叶子节点的深度的最大值。 &#xff08;注&#xff1a;叶子节点是指没有子节点的节点。&#xff09; 思路&#xff1a; 当前节点的最大高度 ma…...

exp_lr_scheduler理解

1. exp_lr_scheduler理解 这行代码定义了一个学习率调度器,用于动态调整训练过程中优化器的学习率。让我们分解并解释其含义: 1. exp_lr_scheduler 是什么? exp_lr_scheduler 是一个 学习率调度器(LR Scheduler),由 torch.optim.lr_scheduler.StepLR 创建,旨在按照预…...

Algorithm:河内之塔

1. 说明 河内之塔&#xff08;Towers of Hanoi&#xff09;是法国人 M.Claus&#xff08;Lucas&#xff09;于1883年从泰国带至法国的&#xff0c;河内为越战时北越的首都&#xff0c;即现在的胡志明市&#xff1b;1883年法国数学家 Edouard Lucas 曾提及这个故事&#xff0c;据…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...