Spring学习(三)(类注解和方法注解)

news2024/12/26 10:50:58

目录

1. 存储Bean对象

1.1 配置扫描路径

1.2 添加注解存储Bean对象

1.2.1 @Controller(控制器存储)

 1.2.2 @Service(服务存储)

1.3 这么多注解???为什么??

 1.3.1 类注解时间的关系

1.4 方法注解@Bean

1.4.1 @Bean重命名

1.4.2 @Bean存储多个相同对象

2.获取Bean对象(对象装配)

2.1 属性注入

2.2 Setter注入

2.3 构造方法注入(Spring官方推荐)

2.4 @Resource注解


1. 存储Bean对象

通过再配置文件中添加bean注册内容的方式来存储bean感觉是一个十分不方便的操作。想要通过更加简单的操作来实现对bean的注册该怎么办呢?Spring为使用者还提供了通过注解的方式来注册bena。这种方式也是主流的方式,工作当中也大多是通过这种方式来注册bean的,因为十分的方便,而且关联到java的标准分层。

1.1 配置扫描路径

配置扫描路径是什么意思呢??难道不是直接在需要的地方加上注解就可以了吗??

Spring作为一个成熟的框架,肯定是要追求效率的,如果是直接加上注解就可以注册的话,就必须扫描所有的代码遍历去检查有没有注册的需求。这样逻辑工作的话,效率肯定是十分低下的,为了提高效率,Spring决定只扫描在配置在base-package包以及其子包。如果不在base-package包下的地方即使加上了注解也是没有办法注册bean的,在使用的时候就会报错。只有被配置的包下的所有类,并且添加了注解才能被正确的识别并保存到 Spring 中。

怎么配置扫描路径?只需要在spring-config.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:content="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans htt
p://www.springframework.org/schema/beans/spring-beans.xsd http://www.spring
framework.org/schema/context https://www.springframework.org/schema/contex
t/spring-context.xsd">
 <content:component-scan base-package="com.xxx.yyy"></content:compon
ent-scan>
</beans>

其中

添加完扫描路径以后,Spring就会在这个包下面扫面有哪些添加了注解然后将其存储到Spring中。

1.2 添加注解存储Bean对象

Spring提供了两种类型的注解来帮助使用者将对象存储到Spring当中。

  • 1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration。
  • 2. ⽅法注解:@Bean。

 下面先来介绍他们是怎么使用的,然后再去介绍他们的使用场景。

1.2.1 @Controller(控制器存储)

首先它是一个类注解,使用的时候就是在想要存储的类上加上这个注解。使用@Controller存储bean的代码如下所示:

@Controller
public class UserController {
    public void sayHi(String name){
        System.out.println("Hi I am " + name);
    }
}

读取使用起来还是一样的:

public class App {
    public static void main(String[] args) {
        // 1.得到 spring 上下⽂
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2.得到 bean
        UserController userController = (UserController) context.getBean(
                "userController");
        // 3.调⽤ bean ⽅法
        userController.sayHi("Zhangsan");
    }
}

其实现在有一个小问题,我们使用注解的时候并没有指定id啊,这样我们在读取的时候是怎么样知道他的id并且是获取的呢?根据上面的使用情况来看即使将注解的类名的首字母改成小写就是存储的id,那么到底是不是这样的?

答案其实不是这样的,这需要搞清楚类注解的bean命名规则才能得到答案。我们可以看一下Spring的源码中对于BeanName的实现到底是什么情况?在 Idea 中使⽤搜索关键字“beanName”可以看到以下内容:

 

 看完源代码之后就能十分确定我们在使用的时候怎么确定ID了,分为两种情况:

  • 1.类名首字母和第二个字母都是大写的情况下,bean的名字就是类名;
  • 2.其他情况下就是将首字母改为小写作为bean的名字。

 1.2.2 @Service(服务存储)

使⽤ @Service 存储 bean 的代码如下所示,和前面的controller的使用方法一致。

@Service
public class UserService {
    public void sayHi(String name) {
        System.out.println("Hi," + name);
    }

}
public class App {
    public static void main(String[] args) {
        // 1.得到 spring 上下⽂
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2.得到 bean
        UserController userController = (UserController) context.getBean("userService");
        // 3.调⽤ bean ⽅法
        userController.sayHi("Zhangsan");
    }
}

剩下的集中情况不再去逐个演示,使用起来的方式都是大同小异,在类上加上对应的注解就可以了。用法并不是重点,重点是为什么提供这么多的注解??而且他们的使用方法都是一致的,这是为什么??

