【JavaEE进阶】Spring 更简单的读取和存储对象

文章目录

  • 一. 存储Bean对象
    • 1. 配置扫描路径
    • 2. 添加注解存储 Bean 对象
      • 2.1 使用五大类注解存储Bean
      • 2.2 为什么要有五大类注解?
      • 2.3 有关获取Bean参数的命名规则
    • 3. 使用方法注解储存 Bean 对象
      • 3.1 方法注解储存对象的用法
      • 3.2 @Bean的重命名
      • 3.3 同⼀类型多个 @Bean 报错
  • 二. 获取 Bean 对象(对象装配)
    • 1. 属性注入
    • 2. Setter注入
    • 3. 构造方法注入(Spring官方推荐)
    • 4. @Resource:另⼀种注入关键字

一. 存储Bean对象

1. 配置扫描路径

配置扫描路径是使用注解之前的前置工作,是非常重要的,是必须的操作项.只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 中.

首先创建一个Spring项目.创建好后,第一步就是配置扫描路径:在resources目录中创建一个spring-config.xml文件.然后在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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scan base-package=""></content:component-scan>
</beans>

<content:component-scan base-package=""></content:component-scan>base-package=""的值设置为需要扫描对象的根路径.注意:这个根路径是从java目录开始的.
在这里插入图片描述

2. 添加注解存储 Bean 对象

想要将对象存储在spring中,有两种注解类型可以实现:

  1. 使用类注解(五大类注解):

    • @Controller:控制器:验证用户请求的数据正确性(相当于安保系统).
    • @Service:服务:编排和调度具体执行方法(相当于客服中心).
    • @Repository:持久层:和数据库交互;(相当于执行者) = DAO(Date Access Obiect)数据访问层
    • @Component:组件;(工具类)
    • @Configuration:配置项(项目中的一些配置)
  2. 方法注解

    • @Bean

2.1 使用五大类注解存储Bean

首先,我们来了解如何使用五大类注解来储存对象

  1. @Controller

    package com.spring.demo;import org.springframework.stereotype.Controller;@Controller
    public class UserController {public void sayHi() {System.out.println("UserController sayHi!");}
    }
    

    在扫描路径下创建该UserController类.并在类上加@Controller注解,此时就将Bean存储到容器中了.

    接下来就是从 Spring 中读取出我们的对象,这里还是先使用依赖查找的方式来获取 Bean,使用五大类注解,默认情况下,Bean 的名字就是原类名首字母小写(小驼峰).

    import com.spring.demo.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {//1.获取 srping 容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//2.获取 bean 对象//获取对象时使用类名的小驼峰形式作为 name 参数UserController userController =  context.getBean("userController", UserController.class);//3.使用 beanuserController.sayHi();}
    }
    

    运行结果:
    在这里插入图片描述
    注意:要将Bean存储到Spring中需要满足两个条件:

    1. 使用五大类注解创建的类
    2. 必须在配置的扫描路径下.(包括子包)

    扫描路径也叫做根路径.两个条件缺一不可.

    为什么要设置根路径?
    设置根路径其实也是为了提高程序的性能,因为如果不设置根路径,Spring 就会扫描项目文件中所有的目录,但并不是所有类都需要储存到 Spring当中,这样性能就会比较低,设置了根路径,Spring 就只扫描该根路径下所有的目录就可以了,提高了程序的性能。下来我们演示一下没有配置扫描路径下的情况:
    在这里插入图片描述
    还需要知道的是使用注解存储的 Bean 和使用XML存储的的 Bean 是可以一同使用的,比如我们将刚刚有问题的Student重新通过XML的方式进行存储.
    在这里插入图片描述

    注意:默认情况下,使用原类名首字母小写就能读取到Bean对象.特例情况:原类名如果首字母和第二个字母都是大写的情况下,那么bean名称就是原类名.
    在这里插入图片描述

  2. @Service
    启动类中代码:

    //1.获取 srping 容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//2.获取 bean 对象//获取对象时使用类名的小驼峰形式作为 name 参数UserService userService =  context.getBean("userService", UserService.class);//3.使用 beanuserService.sayHi();
    

    UserService类:

    package com.spring.demo;import org.springframework.stereotype.Service;@Service
    public class UserService {public void sayHi(){System.out.println("UserService sayHi!");}
    }
    

    运行结果:
    在这里插入图片描述

