JavaEE5-Spring更简单的读取和存储对象

news2024/11/14 14:30:45

目录

1.存储Bean对象

1.1.前置工作:在配置文件中设置bean扫描的根路径(重要)

1.2.添加注解存储Bean对象到Spring中

1.2.1.类注解(添加到某个类上,将当前的类存储到Spring中):@Controller,@Service,@Repository,@Component,@Configuration

关于类注解的bean的命名规则:

PS:为什么要这么多类注解?

1.2.2.方法注解(添加到某个方法上,将当前方法返回的对象存储到Spring中):@Bean

2.获取Bean对象(对象装配/对象注入)

2.1.属性注入:是使用@Autowired(自动写入)注解实现的

2.2.构造方法注入:是在类的构造方法中实现注入

2.3.Setter注入:和属性的Setter方法实现类似,只不过在设置set方法时需要加上@Autowired注解

PS:(经典面试题)属性注入,构造方法注入和Setter注入的异同分析?

2.4.另一种注入关键字:@Resource

2.4.1.属性注入:

2.4.2.Setter注入:

PS:(经典面试题)@Autowired和@Resource的区别?

2.5.同一类型多个@Bean报错

处理方法:

2.5.1.使用正确的bean name来获取(有限制,不用于大规模使用)

2.5.2.使用@Resource注解设置name属性(最简单)(@Autowired只有一个参数,没有name属性)

2.5.3.使用@Autowired + @Qualifier


在Spring中想要更简单地读取和存储对象的核心是使用注解。(Spring,SpringBoot,SpringMVC中的注解是通用的)

1.存储Bean对象

之前需要在spring-config.xml文件中添加bean标签注册内容,而xml的问题在于出错的概率和排错的难度都高:

  • 无法像代码一样调试,只能人工去看;
  • 有错后IDEA不会提示/即使有提示,程序也能正常运行;
  • 写法不方便。

而现在只需要一个注解就ok~

1.1.前置工作:在配置文件中设置bean扫描的根路径(重要)

要想将对象存储到Spring中,需要配置存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确地识别并保存到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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--设置需要存储到spring中的bean根目录-->
    <content:component-scan base-package="com.beans"></content:component-scan>
</beans>

其中:

<content:component-scan base-package="com.beans"></content:component-scan>

content:正文;

component-scan:扫描组件;

base-package:根目录(写自己的)。

规定了需要存储到Spring中的类的根目录的扫描路径,否则要扫描当前项目下的所有的类(要加到Spring中的和不要加到Spring中的类),这样提高了效率。

base-package是当前路径当前路径下的所有子路径下的所有的bean。

1.2.添加注解存储Bean对象到Spring中

1.2.1.类注解(添加到某个类上,将当前的类存储到Spring中):@Controller,@Service,@Repository,@Component,@Configuration

使用这5大类注解中的任意一种都可以将bean存储到Spring中。

注:

  1. 即使在Spring配置文件中配置了bean的扫描路径,5大类注解依旧不能省略。
  2. 即使加了5大类注解,但类没有放在Spring配置的bean路径下,那么也是不能将类注入到Spring中的。

①@Controller(控制器存储)

@Controller //将当前对象存储到Spring中
public class UserController {
    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("userController");//通常情况下是小驼峰(将加注解的类的类名首字母小写)就可以获取到bean对象
        //3.使用bean
        userController.sayHi("张三");
    }
}

当使用id获取带注解的bean时:

关于类注解的bean的命名规则:

通常bean使用的都是标准的大驼峰命名:

若bean的命名为第一个字母大写,第二个字母小写,那么读取时将bean的名称首字母小写

若bean的命名为第一个字母和第二个字母都大写,那么读取时为原bean名

若bean的命名为第一个字母和第二个字母都小写,那么读取时为原bean名(一般不存在)。

查看源码:

②@Service(服务存储)

@Service //将当前对象存储到Spring中
public class UserService {
    public void sayHi(String name){
        System.out.println("Hi," + name);
    }
}

③@Repository(仓库存储)