1.3 这么多注解???为什么??

那么为什么需要怎么多的类注解也是相同的原因,就是让程序员看到类注解之后,就能直接了解当前类 的⽤途,⽐如:

  • @Controller:表示的是业务逻辑层;
  • @Servie:服务层;
  • @Repository:持久层;
  • @Configuration:配置层。

这样就涉及到程序的工程分层,调用的流程大致如下:

 1.3.1 类注解时间的关系

查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:

其实这些注解⾥⾯都有⼀个注解 @Component,说明它们本身就是属于 @Component 的“⼦类”

1.4 方法注解@Bean

通过学习发现类注解是加在类上面的,想必方法注解就是加在某个方法上面了。另外要注意的是,这个方法必须要有一个返回值,如果没有返回值的话,Spring存什么呢?所以必须是要有一个返回值的,然后将这个返回值存入到spring中。并且存入的时候只能存一个无参方法的返回值。

先来看一下直接在方法上加上Bean注解是否能够成功使用?

public class StudentBeans {
    @Bean // 使用Bean注解讲函数的返回值也就是Student对象存储到spring中
    public Student stu1(){
        Student student = new Student("tom");
        student.setAge(18);
        student.setPassword("123456");
        return student;
    }
}

public class App {
    public static void main(String[] args) {
        // 1.得到 spring 上下⽂
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2.得到 bean
        Student stu1 = context.getBean("student", Student.class);
        // 3.调⽤ bean ⽅法
        System.out.println(stu1.getName());
    }

}

 

 运行时候发现报错,No bean named 'student' available,也就是我们spring中没有student。实际上造成上面报错的原因是代码中包含两处错误:

  • 1.Bean方法注解的命名规则相较于类注解已经发生了变化,Bean方法注解存入的id就是方法名,和类名没有任何的关系。比如 public Student stu1()中存入的id就是stu1。
  • 2. Bean注解必须搭配五大类注解使用才可以生效,否则也会报错。

 加入类注解,根据bean命名规则修改代码后:

 

 运行代码,观察是否能够成功获取到stu对象:

1.4.1 @Bean重命名

@Bean(name = {"student","stu"})

使用上面的代码可以给@Bean存入的对象重命名,而且可以起多个名字。name可以使用value替换。但是当@Bean重命名以后原来的默认的id就无法再获取到了。也就是通过

Student stu1 = context.getBean("stu1" , Student.class);无法在获取到存入的对象,只能通过重命名以后的id来获取到。在使用的时候要注意这个地方

1.4.2 @Bean存储多个相同对象

 当使用@Bean注解存储多个相同对象的时候可以使用重命名来加以区分:

@Component
public class StudentBeans {
    @Bean(name = {"student","stu"}) // 使用Bean注解讲函数的返回值也就是Student对象存储到spring中
    public Student stu1(){
        Student student = new Student("tom");
        student.setAge(18);
        student.setPassword("123456");
        return student;
    }

    @Bean(name = {"student1","stu1"}) // 使用Bean注解讲函数的返回值也就是Student对象存储到spring中
    public Student stu(){
        Student student = new Student("jack");
        student.setAge(18);
        student.setPassword("123456");
        return student;
    }
}

如果现在在两个不同的类中,分别存在一个方法名和返回值都一样的方法并且都是用了@Bean注解,会不会报错??

 

 答案是不会报错,但是每次运行的结果都是相同的结果,并不是随机的(我这里每次都是jordan)

 

这里可以通过@Oeder()来控制注入的顺序,值越小,越先注入,然后就会被后者注入的覆盖掉。

 

2.获取Bean对象(对象装配)

2.1 属性注入

缺点:

  • 无法注入final修饰的变量;

 

  • 只能适用于IoC容器,兼容性不好;
  • 此恶法简单,更容易违反单一设计原则;

优点:

  • 使用十分简单;

2.2 Setter注入

优点:更符合单一设计原则,每次都只传递一个对象;

缺点:

  • 不可以注入一个final修饰的变量;

 

  • 使用Setter注入的对象可以被修改 ,因为使用的载体就是一个setter方法,setter方法可以被多次调用;

2.3 构造方法注入(Spring官方推荐)

当当前类中只有一个构造方法的时候,@Autowired注解可以省略不写!

优点:

  • 1.可注入final修饰的变量;

为什么构造方法可以注入final修饰的不可变对象呢??因为java中被final修饰的对象,必须满足:final修饰的对象直接被赋值  或者  final修饰的对象在构造方法中被赋值

  • 2.注入的对象不会被修改,因为构造方法只能执行一次;
  • 3 .构造方法注入可以保证注入对象被完全初始化;
  • 4.构造方法的兼容性更好,即使脱离了IoC容器中也可以使用。