其余三种使用方式相同,此处不再做介绍.

2.2 为什么要有五大类注解?

既然都五大类完成的是同样的工作,那为什么要有五大类注解呢?

其实五大类注解主要是为了规范 Java 项目的代码,Java 项目的标准分层如下:

  1. 控制层(Controller)
  2. 服务层(Service)
  3. 数据持久层(Dao)

而五大类注解便是对应着不同的层级别使用的,让程序猿看到某一个注解就可以明确这个了类是做什么的。
程序的⼯程分层,调⽤流程如下:
在这里插入图片描述
包括企业中也是按照这样的结构来将项目分层的,典型的比如阿里,它只是在标准分层在服务层(Service)做了一个扩展,划分的更加细致详细了.
在这里插入图片描述
五大类注解主要起到的是“见名知意”的作用,代码层面上来看,作用是类似的.查看五大类源码可知:
五大类的源码中除了 @Component 以外,其他四大类注解中都包含了 @Component 注解的功能,这四大类注解都是基于 @Component 实现的,是 @Component 拓展。

2.3 有关获取Bean参数的命名规则

上文中在使用依赖查找的方式获取Bean时,我们讲到了getBean方法的BeanName是使用类名的小驼峰形式(即类名的首字母小写)以及第一个字母和第二个字母都大写情况下的特例.

注意:BeanName的规范命名规则并不是 Spring 独创的,而依照 Java 标准库的规则进行的。

BeanName的规范命名规则:

  1. 如果类名不存在或类名为空字符串,BeanName为原类名。
  2. 如果类名字长度大于1,且第一个与第二个字符为大写,BeanName为原类名。
  3. 其他情况,BeanName为原类名的小驼峰形式.

3. 使用方法注解储存 Bean 对象

3.1 方法注解储存对象的用法

类注解是添加到某个类上的,而方法注解是放到某个方法上的.在Spring框架的设计中,方法注解@Bean要配合类注解才能将对象正常存储到Spring容器中.

举个🌰:我们有一个普通书本类

package com.spring.demo;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;@Controller
public class BookInfo {private String bookName;private String author;private String style;public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getStyle() {return style;}public void setStyle(String style) {this.style = style;}@Override@Beanpublic String toString() {return "com.spring.demo.BookInfo{" +"bookName='" + bookName + '\'' +", author='" + author + '\'' +", style='" + style + '\'' +'}';}}

下面演示使用@Bean方法注解储存对象:

package com.spring.demo;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;@Controller
public class Books {@Beanpublic BookInfo getBook(){BookInfo bookInfo = new BookInfo();bookInfo.setBookName("三体");bookInfo.setAuthor("刘慈欣");bookInfo.setStyle("文学科幻");return bookInfo;}public void sayHi(){System.out.println("Books sayHi!");}
}

启动类:

获取方法注解储存的对象时,传入的BeanName参数值默认值就是方法名,上面的代码中方法名为getBook,所以获取时,就使用getBook作为参数来进行获取。

import com.spring.demo.BookInfo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BookInfo book =  context.getBean("getBook", BookInfo.class);System.out.println(book);}
}

运行结果:
在这里插入图片描述

3.2 @Bean的重命名

获取方法注解储存的对象时,传入的BeanName参数值默值为方法名,但像上面那样返回对象的方法名称往往是getXXX这样式取名的,虽然在语法与实现上是没有问题的,但实际开发写出这样的代码,看起来还是比较别扭的。
实际上注解 @Bean 是可以加参数的,给储存的对象起别名,像下面这个样子。

package com.spring.demo;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;@Controller
public class Books {@Bean(name = "book")public BookInfo getBook(){BookInfo bookInfo = new BookInfo();bookInfo.setBookName("三体");bookInfo.setAuthor("刘慈欣");bookInfo.setStyle("文学科幻");return bookInfo;}public void sayHi(){System.out.println("Books sayHi!");}
}

在这里插入图片描述

也可以给 Bean 设置多个别名,总结起来有如下几种方式:

//方式一(省略参数名的情况下默认是name)
@Bean("article1")
//方式二
@Bean(name = "article2")
//方式三
@Bean(value = "article3")
//起多个别名
@Bean(name = {"article4", "article5"})
@Bean(value = {"article6", "article7"})
@Bean({"article8", "article9", "article10"})