@Repository //将当前对象存储到Spring中
public class UserRepository {
    public void sayHi(String name){
        System.out.println("Hi," + name);
    }
}

④@Component(组件存储)

@Component //将当前对象存储到Spring中
public class UserComponent {
    public void sayHi(String name){
        System.out.println("Hi," + name);
    }
}

⑤@Configuration(配置存储)

@Configuration //将当前对象存储到Spring中
public class UserConfiguration {
    public void sayHi(String name){
        System.out.println("Hi," + name);
    }
}

PS:为什么要这么多类注解?

①5大类注解之间的关系:

查看源码:

 结论:@Controller,@Service,@Repository,@Configuration这4个注解都是依靠@Component注解来实现的,因此@Component注解是其他4个注解的父类。那为啥还要其他4个呢?

②程序的工程分层-调用流程:

一个项目中后端接口最少有这4个目录,方便大型项目中类的分类,查找,维护:让程序员看到类注解后,能直接了解当前类的用途,让逻辑条理更加清晰;也方便项目的人员分工,每人只针对一部分即可。而若都是@Component注解,则不会直观地了解到类的用途。

so~类注解由1个变5个,使得整个代码的语义更加直观!

  • @Controller:业务逻辑层/控制器层,和前端请求打交道,验证前端的有效性;
  • @Service:服务层,组织数据调用相应的接口,不做具体的业务;
  • @Repository:数据持久层/仓库(不同的叫法:dao/repository),和数据打交道,执行具体的CRUD操作;
  • @Configuration:配置层,存放所有的配置信息。

还可能会有更多分层,如有实体层,工具层等。

1.2.2.方法注解(添加到某个方法上,将当前方法返回的对象存储到Spring中):@Bean

①方法注解要配合类注解一起使用,才能将对象正常存储到Spring中。(主要是为了考虑性能的问题) 默认读取bean的名称为方法名。

@Component
public class UserBeans {
    @Bean
    public User getUser() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123");
        return user;
    }
}

②重命名Bean

方法名主要体现业务性,多为动词;读取bean名称多为名词。若默认二者相等会比较奇怪。

那么可以通过在@Bean注解中设置name属性给Bean对象进行重命名操作:

@Component
public class UserBeans {
    @Bean(name = {"user1"})
    public User getUser() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123");
        return user;
    }
}

注:

1).这个重命名的name其实是一个数组,一个bean可以有多个名字。

含有"{ }"的写法表示给当前对象起一个或多个别名。

@Bean(name = {"user1"})
@Bean(name = {"user1", "user2"})

并且name = { } 可以省略。

@Bean("user1", "user2")

不含有"{ }"的写法表示给当前对象起一个别名。

@Bean(name = "user1")

2).当@Bean注解重命名之后就不能使用方法名来读取bean了。

2.获取Bean对象(对象装配/对象注入)

获取bean对象是把对象取出来放到某个类中。实现方法有3种。5大类注解不能省略(存了才能取)。

2.1.属性注入:是使用@Autowired(自动写入)注解实现的

例:将Service类注入到Controller类中:

Service类的实现代码如下:

import com.model.User;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    /**
     * 根据id获取用户数据
     * @param id
     * @return
     */
    public User getUserById(Integer id) {
        //伪代码,不连接数据库
        User user = new User();
        user.setId(id);
        user.setName("唐僧");
        user.setPassword("123456");
        return user;
    }
}

Controller类的实现代码如下:

import com.beans.service.UserService;
import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    //1.属性注入:先定义一个属性,再把对象注入给属性
    @Autowired
    private UserService userService;

    public User getUserById(Integer id) {
        return userService.getUserById(id);
    }
}

获取Controller中的getUserById方法:

import com.beans.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //2.得到bean
        UserController userController = context.getBean(UserController.class);
        //3.使用bean
        System.out.println(userController.getUserById(10));
    }
}

2.2.构造方法注入:是在类的构造方法中实现注入

如果当前类只有一个构造方法,则@Autowired注解可以省略;如果当前类有多个构造方法,则@Autowired注解不可以省略。

