Spring 的存储和获取Bean

文章目录

  • 获取 Spring 上下文对象的方式
  • 存储 Bean 对象的方式
    • 类注解
      • 配置扫描路径(必须)
      • @Controller(控制器存储)
      • @Service(服务)
      • @Repository(持久层)
      • @Component(工具)
      • @Configuration(项目中的一些配置)
      • 关于五大类注解
    • 方法注解
  • 获取指定的 Bean 对象的方式
    • 普通方式
    • 对象注入
      • 属性注入
      • 构造方法注入
      • Setter 注入
      • @Resource:另⼀种注入关键字
      • 总结

获取 Spring 上下文对象的方式

首先获取 Bean 对象之前都需要先获取 Spring 的上下文对象,那么获取这个对象可以有以下方式

ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

那么这两者之间有什么区别呢,现在新建两个 Bean 类运行起来后看结果:

1、ApplicationContext

image-20240125172346756

2、BeanFactory

image-20240125172539215

两者的运行结果是不一样的,通过 BeanFactory 实例出来的并不会将 Teacher 对象放入 Spring

ApplicationContext 和 BeanFeactory:

  1. ApplicationContext 会将 xml文件中所声明需要注册到Spring中的 Bean 一次性全部注册完成,而BeanFactory 则是在首次去获取某一个Bean 对象时才会去注册该对象
  2. ApplicationContext 比较废内存但是之后的读取会很快
  3. BeanFeactory 比较省内存但是效率较低
  4. ApplicationContext 是 BeanFeactory 的子类,ApplicationContext 还拥有独特的特性, 添加了对国际化支持、资源访问支持、以及事件传播等方面的支持

存储 Bean 对象的方式

基本的存储方式需要在 spring-config.xml 文件中去添加指定的 Bean 注册内容才行,这样就很麻烦。

类注解

配置扫描路径(必须)

首先在进行注解前需要先配置好路径,在 spring-config.xml 中添加下面的代码

<content:component-scan base-package="spring.demo"></content:component-scan>

base-package中添加的是一串路径,也就是声明这个路径下的包中的 Bean 是有可能需要存入到 Spring 中的。注意只是有可能,开始的时候并没有立即注册存放到 Spring 中。

@Controller(控制器存储)

验证用户请求的数据正确性,相当于“安保系统”

Student类

import org.springframework.stereotype.Controller;@Controller // 将当前类存储到 Spring 中
public class Student {public Student(){System.out.println("Student init");}public void print(String str){System.out.println(str);}
}