但是需要注意,当重新命名之后,就不能使用原来的方法名来获取对象了.
在这里插入图片描述
所以使用 @Bean 存储对象的beanName命名规则是,当没有设置name/value属性时,此时 Bean 的默认名字就是方法名,一旦添加了别名name/value属性后,就只能通过重命名的别名来获取 Bean 了,默认的使用方法名获取 Bean 对象就不能使用了。

@Bean 使用时,同一类如果多个 Bean 使用相同的名称,此时程序执行是不会报错的,他会根据类加载顺序和类中代码从上至下的的顺序,将第一个 Bean 存放到 Spring 中,但第一个之后的对象就不会被存放到容器中了,也就是只有在第一次创建 Bean 的时候会将对象和 Bean 名称关联起来,后续再有相同名称的Bean存储时候,容器会自动忽略。

还可以通过类注解 @Order 注解控制类加载顺序(值越小,优先级越高),进而影响 Bean 的存放的先后顺序.

3.3 同⼀类型多个 @Bean 报错

当出现以下多个 Bean,返回同⼀对象类型时程序会报错,如下代码所示:
在这里插入图片描述
在这里插入图片描述
运行结果如下:
在这里插入图片描述
报错的原因是,⾮唯⼀的 Bean 对象.
同⼀类型多个 Bean 报错处理:
解决同⼀个类型,多个 bean 的解决⽅案有以下两个:

  1. 使⽤ @Resource(name="user1") 定义。(@Resource下文有介绍)
    在这里插入图片描述
  2. 使⽤ @Qualifier 注解定义名称。
    在这里插入图片描述

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

获取bean对象也叫做对象装配.是把bean对象取出来放到某个类中.有时候也叫对象注⼊(DI).
对象装配(对象注⼊)的实现⽅法以下 3 种:

  1. 属性注⼊
  2. 构造⽅法注⼊
  3. Setter 注⼊
    接下来,我们分别来看。
    下⾯我们按照实际开发中的模式,将 Service 类注⼊到 Controller 类中。

1. 属性注入

属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中。
User代码:

package com.spring.demo;public class User {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}
}

Service代码:

package com.spring.demo;import org.springframework.stereotype.Service;@Service
public class UserService {public void sayHi(){System.out.println("UserService sayHi!");}public User getUser(Integer id){User user = new User();user.setId(id);user.setName("xxxflower-"+id);return user;}}

Controller代码:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {@Autowiredprivate UserService userService;public User getUser(Integer id){return userService.getUser(id);}public void sayHi() {System.out.println("UserController sayHi!");}
}

运行结果:
在这里插入图片描述
在这里插入图片描述
优点:简单.
缺点:

  1. 没办法实现final修饰的变量注入.
    在这里插入图片描述
  2. 兼容不好:只适用于Ioc容器.
  3. 风险:因为写法简单,所以违背单一设计原则的概率更大.

2. Setter注入

Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解,如下代码所示:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController2 {private UserService userService;//2.使用Setter注入@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public User getUser(Integer id){return userService.getUser(id);}
}

运行结果:
在这里插入图片描述
优点:符合单一设计原则(每个方法只传递一个对象)
缺点:

  1. 不能注入不可变对象
    在这里插入图片描述
  2. 使用setter注入的对象可能会被修改.

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

构造⽅法注⼊是在类的构造⽅法中实现注⼊,如下代码所示:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController3 {private UserService userService;//3.构造方法注入@Autowiredpublic UserController3(UserService userService){this.userService = userService;}public User getUser(Integer id){return userService.getUser(id);}
}

运行结果:
在这里插入图片描述
特点:如果当前类中只有一个构造方法的话,那么@Autowired 注解可以省略.
在这里插入图片描述
优点:

  1. 可以注入一个不可变对象(使用fianl修饰的对象)
    在这里插入图片描述

问题:为什么构造方法可以注入一个不可变对象,而属性注入和Setter注入却不行?
答:这是Java的规定,在java中,被final对象必须满足以下两个条件中的任意一个:

  1. final修饰的对象,是直接复制的.
  2. final修饰的对象,必须在构造方法中赋值.
  1. 注入的对象不会被改变(构造方法只能执行一次)
  2. 构造方法注入可以保证注入对象完全被初始化
  3. 通用性更好.