缺点:

  • 可能会违反单一设计原则(使用者可控,一般来说不会违反);

2.4 @Resource注解

@Resource在属性注入和Setter注入场景下可以替换@Autowired,但是在构造方法注入场景下只能使用@Autowired注解;

@Resource支持更多的参数设置:(当同一个类型的类被注入多个在spring当中的时候,使用@Autowired可能会解决不了命名冲突的问题,这时候就只能使用@Resource来给注入的bean重命名)

 

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

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

相关文章

leetcode:种花问题

种花问题 假设有一个很长的花坛&#xff0c;一部分地块种植了花&#xff0c;另一部分却没有。可是&#xff0c;花不能种植在相邻的地块上&#xff0c;它们会争夺水源&#xff0c;两者都会死去。 给你一个整数数组 flowerbed 表示花坛&#xff0c;由若干 0 和 1 组成&#xff0c…

Go语言网络编程:TCP粘包问题——Go实现封包拆包

一&#xff1a;TCP粘包介绍 1.1 TCP介绍 如上图&#xff0c;TCP具有面向连接、可靠、基于字节流三大特点。 字节流可以理解为一个双向的通道里流淌的数据&#xff0c;这个数据其实就是我们常说的二进制数据&#xff0c;简单来说就是一大堆 01 串。纯裸TCP收发的这些 01 串之间…

对弈人工智能!myCobot 280开源六轴机械臂Connect 4 四子棋对弈下篇

前言 在上篇文章中&#xff0c;我们探讨了如何创造一个能够进行Connect4的对弈大脑。简单的介绍了几种对弈算法&#xff0c;例如极小化极大算法&#xff0c;Alpha-Beta剪枝算法等&#xff0c;最关键的是目前最流行的神经网络算法和深度学习。神经网络算法&#xff0c;让计算机…

Dubbo zookeeper

1、RPC全称为remote procedure call&#xff0c;即远程过程调用。Dubbo作为一个RPC框架,其最核心的功能就是要实现跨网络的远程调用 2、Dubbo提供了三大核心能力&#xff1a;面向接口的远程方法调用&#xff0c;智能容错和负载均衡&#xff0c;以及服务自动注册和发现。 3、 Du…

Google SEO内容指南:您实现最大自然流量的路线图

欢迎来到令人兴奋的SEO内容世界&#xff01; SEO就像拥有一个秘方&#xff0c;结合了创造力、策略和技术诀窍的正确成分&#xff0c;使您的内容在广阔的数字环境中大放异彩。 但最好的是 – SEO内容并不是要牺牲您独特的声调或损害您的创造力。相反&#xff0c;它是关于了解搜…

从0开始,手写MySQL数据管理器DM

说在前面 从0开始&#xff0c;手写一个MySQL的学习价值在于&#xff1a; 可以深入地理解MySQL的内部机制和原理&#xff0c;MySQL可谓是面试的绝对重点和难点&#xff0c; 尼恩曾经指导过的一个7年经验小伙&#xff0c;凭借精通MySQL 搞定月薪40K。 从而更好地掌握MySQL的使…

六、Eureka服务发现(源码分析)

1 什么是服务发现 根据服务名称发现服务的实例过程客户端会在本地缓存服务端的列表拉取列表是有间隔周期的 &#xff08;导致服务上线 客户端不能第一时间感知到 &#xff08;可以容忍&#xff09;&#xff09;其实每次做服务发现 都是从本地的列表来进行的 2 测试服务发现 …

哆啦A梦和小猪佩奇(Python实现)

目录 1 哆啦A梦 2 小猪佩奇 3 Python代码实现&#xff08;哆啦A梦&#xff09; ​ 4 Python代码实现&#xff08;小猪佩奇 &#xff09; 1 哆啦A梦 “只要把愿望系在竹竿上请求月亮女神&#xff0c;心愿便能达成”。我超喜欢这句话。 哆啦A梦的创造要追溯到1969年的某个…

【PHP语言-PDO接口】PDO接口执行脚本操作数据库

目录 前言&#xff1a; 一、 PDO简介 二、 PDO对象方法 前言&#xff1a; PDO&#xff1a;数据库抽象层 简介&#xff1a;PDO扩展为PHP访问数据库定义了一个轻量级的、一致性的接口&#xff0c;PDO解决了数据库连接不统一的问题。 一、 PDO简介 1、PDO简介 &#xff08;1…