import com.beans.service.UserService;
import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller 
public class UserController2 {
    private UserService userService;

    //2.构造方法注入
    @Autowired
    public UserController2(UserService userService) {
        this.userService = userService;
    }

    public UserController2(UserService userService, Integer id) {
        this.userService = userService;
    }

    public User getUserById(Integer id) {
        return userService.getUserById(id);
    }
}

2.3.Setter注入:和属性的Setter方法实现类似,只不过在设置set方法时需要加上@Autowired注解

import com.beans.service.UserService;
import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController3 {
    private UserService userService;

    //3.Setter注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public User getUserById(Integer id) {
        return userService.getUserById(id);
    }
}

PS:(经典面试题)属性注入,构造方法注入和Setter注入的异同分析?

都可以将一个对象注入到当前的类当中。

属性注入(差):

优点:简洁,使用方便。官方实际还是用属性注入多些

缺点:不通用,只能用于IoC容器,非IoC容器不可用(使用的时候会出现NPE(空指针异常))。

构造方法注入(好):

优点:通用性强;且在使用之前一定能保证注入的类不为空(能保证在调用对象之前,此对象一定是存在的)是Spring后期推荐的注入方式

缺点:可能存在传递多个参数来实现构造方法的初始化,如果有多个注入会显得代码比较臃肿,但出现这种情况是程序员自身的问题,他需要反思当前类是否符合程序的单一职责的设计模式。

Setter注入(中):

优点:是Spring早期版本推荐的注入方式,比属性注入适用性好,无论是IoC容器还是非IoC容器都可以使用。

缺点:通用性不如构造方法注入,所有Spring版本已经推荐使用构造方法注入的方式来进行类注入了。

2.4.另一种注入关键字:@Resource

在进行对象注入时,除了可以使用@Autowired关键字之外,还可以使用@Resource进行注入。

2.4.1.属性注入:

import com.beans.service.UserService;
import com.model.User;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;

@Controller
public class UserController4 {
    @Resource //引入一个资源到当前类
    private UserService userService;

    public User getUserById(Integer id){
        return userService.getUserById(id);
    }
}

2.4.2.Setter注入:

import com.beans.service.UserService;
import com.model.User;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;

@Controller 
public class UserController5 {
    private UserService userService;

    @Resource
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public User getUserById(Integer id){
        return userService.getUserById(id);
    }
}

PS:(经典面试题)@Autowired和@Resource的区别?

①出身不同:

@Autowired是Spring框架提供的实现;

而@Resource是JDK提供的实现。

②支持的参数设置不同:

@Autowired只支持required设置;

@Autowired注解源码实现

而@Resource支持更多的参数设置,如name设置,根据名称获取bean。

 @Resource注解源码实现

③支持的注入类型不同:

@Autowired支持属性注入,构造方法注入和Setter注入;

而@Resource只支持属性注入和Setter注入。

④获取注入一个对象时的机制不同:

@Autowired默认先按Type进行匹配,如果找到多个bean,则又会按照组件id方式进行匹配(需要@Qualifier("name")配合);

而@Resource默认按照组件id自动注入,如果按照默认组件id找不到bean时,再按照类型去匹配。

2.5.同一类型多个@Bean报错

import com.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class UserBeans {
    @Bean(name = {"user1"})
    public User getUser1() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123");
        return user;
    }

    @Bean(name = "user2")
    public User getUser2() {
        User user = new User();
        user.setId(2);
        user.setName("李四");
        user.setPassword("456");
        return user;
    }
}
import com.model.User;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;

@Controller
public class UserController6 {
    @Resource
    private User user;

    public void sayHi(){
        System.out.println(user);
    }
}
import com.beans.controller.UserController6;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController6 controller6 = context.getBean(UserController6.class);
        controller6.sayHi();
    }
}

一个类型被注册到Spring多次时,程序运行会出现异常报错:非唯一的Bean对象。

处理方法:

2.5.1.使用正确的bean name来获取(有限制,不用于大规模使用)

import com.model.User;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;

@Controller
public class UserController6 {
    @Resource
    private User user2;