4. @Resource:另⼀种注入关键字

在进行类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊,如下代码所示:

package com.spring.demo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;import javax.annotation.Resource;@Controller
public class UserController {//    @Autowired@Resourceprivate UserService userService;public User getUser(Integer id){return userService.getUser(id);}public void sayHi() {System.out.println("UserController sayHi!");}
}

上述三种注入方式使用@Autowired行,使用@Resource也行,但是这两者也是有区别的:

  1. 出身不同:@Autowired 来自于 Spring,而 @Resource 来⾃于 JDK 的注解;
  2. 使⽤时设置的参数不同:相比于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如
    name 设置,根据名称获取 Bean。
  3. @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊。
  4. @Autowired 先根据类型查找(byType),之后再根据名称查找(byName)。@Resource 先根据名称去查,之后再根据类型去查。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【力扣每日一题】88. 合并两个有序数组 双指针 辅助数组 8.13打卡

文章目录 题目思路代码 题目 88. 合并两个有序数组 难度&#xff1a; 简单 描述&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&am…

Excel(1):表头或列头冻结

1.需求 对于较大的excel&#xff0c;通常需要固定一部分内容&#xff0c;另一份内容为可翻动。 2.解决方式 在视图中选择冻结窗格&#xff0c;需要注意的是&#xff0c;选择冻结窗格时&#xff0c;窗格的左上方的表格区域是固定不动的&#xff0c;只可以向下或者向右活动。

TCP/IP 下的计算机网络江湖

〇、引言 在当今数字化时代,计算机网络宛如广袤江湖,涵盖着五大门派:物理层、数据链路层、网络层、传输层和应用层。每个门派独具技能,共同构筑着现代网络的框架。物理层宛如江湖基石,将比特流传输;数据链路层如武林传承,组织数据帧传递;网络层则像导航大师,寻找传送路…

EMQX Enterprise 5.1 正式发布:生产环境就绪的 MQTT over QUIC、基于 MQTT 的文件传输支持

近日&#xff0c;企业级 MQTT 物联网接入平台 EMQX Enterprise 5.1 正式发布。该版本为用户提供了更强大、更灵活的物联网解决方案&#xff0c;通过简化功能操作与管理流程&#xff0c;帮助用户快速构建所需的业务。 新版本提供了更大规模且更具伸缩性的全新集群架构&#xff…

Mac M2 Pro安装使用Cocoapods

Mac Pro M2安装使用Cocoapods 在新公司要做iOS开发&#xff0c;所以在新电脑上安装Cocoapods 在升级gem&#xff0c;sudo gem update --system&#xff0c;和安装cocoapods时都遇到如下的提示&#xff1a; ERROR: While executing gem ... (Errno::EPERM)Operation not per…

探讨uniapp的网络通信问题

uni-app 中有很多原生的 API&#xff0c;其中我们经常会用到的肯定有&#xff1a;uni.request(OBJECT) method 有效值 注意&#xff1a;method有效值必须大写&#xff0c;每个平台支持的method有效值不同&#xff0c;详细见下表。 success 返回参数说明 data 数据说明 最终…

赛事 | 第25届中国机器人及人工智能大赛全国决赛榜单发布

第25届中国机器人及人工智能大赛成功举办 2023年6月13日至14日&#xff0c;第二十五届中国机器人及人工智能大赛于海南科技职业大学成功举办。大赛由中国人工智能学会主办&#xff0c;共有来自清华大学、哈尔滨工业大学、中国科学技术大学、西安交通大学等500多所高校进入全国…

线性代数(三) 线性方程组向量空间

前言 如何利用行列式&#xff0c;矩阵求解线性方程组。 线性方程组的相关概念 用矩阵方程表示 齐次线性方程组&#xff1a;Ax0&#xff1b;非齐次线性方程组&#xff1a;Axb. 可以理解 齐次线性方程组 是特殊的 非齐次线性方程组 如何判断线性方程组的解 其中R(A)表示矩阵A的…

【RabbitMQ上手——单实例安装5种简单模式实现通讯过程】