iview 文档中的三个提示彩蛋

第一个彩蛋 在iview的Collapse 折叠面板最底下&#xff0c;简洁模式的第二个&#xff0c;双击数字 19840124 是一个日期&#xff0c;也就是 1984 年 1 月 24 日&#xff0c;这一天&#xff0c;苹果发布了麦金塔电脑&#xff08;Macintosh&#xff09;&#xff0c;对于苹果来说…

当量因子法、InVEST、SolVES模型等多技术融合在生态系统服务功能社会价值评估中的应用

第一章 理论基础与研究热点分析 1. 生态系统服务与生态系统服务价值介绍 ​ 2. 生态系统服务价值研究方法 3. 生态系统服务价值研究热点 Citespace文献可视化分析 VOSviewer文献可视化分析 第二章 空间数据来源及预处理 1. 空间数据简介 2. ArcGIS Pro数据采集与分析 数…

【Python】matplotlib.pyplot 详解与使用(内有大量例子)

0. 写在前面 本文是根据 matplotlib 3.7.1 版本撰写的&#xff0c;若出现有文章与实际有出入的情况请查看版本是否一致。 我们使用 matplotlib.pyplot 需要使用以下的语句来导入它 import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np1. 官方文档详…

chrome开发调试小技巧—Replay XHR(重新请求)

一、需求 想要验证一个ajax请求&#xff0c;需要每次都需要在页面点几次才会触发或者刷新页面&#xff0c;着急调试看效果时&#xff0c;可以通过chrome的Replay XHR功能直接同参数重新请求ajax 二、实现 chrome调试工具network下找到要重新发起的ajax请求&#xff0c;右键找…

Vue核心语法

Vue核心语法 vue下载 我们以前都是用的框架来搭建的&#xff0c;省去了很多内容&#xff0c;今天我们从原始的方式来使用vue&#xff0c;下面是下载地址 响应式 未使用响应式 <!DOCTYPE html> <html lang"en"><head><meta charset"U…

基于J-Link RTT Viewer输出日志(适用于JLink DAPLink STLink)

前言 通过RTT输出日志&#xff0c;可以不占额外的引脚和外设&#xff0c;速度非常快&#xff0c;几乎不影响程序的实时性。 参考官方介绍文档 安装J-Link驱动 官网下载地址&#xff0c;本文选择的是7.60版本&#xff0c;如果官网下载太慢&#xff0c;可以点击在CSDN下载 …

linux入门进程概念中(僵尸进程,孤儿进程,进程优先级,并行和并发,环境变量)

目录 一、进程状态 1.看看Linux Kernel怎么说 1.1阻塞 2.进程状态查看 3.僵尸进程 3.1模拟僵尸进程的实验 3.2僵尸进程的危害 4.孤儿进程 4.1模拟孤儿进程实验 二、进程优先级 三、环境变量 3.1常见环境变量 3.2查看环境变量的方法&#xff1a; 3.3 加入环境变量 …

性能测试基础知识及性能指标

目录 1.1、性能概述&#xff1a; 1.2 、测试目标 1.3 、性能测试方法 2 .1 、需求分析 2.2 、测试对象 2.3 、拆分对象 2.4 、指标分析 3.1 、用例设计 4.1、性能监控关键指标 结尾 &#x1f381;更多干货 前言&#xff1a;最近公司接了个项目&#xff0c;领导开会突…

【python】面向对象语言的特性

面向对象语言的特性 封装继承继承定义继承下的方法重写 类型注解变量类型注解函数(方法)类型注解Union 联合类型注解 多态定义抽象类 面向对象语言的三大特性&#xff1a;封装、继承、多态 本文主要来介绍这三个特性 封装 封装&#xff1a;指的是将对象的状态信息隐藏在对象内…

nodejs(express)+TypeScripts环境

初始化项目&#xff1a; npm init -y 安装包&#xff1a; npm i types/express //安装type类型的express如果不加types就是安装js文件&#xff0c;虽然对项目的运行没啥问题但是会没有提示npm i typescriptnpm i types/mysql安装完成后就开始配置了&#xff1a; 在项目的根…

VCL组件DevExpress VCL图表控件中文指南 - 如何实现值标签自定义?

DevExpress VCL拥有230个VCL界面控件、40个自定义设计的VCL应用主题&#xff0c;它能帮助您创建优异的用户体验&#xff0c;提供高影响力的业务解决方案&#xff0c;并利用您现有的VCL技能为未来构建下一代应用程序。 在刚更新的DevExpress VCL v23.1组件库中&#xff0c;包含…