    public void sayHi(){
        System.out.println(user2);
    }
}

2.5.2.使用@Resource注解设置name属性(最简单)(@Autowired只有一个参数,没有name属性)

import com.model.User;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;

@Controller
public class UserController6 {
    @Resource(name = "user1")
    private User user;

    public void sayHi(){
        System.out.println(user);
    }
}

2.5.3.使用@Autowired + @Qualifier

@Qualifier只有一个属性,做筛选功能。

import com.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

@Controller
public class UserController6 {
    @Autowired
    @Qualifier(value = "user2")
    private User user;

    public void sayHi(){
        System.out.println(user);
    }
}

 其中:

@Qualifier(value = "user2")

也可以省略"value =",写为:

@Qualifier("user2")

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

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

相关文章

树,堆,二叉树的认识

1.树概念及结构 1.1树的概念 注意&#xff1a;树形结构中&#xff0c;子树之间不能有交集&#xff0c;否则就不是树形结构 1.2 树的相关概念 1.3 树的表示 树结构相对线性表就比较复杂了&#xff0c;要存储表示起来就比较麻烦了&#xff0c;既然保存值域&#xff0c;也要保存…

Gateway服务网关

Gateway服务网关一、网关介绍二、gateway快速入门1.创建gateway服务&#xff0c;引入依赖2.编写启动类3.编写基础配置和路由规则4.重启测试5.网关路由的流程图三、断言工厂四、过滤器工厂1.路由过滤器的种类2.请求头过滤器3.默认过滤器4.总结五、全局过滤器1.全局过滤器作用2.自…

fpga实操训练(系统开发和硬件接口)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 相信很多学习fpga的同学都会有这样的一个感受,一开始fpga学习还比较简单,但是一旦涉及到呼吸灯、uart、spi、iic、ddr2后面就会越来越难。遇到这样的困难之后,学习的激情一下子少…

从零搭建一个组件库(一)项目环境搭建

文章目录前言monorepo架构1.monorepo架构的优势2.使用pnpm搭建monorepo架构&#xff08;1&#xff09;全局安装pnpm&#xff08;2&#xff09;初始化项目&#xff08;3&#xff09;新建workspace.yaml文件4.不同包之间的相互引用TypeScript支持1.安装TypeScript2.初始化TypeScr…

http三次握手四次挥手详解

1、 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手&#xff1a;为了对每次发送的数据量进行跟踪与协商&#xff0c;确保数据段的发送和接收同步&#xff0c;根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系&#xff0c;并建立虚连接。 四次挥…

C++6:STL-模拟实现string

string时STL中的模板库之一&#xff0c;类似于专门处理字符串的数据结构&#xff0c;在模拟实现并探讨其中构造的巧妙之处之前&#xff0c;我们短浅的认识一下STL是什么 目录 什么是STL STL的诞生 关于string string的模拟实现 构造函数和析构函数 实现简单的string打印 …

【蓝桥杯】简单数论2——快速幂矩阵快速幂

1、快速幂 1.1运算模 定义&#xff1a;模运算为a除以m的余数&#xff0c;记为a mod m&#xff0c;有a mod m a % m。 模运算是大数运算中的常用操作&#xff1a;如果一个数太大&#xff0c;无法直接输出&#xff0c;或者不需要直接输出&#xff0c;可以把它取模后&#xff0…

Android 深入系统完全讲解(37)

7.5 源码讲解 dlopen 打开动态库 dlsym 找到符号 (*print_func)(); 调用方法 我们可以看到&#xff0c;要使用一个 so 库的某个方法&#xff0c;就上面三步骤&#xff0c;加载 &#xff0c;查找 &#xff0c;使用 。我 们这里调用了 so 库中的 my_print 方法。 7.6 运行 我们把…

Linux——进程间通信

文章目录前言1. 进程间通信方式的一些标准&#xff1a;2. 管道2.1 什么是管道2.2 管道的原理2.3 匿名管道2.3.1 实例代码1. demo代码2. 总结管道的特点&#xff0c;理解以前的管道 |3. 扩展——进程池2.4 管道读写规则2.5 命名管道2.5.1 创建一个命名管道2.5.2 命名管道的打开规…