启动类

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.demo.Student;public class Start {public static void main(String[] args) {// 获取 Spring 的上下文对象ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");// 获取 Bean 对象Student student = (Student) context.getBean("student", Student.class);// 使用 Bean 对象student.print("hello world");}
}

因为使用了注解后并没有指定id属性,这时需要将id属性写为类名的小驼峰形式,这是一个“约定”。

但是也有特例:

原类名如果首字母和第二个字母都是大写的话,id属性的名称就和原类名相同

@Service(服务)

编排和调度具体执行方法,相当于“客服中心”

Student类

@Service // 将当前类存储到 Spring 中
public class Student {public Student(){System.out.println("Student init");}public void print(String str){System.out.println(str);}
}

这样也同样可以执行程序

@Repository(持久层)

和数据库进行交互,是一个“执行者”(DAO)

Student类

@Repository // 将当前类存储到 Spring 中
public class Student {public Student(){System.out.println("Student init");}public void print(String str){System.out.println(str);}
}

这样也同样可以执行程序

@Component(工具)

主要是注解工具类

Student类

@Component // 将当前类存储到 Spring 中
public class Student {public Student(){System.out.println("Student init");}public void print(String str){System.out.println(str);}
}

这样也同样可以执行程序

@Configuration(项目中的一些配置)

Student类

@Configuration // 将当前类存储到 Spring 中
public class Student {public Student(){System.out.println("Student init");}public void print(String str){System.out.println(str);}
}

这样也同样可以执行程序

关于五大类注解

  1. 如果遇到同一个包中有 同名的类 那么可以在使用注解时使用例如 @Controller(value = “XXX”) 这种方式去分别,但是建议一个包中尽量不要有同名类
  2. 五大注解的关系:事实上五大注解都是基于 Component 实现的,也就是它们都是 Component 的“子类”,是对于 Component 的扩展。那么需要分出这么多类注解的原因就是让程序员看到类注解之后,就能直接了解当前类的用途

方法注解

方法注解就是在一个有返回值的方法上加上 @Bean 注解的方式,也就是说 Spring 会将有着 @Bean 注解的方法的返回值的对象存入

需要注意:

  1. @Bean 注解需要配合五大类注解使用
  2. 使用了@Bean 注解后,默认的 Bean 对象ID属性为该具有 @Bean 注解的方法名
  3. 可以使用 @Bean(name = {“XXX”})的形式去设置这个 Bean 对象的ID属性。并且这个重命名的 name 其实是⼀个数组,一个 Bean 可以有多个名字,例如 @Bean(name = {“XXX”, “XXX”})。并且 name= 是可以去掉的,例如 @Bean({“XXX”, “XXX”})
@Component
public class UserBeans {@Bean({"user"})public User getUser(){User user = new User();user.setId(1);user.setName("张三");return user;}
}
public class Start {public static void main(String[] args) {// 获取 Spring 的上下文对象ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");// 获取 Bean 对象User user = context.getBean("user", User.class);// 使用 Bean 对象System.out.println(user.getName());}
}

image-20240126175928869

获取指定的 Bean 对象的方式

获取到上下文对象之后就可以通过调用该对象的 getBean方法去获取 Bean 对象

普通方式

首先常规的就是使用加载时设置的 id 属性去获取

Student student = (Student) context.getBean("student");

需要注意这种方式的返回值是 Object 类的,因此需要强转为 Bean 对象的类

第二种方式可以通过 Bean类的.class 加上 id 属性去获取

Student student = context.getBean("student", Student.class);

这样写法就比较优美

第三种方式可以直接通过 .class去获取,但是存在隐患

Student student = context.getBean(Student.class);

存在什么隐患呢,首先一个 Bean类是可以存放多个对象到 Spring 中的,也就是可以这样

<bean id="student" class="spring.demo.Student"></bean>
<bean id="student2" class="spring.demo.Student"></bean>

那么如果还使用第三种方式就会出现,编译器不知道具体是要获取哪一个对象,就会报错

image-20240125174238394

因此不建议使用这种方式

对象注入

在 Spring 中实现依赖注入的常见方式有以下 3 种:

  1. 属性注入(Field Injection);
  2. 构造方法注入(Constructor Injection);
  3. Setter 注入(Setter Injection)。

属性注入

属性注⼊是使⽤ @Autowired 实现的,例如下列代码

// UserService@Service
public class UserService {public void print(){System.out.println("hello");}
}
// UserController@Controller
public class UserController {@Autowiredprivate UserService userService;public void print(){userService.print();}
}
// Startpublic class Start {public static void main(String[] args) {// 获取 Spring 的上下文对象ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");// 获取 Bean 对象UserController user = context.getBean("userController", UserController.class);// 使用 Bean 对象user.print();}
}

image-20240126180319147

首先可以看到 UserService 和 UserController 这两个类都是加了类注解的,因此在程序运行后,这两个 Bean 都是会被存放到 Spring 中。因为在 UserController 类包含了一个 UserService 对象,并且加了 @Autowired 注解,所以这个 UserService 对象就不需要 new 出来,而是会自动从 Spring 中直接获取。这就是属性注入

属性注入的优点:

​ 属性注入最大的优点就是实现和使用简单,只需要给变量上添加一个 @Autowired 注解,就可以在不 new 对象的情况下直接获得注入的对象

属性注入的缺点:

  1. 无法注入一个不可变的对象,也就是final 修饰的对象
  2. 只能适应于 IoC 容器
  3. 更容易违背单一设计原则

构造方法注入

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

// UserService@Service
public class UserService {public void print(){System.out.println("hello");}
}
// UserController@Controller
public class UserController {private UserService userService;@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public void print(){userService.print();}
}
// Startpublic class Start {public static void main(String[] args) {// 获取 Spring 的上下文对象ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");// 获取 Bean 对象UserController user = context.getBean("userController", UserController.class);// 使用 Bean 对象user.print();}
}

image-20240126180319147

当该类中只有一个构造方法的时候,可以省略 @Autowired 注解,但是有多个构造方法时就需要在需要注入的方法上加上 @Autowired 注解