【RabbitMQ入门-单实例安装&5种简单模式实现通讯过程】 一、环境说明二、安装RabbitMQ三、用户权限及Virtual Host设置四、5种简单模式实现通讯过程的实现五、小结 一、环境说明 安装环境&#xff1a;虚拟机VMWare Centos7.6 Maven3.6.3 JDK1.8RabbitMQ版本&#xff1a;…

Windows CMD 关闭,启动程序

Windows CMD 关闭&#xff0c;启动程序 1. Windows 通过 CMD 命令行关闭程序 示例&#xff1a;通过 taskkill 命令关闭 QQ 管家&#xff0c;但是这里有个问题&#xff0c;使用命令行关闭 QQ 管家时&#xff0c;会提示“错误: 无法终止 PID 1400 (属于 PID 22116 子进程)的进程…

ABeam×Startup丨德硕管理咨询(深圳)创新研究团队前往灵境至维·既明科技进行拜访交流

近日&#xff0c;德硕管理咨询&#xff08;深圳&#xff09;&#xff08;以下简称“ABeam-SZ”&#xff09;创新研究团队一行前往灵境至维既明科技有限公司&#xff08;以下简称“灵境至维”&#xff09;进行拜访交流&#xff0c;探讨线上虚拟空间的商业模式。 现场合影 &…

基于灰色神经网络的订单需求预测代码

目录 1 概述 2 代码 3 结果 ​ 1 概述 BP(Back Propagation)神经网络模型是一种信息前向传播,误差反向传播的神经网络模型0,能够通过训练样本反向传播调节网络的阈值和权值,使误差平方最小。 BP神经网络是目前应用最广泛的神经网络模型之一。 灰色人工神经网络模型建模过…

了解华为(H3C)网络设备和OSI模型基本概念

目录 一&#xff0c;认识华为 1.华为发展史 2.华为网络设备介绍 3.VRP概述 二&#xff0c;OSI七层模型 1.七层模型详细表格 2.各层的作用 3.数据在各层之间的传递过程 4.OSI四层网络模型 一&#xff0c;认识华为 官网&#xff1a;https://www.huawei.com/cn/ 1.华为发…

MyBatis快速入门

一、Mybatis介绍 MyBatis是一个支持普通SQL查询&#xff0c;存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射&#xff0c;将接口和Java的POJO&#xff08;Pla…

<Vite>HMR实现原理

什么是HMR&#xff1f; HMR&#xff08;Hot Module Replacement&#xff09;是一种开发工具&#xff0c;也就是热更新。用于在应用程序运行时替换、添加或删除模块&#xff0c;而无需完全重新加载整个页面或重新启动应用程序。这可以极大地提高开发效率和调试体验。 HMR的优势 …

vue table动态合并, 自定义合并,参照合并,组合合并

<template><div><el-table:data"tableData":span-method"objectSpanMethod"border:header-cell-style"{ textAlign: center }"><el-table-column prop"area" label"区域" align"center">…

ios 知识

IOS 类文件.h和.m中interface的区别 大家都知道我们在创建类文件时会发现&#xff1a; #import <UIKit/UIKit.h>interface ViewController : UIViewControllerend和 #import "ViewController.h"interface ViewController ()end那么他们之间有何区别呢&#x…

MySql存储过程详解

文章目录 存储过程1 介绍 基本语法创建:调用查看删除演示: 变量相关系统变量演示: 用户自定义变量局部变量 if语法参数介绍casewhilerepeatloop游标条件处理程序存储函数 存储过程 1 介绍 存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合&#xff0c;调用存储过…

kafka 02——三个重要的kafka客户端

kafka 02——三个重要的kafka客户端 1. 前言1.1 关于 Kafka 的安装1.2 常用客户端简介1.3 依赖 2. AdminClient2.1 Admin Configs2.2 AdminClient API2.2.1 设置 AdminClient 对象2.2.2 创建 topic 获取 topic 列表2.2.3 删除topic2.2.4 查看 topic 的描述信息2.2.5 查看 topi…

Python系统学习1-7-字典

一、字典 1、概念及内存图 列表&#xff1a;由一系列变量组成的可变序列容器字典&#xff1a;由一系列键值对组成的可变散列容器字典优势&#xff1a;利用&#xff08;内存&#xff09;空间&#xff0c;换取&#xff08;CPU查找&#xff09;时间 键key 必须唯一且为不…