Python break用法详解

我们知道&#xff0c;在执行 while 循环或者 for 循环时&#xff0c;只要循环条件满足&#xff0c;程序将会一直执行循环体&#xff0c;不停地转圈。但在某些场景&#xff0c;我们可能希望在循环结束前就强制结束循环&#xff0c;Python 提供了 2 种强制离开当前循环体的办法&a…

路由处理及功能(实现了权限控制vue admin)

界面简化 将 template 改为&#xff1a; <template><div class"login-container"><el-formref"loginForm":model"loginForm":rules"loginRules"class"login-form"autocomplete"on"label-positio…

Mybatis遇到的脑残问题

一、MySQL的版本问题 有的教程mysql是8.0版本使用jar包不一样 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0</version></dependency>然后我查了一下我的mysql版本是5.7版…

分支语句与循环语句

文章目录 什么是语句&#xff1f; 分支语句&#xff08;选择结构&#xff09;循环语句goto语句前言 一、什么是语句&#xff1f; C语句可分为以下五类&#xff1a; 1. 表达式语句 2. 函数调用语句 3. 控制语句 4. 复合语句 5. 空语句 控制语句用于控制程序的执行流程&#xff0…

第九层(1):初识STL

文章目录前情回顾初识STLSTL的诞生STL的基本概念STL六大组件STL中的容器、算法、迭代器容器算法迭代器容器、算法、迭代器的配合使用vector中的嵌套使用石碑倒下...后面还有石碑&#xff1f;本章知识点&#xff08;图片形式&#xff09;&#x1f389;welcome&#x1f389; ✒️…

为什么带NOLOCK的查询语句还会造成阻塞

背景客户反映HIS数据库在11点出现了长时间的阻塞&#xff0c;直到手动KILL掉阻塞的源头。请我们协助分析原因&#xff0c;最终定位到.NET程序中使用的SqlDataReader未正常关闭导致。现象登录SQL专家云&#xff0c;进入趋势分析&#xff0c;在活动会话中回溯11点一个小时内的运行…

【Ajax】防抖和节流

一、防抖什么是防抖防抖策略&#xff08;debounce&#xff09;是当事件被触发后&#xff0c;延迟 n 秒后再执行回调&#xff0c;如果在这 n 秒内事件又被触发&#xff0c;则重新计时。如果事件被频繁触发&#xff0c;防抖能保证只有最有一次触发生效&#xff01;前面 N 多次的触…

【Linux IO】文件描述符、重定向、缓冲区

1.open函数1.1第二个参数的解释&#xff1b;O_RDONLY: 只读打开 O_WRONLY: 只写打开 O_RDWR : 读&#xff0c;写打开上面三个常量&#xff0c;必须指定一个且只能指定一个 O_CREAT : 若文件不存在&#xff0c;则创建它。需要使用mode选项&#xff0c;来指明新文件的访问权限 O_…

MyBatis 连接数据库与增删改查

❤️作者主页&#xff1a;微凉秋意 ✅作者简介&#xff1a;后端领域优质创作者&#x1f3c6;&#xff0c;CSDN内容合伙人&#x1f3c6;&#xff0c;阿里云专家博主&#x1f3c6; ✨精品专栏&#xff1a;数据结构与课程设计 &#x1f525;系列专栏&#xff1a;javaweb 文章目录前…

C++设计模式(8)——命令模式

命令模式 亦称&#xff1a;动作、事务、Action、Transaction、Command 意图 命令模式是一种行为设计模式&#xff0c; 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中&#xff0c; 且能…

linux基本功系列之-lsattr命令实战

文章目录一. lsattr命令实战二. 语法格式及常用选项三. 参考案例3.1 查看指定文件上的隐藏属性&#xff1a;3.2 查看目录的隐藏属性3.3 查看目录中全部文件的隐藏属性总结前言&#x1f680;&#x1f680;&#x1f680; 想要学好Linux&#xff0c;命令是基本功&#xff0c;企业中…