构造方法注入的优点:

  1. 可注入不可变对象;
  2. 注入对象不会被修改;(构造方法在对象创建时只会执行一次,因此它不存在注入对象被随时(调用)修改的情况
  3. 注入对象会被完全初始化;(注入的对象在使用之前会被完全初始化
  4. 通用性更好。(可适用于任何环境,无论是 IoC 框架还是非 IoC 框架

Setter 注入

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

// UserService@Service
public class UserService {public void print(){System.out.println("hello");}
}
// UserController@Controller
public class UserController {private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void print(){userService.print();}
}
// Startpublic class Start {public static void main(String[] args) {// 获取 Spring 的上下文对象ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");// 获取 Bean 对象UserController user = context.getBean("userController", UserController.class);// 使用 Bean 对象user.print();}
}

image-20240126180319147

Setter注入的优点:

  1. 完全符合单一职责的设计原则,一个set方法只针对一个对象

Setter注入的缺点:

  1. 不能注入不可变对象;(final 修饰的对象)
  2. 注入的对象可被修改。(因为set方法的缘故,因此对象可以被随时随地修改)

@Resource:另⼀种注入关键字

@Controller
public class UserController {@Resourceprivate UserService userService;public void print(){userService.print();}
}

@Autowired 和 @Resource 的区别:

  1. @Autowired 来自于 Spring,而 @Resource 来自于 JDK 的注解
  2. 相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean,可以使用@Resource(name=“XXX”) 指定获取。而 @Autowired 需要配合 @Qualifier(value = “XXX”)
  3. @Resource 只能用于 Setter 注入和属性注入,不能用于构造函数注入

总结

属性注入的写法最简单,所以日常项目中使用的频率最高,但它的通用性不好;

而 Spring 官方推荐的是构造方法注入,它可以注入不可变对象,其通用性也更好。

如果是注入可变对象,那么可以考虑使用 Setter 注入

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

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

相关文章

css不规则的文本环绕

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>不规则的文本环绕</title><style>.b…

flyway使用配置参数和注意事项介绍

文章目录 业务场景参数介绍initSqlsbaselineOnMigratebaselineVersiontargetvalidateOnMigrate SQL注意事项 业务场景 对于生产环境&#xff0c;随着项目版本迭代&#xff0c;数据库结构也会变动。如果一个项目在多个地方实施部署&#xff0c;且版本不一致&#xff0c;就需要一…

CSS之粘性定位

让我为大家介绍一下粘性定位吧&#xff01; 大家应该都了解过绝对定位&#xff0c;它是相对于父级定位 那么粘性定位相对于谁呢&#xff1f; 它相对于overflow:hidden; 如果没找到就会跟fixed固定定位一样&#xff0c;相对于视口 <!DOCTYPE html> <html lang"en…

C++ 利用容器适配器,仿函数实现栈,队列,优先级队列(堆),反向迭代器,deque的介绍与底层

C 利用容器适配器,仿函数实现栈,队列,优先级队列【堆】,反向迭代器,deque的介绍与底层 一.容器适配器的介绍二.利用容器适配器实现栈和队列1.stack2.queue 三.仿函数介绍1.什么是仿函数2.仿函数的使用3.函数指针的使用1.函数指针的用处2.利用函数指针完成回调3.利用仿函数完成回…

免 费 小程序商城搭建之b2b2c o2o 多商家入驻商城 直播带货商城 电子商务b2b2c o2o 多商家入驻商城 直播带货商城 电子商务

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

cg插画设计行业怎么样,如何学习插画设计

插画设计行业是一个充满创意和艺术性的行业&#xff0c;随着数字化时代的不断发展&#xff0c;cg插画的应用范围越来越广泛&#xff0c;市场需求也在逐年增长。以下是一些关于acg插画设计行业的现状和发展趋势&#xff1a; 市场需求不断增长&#xff1a;随着广告、媒体、影视、…

HCIA学习作业二

要求&#xff1a;基于192.168.1.0/24进行合理划分&#xff0c;要求全网通 [AR3]display ip interface brief [AR3]display ip routing-table [AR1]display ip interface brief [AR1]display ip routing-table [AR2]display ip interface brief [AR2]display ip routing-tab…

Hadoop3.x源码解析

文章目录 一、RPC通信原理解析1、概要2、代码demo 二、NameNode启动源码解析1、概述2、启动9870端口服务3、加载镜像文件和编辑日志4、初始化NN的RPC服务端5、NN启动资源检查6、NN对心跳超时判断7、安全模式 三、DataNode启动源码解析1、概述2、初始化DataXceiverServer3、初始…

《WebKit 技术内幕》学习之十一(2):多媒体

2 视频 2.1 HTML5视频 在HTML5规范定义中&#xff0c;Web开发者可以使用“video”元素来播放视频资源。视频中有个重要的问题就是视频编码格式&#xff0c;对此&#xff0c;目前标准中包含了三种编码格式&#xff0c;它们分别是Ogg、MPEG4和WebM。其中Ogg是由Xiph.org组织开…

【模拟算法系列】详解5道题

本文讲解模拟算法系列的5道经典题&#xff0c;在讲解题目的同时提供AC代码&#xff0c;点击题目即可打开对应OJ链接 目录 模拟算法的介绍 1、替换所有的问号 2、提莫攻击 3、 Z 字形变换 4、外观数列 5、数青蛙 模拟算法的介绍 题目中明确告诉你要干什么&#xff0c;思路…

ChatGPT 和文心一言 | 两大AI助手哪个更胜一筹

欢迎来到英杰社区&#xff1a; https://bbs.csdn.net/topics/617804998 欢迎来到阿Q社区&#xff1a; https://bbs.csdn.net/topics/617897397 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff…

Web开发4:单元测试

在Web开发中&#xff0c;单元测试是一种重要的开发实践&#xff0c;它可以帮助我们确保代码的质量和可靠性。通过编写和运行单元测试&#xff0c;我们可以验证代码的正确性&#xff0c;减少错误和缺陷&#xff0c;并提高代码的可维护性。本文将介绍单元测试的概念、好处以及如何…

python写一个彩票中奖小游戏修订版本

先说规则&#xff1a; print("下面介绍双色球颜色规则:")print("一等奖,投注号码与当期开奖号码全部相同&#xff08;顺序不限&#xff0c;下同&#xff09;&#xff0c;即中奖")print("二等奖:投注号码与当期开奖号码中的6个红色球号码相同,即中奖&q…

鸿蒙开发实战-手写文心一言AI对话APP

运行环境 &#xff08;后面附有API9版本&#xff0c;可修改后在HarmonyOS4设备上运行&#xff09; DAYU200:4.0.10.16 SDK&#xff1a;4.0.10.15 IDE&#xff1a;4.0.600 在DAYU200:4.0.10.16上运行 一、创建应用 1.点击File->new File->Create Progect 2.选择模版…

分享7种SQL的进阶用法

分享7种SQL的进阶用法 前言 还只会使用SQL进行简单的insert、update、detele吗&#xff1f;本文给大家带来7种SQL的进阶用法&#xff0c;让大家在平常工作中使用SQL简化复杂的代码逻辑。 1.自定义排序&#xff08;ORDER BY FIELD&#xff09; 在MySQL中ORDER BY排序除了可以…

temu跨境电商怎么样?做temu蓝海项目有哪些优势?

在全球电商市场激烈的竞争中&#xff0c;Temu跨境电商平台以其独特的优势和策略&#xff0c;逐渐崭露头角。对于许多想要拓展海外市场的商家来说&#xff0c;Temu的蓝海项目提供了一个充满机遇的新平台。本文将深入探讨Temu跨境电商的优势以及在蓝海市场中的发展前景。 全球化市…

编程笔记 html5cssjs 056 CSS不透明度

编程笔记 html5&css&js 056 CSS不透明度 一、CSS 不透明度 / 透明度二、使用 RGBA 的透明度三、透明盒中的文本小结 不透明度/透明度。利用透明度可以提高页面的层次效果。 一、CSS 不透明度 / 透明度 opacity 属性指定元素的不透明度/透明度。 opacity 属性通常与 :h…

仅使用 Python 创建的 Web 应用程序(前端版本)第08章_商品详细

在本章中,我们将实现一个产品详细信息页面。 完成后的图像如下。 Model、MockDB、Service都是在产品列表页实现的,所以创建步骤如下。 No分类内容1Page定义PageId并创建继承自BasePage的页面类2Application将页面 ID 和页面类对添加到 MultiPageApp 的页面中Page:定义PageI…

VsCode提高生产力的插件推荐-持续更新中

别名路径跳转 自定义配置// 文件名别名跳转 "alias-skip.mappings": { "~/": "/src", "views": "/src/views", "assets": "/src/assets", "network": "/src/network", "comm…

Android App开发基础(2)—— App的工程结构

本专栏文章 上一篇 Android开发修炼之路——&#xff08;一&#xff09;Android App开发基础-1 2 App的工程结构 本节介绍App工程的基本结构及其常用配置&#xff0c;首先描述项目和模块的区别&#xff0c;以及工程内部各目录与配置文件的用途说明&#xff1b;其次阐述两种级别…