【JavaEE】Spring中存储和获取Bean(使用注解)

news2024/11/19 6:20:31

目录

存储Bean

配置文件中设置扫描路径

使用注解存储Bean

五大类注解存储Bean

五大类注解之间的关系

为什么要有五大类注解

@Bean方法注解存储方法返回值

注入Bean

属性注入

Setter方法注入

构造方法注入

@Resource注解


存储Bean

上篇文章的存储Bean是在Spring的配置文件下通过bean标签来把Bean存储到Spring容器中,其中需要设置标签属性id 和 name,还是比较麻烦的,接下来介绍一种更为简单也最为常用的方法来存储Bean。


配置文件中设置扫描路径

首先还是要在配置文佳中设置一下。这里需要设置的是要存储的Bean对象的路径。

比如我想把test包下面的这几个类存储到Spring中,此时就需要在配置文件中写一下扫描的路径。

<?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="com.test"></content:component-scan>
</beans>

有关扫描路径需要注意的点:

1. 只有在扫描路径下的类,加了注解的才能被存储到Spring中

2. 扫描路径是可以提升效率的,不至于在整个项目中找要存储的类 


使用注解存储Bean

上述工作完成后就可以通过注解存储Bean。注解分为两大类,一类是类注解,一类是方法注解

五大类注解存储Bean

这五个注解分别是  @Controller  @Component  @Configuration  @Repository  @Service

使用演示:

package com.test;

import org.springframework.stereotype.Controller;

@Controller
public class UserController {

    public void doController() {
        System.out.println("doUserController");
    }
}
import com.test.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 获取到Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        // 测试Controller
        UserController userController = context.getBean("userController", UserController.class);

        userController.doController();

    }
}

上面获取到Bean时,第一个参数直接就是把类的第一个字母小写了(大驼峰变成小驼峰)

这只是其中的一个对Bean名字的处理方式,接下来来看另外一种。

package com.test;

import org.springframework.stereotype.Controller;

// 当类的第一、二的字母都是大写的情况
@Controller
public class UController {
    public void doController() {
        System.out.println("doUController");
    }
}

 

 

为什么会有两个处理情况,通过查看源码可知。

其他四个注解也都是相同的命名规则,也是相同的用法,就不一一演示了。

小结:

1. 使用注解来存储的前提是配置文件中已经设置好了路径

2. 只有在配置文件路径下加了注解才能把Bean存储到Spring中,二者同时成立才可以

3. 取出Spring的bean时,有两种方法:

    a. 如果类名的前两个字母并非都为大写字母,则在取的时候变成首字母小写

    b. 如果前两个字母都是大写,在取的时候使用原类名即可

五大类注解之间的关系

可以看出,@Service  @Repository  @Controller @Configuration  这四个注解都是相当于 拓展了 @Component 这个注解,所以它们的使用方式基本都一致。

为什么要有五大类注解

当程序员看到五大类注解后,就会知道这个类具体是干什么的。


@Bean方法注解存储方法返回值

1. 在配置文件中把把方法所在的类的路径配置好

2. 在方法上加@Bean注解,同时在方法所在的类上面加上五大类注解

package com.test.component;

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

@Component
public class UserBeans {
    @Bean
    public User getUserById() {
        User user = new User();
        user.setUserId(1);
        user.setUserName("张三");
        user.setUserAge(20);
        return user;
    }
}

import com.test.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        // 获取到Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        // 测试Bean注解
        User user = context.getBean("getUserById", User.class);
        System.out.println(user.getUserName());
    }
}

如果不加类注解:

上面获取到方法返回的Bean是通过方法名,这和之前五大注解的获取Bean又是另外一套规则。但是通过方法名获取通常是不使用的,我们可以在@Bean注解后重写命名,通过新名字来获取,同时使用原方法名就获取不到Bean了

小结: 

1. @Bean方法注解必须在五大类注解下使用(被五大类修饰的类)

2. 该注解如果没用重命名,那么直接使用方法名就可以获取到Bean

3. 如果重命名后,只能使用新的名字,方法名无法继续使用

4. 新名字可以有很多,使用数组保存

5. 该注解是把方法的返回值存入到Spring中,如果方法没有返回值,就不能使用该注解


注入Bean

把对象从Spring中取出来到某个类中使用。

属性注入

package com.test.service;

// 测试从Spring中拿user对象注入UserController类中

import com.test.entity.User;
import org.springframework.stereotype.Service;

@Service()
public class UserService {
    // 实际上要连接数据库通过id查询到对象
    public User getUser(Integer id) {
        User user = new User();
        user.setUserName("张三");
        user.setUserId(123);
        user.setUserAge(20);
        return user;
    }

}
package com.test.controller;

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

@Controller
public class UserController {

    // 通过属性注入
    @Autowired
    private UserService userService;
    public User getUserByAttribute(Integer id) {
        return userService.getUser(id);
    }
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        // 获取到Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取到Bean对象
        UserController userController = context.getBean("userController", UserController.class);
        System.out.println(userController.getUserByAttribute(123).toString());
    }
}

优点:

  1. 高效便捷:使用属性注入时,无需编写额外的构造方法或Setter方法,可以大大降低代码量并提高开发效率。

  2. 可读性强,很容易从代码层面看出有哪些Bean被注入了

 缺点:

  1. 无法注入final修饰的修饰的对象。因为final修饰的对象只能被赋值一次,而在Spring容器中,属性注入是通过反射实现的,它需要通过反射来修改对象的属性值,但是final修饰的对象属性是不可变的,不能被修改,因此无法进行属性注入。
  2. 对象有可能会被修改。因为注入的Bean可以使用很多次。
  3. 只能在IoC容器下使用,其他的不行
  4. 不能保证对象完全初始化  原因有以下两点:

            a:Bean依赖关系不完整,当某个Bean依赖的其他Bean还未完全初始化或者还未注                   入时就会出现这种情况。

            b:Bean的声明周期管理不当(下篇文章讲)

Setter方法注入

package com.test.controller;

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

@Controller
public class UserController {

    private UserService userService;

    // 通过Setter方法注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    public User getUserBySetter(Integer id) {
        return userService.getUser(id);
    }
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        // 获取到Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取到Bean对象
        UserController userController = context.getBean("userController", UserController.class);
        System.out.println(userController.getUserBySetter(123).toString());
    }
}

优点:

  1. 灵活性高,相较于构造方法注入,它可以在任何时候注入
  2.  符合单一设计原则(每个方法只传一个对象)

缺点:

  1. 不能注入final修饰的对象。只用Java8及以下的不可以,原因同上。但是Java9及以后的可以,因为引入了Variable Handles的机制,可以通过反射来修改final字段的值。
  2. 对象可能会被修改

构造方法注入

package com.test.controller;

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

@Controller
public class UserController {

    private UserService userService;

    // 通过构造方法注入
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    public User getUserByConstructor (Integer id) {
        return userService.getUser(id);
    }
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        // 获取到Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 获取到Bean对象
        UserController userController = context.getBean("userController", UserController.class);
        System.out.println(userController.getUserByConstructor(123).toString());
    }
}

特点:

当只有一个构造方法的时候,@AutoWired这个注解可以省略

因为这是官方推荐使用的方法

优点:

  1. 可以注入一个被final修饰的对象。因为除了一开始就赋值,还可以在构造方法中对final修饰的属性赋值。
  2. 被注入的对象不可变。因为构造方法只能在最开始执行一次。
  3. 可以保证被注入的对象完全初始化
  4. 通用性更好,可以在IoC之外的地方使用。

@Resource注解

这是JDK提供的注入Bean的注解,和@AutoWired有以下的区别。

  • @Resource是JDK提供的,@AutoWired是Spring提供的
  • @Resource只能不能使用构造方法注入,@AutoWired都可以
  • @Resource可以设置很多参数,而@AutoWired只能设置一个

 有什么错误评论区指出。希望可以帮到你。

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

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

相关文章

16.网络爬虫—字体反爬(实战演示)

网络爬虫—字体反爬一字体反爬原理二字体反爬模块FonttoolsTTF文件三FontCreator 14.0.0.2790FontCreatorPortable下载与安装四实战演示五后记前言&#xff1a; &#x1f3d8;️&#x1f3d8;️个人简介&#xff1a;以山河作礼。 &#x1f396;️&#x1f396;️:Python领域新星…

一天吃透MySQL面试八股文

什么是MySQL MySQL是一个关系型数据库&#xff0c;它采用表的形式来存储数据。你可以理解成是Excel表格&#xff0c;既然是表的形式存储数据&#xff0c;就有表结构&#xff08;行和列&#xff09;。行代表每一行数据&#xff0c;列代表该行中的每个值。列上的值是有数据类型的…

python调用matlab源码函数

Background 关于在python中调用matlab函数&#xff0c;我之前已经写过两篇文章了&#xff0c;非常详细&#xff0c;且之前的方法可以不用安装matlab程序&#xff0c;只需要按照mcr运行环境就行了。具体可以参考&#xff1a;【java和python调用matlab程序详细记录】【Python 高效…

一文解析为什么进程地址空间中包括操作系统?

今天聊聊进程地址空间这点小事。说到进程的地址空间&#xff0c;大家可能都知道这样一张图&#xff1a; 这张图就是Linux程序运行起来后所谓的进程地址空间&#xff0c;这里包括我们熟悉的代码区、数据区、以及堆区和栈区&#xff0c;今天我们不讲解这些区域&#xff0c;而是重…

elementui的el-message重复点击,提示会一直叠加

1.问题&#xff1a; elementui的el-message连续点击按钮会出现一排提示&#xff0c;注意体验很不友好&#xff0c;而且也不好看 如下&#xff1a; 这种问题如何解决呢 ? 2.参考api elementui的官网有这个api&#xff0c;也就是说通过close这个方法可以解决 3.附上代码&a…

设计模式之美-结构型模式-装饰器模式

装饰器模式主要解决继承关系过于复杂的问题&#xff0c;通过组合来替代继承。指在不改变现有对象结构的情况下&#xff0c;动态地给该对象增加一些职责&#xff08;即增加其额外功能&#xff09;的模式&#xff0c;装饰器模式提供了比继承更有弹性的替代方案将功能附加到对象上…

4月20日专家谈:内网突遭攻击,安全人员一招有效处理

随着网络威胁的愈加频繁&#xff0c;企业面临的安全问题也越来越多&#xff0c;传统的安全能力在面对日益增长的安全问题时显得捉襟见肘。 SOAR借助安全编排和自动化技术&#xff0c;将人工操作和技术集成在一起&#xff0c;自动化完成安全处置&#xff0c;帮助企业更快地响应…

JavaScript【九】JavaScript BOM(浏览器对象模型)

文章目录&#x1f31f;前言&#x1f31f; Bom&#xff08;浏览器对象模型&#xff09;&#x1f31f;window对象&#xff1a;&#x1f31f;属性&#xff1a;&#x1f31f; 方法&#xff1a;&#x1f31f; 获取元素:&#x1f31f; 添加点击事件&#xff1a;&#x1f31f; 获取表单…

大数据Flink进阶(二十):Flink细粒度资源管理

文章目录 Flink细粒度资源管理 一、细粒度资源管理介绍 二、细粒度资源适用场景

关于合金电阻

合金电阻是一种具有高精度、高稳定性和高温度特性的电阻器件&#xff0c;广泛应用于各种电子设备中。选型合适的合金电阻并进行合理的设计&#xff0c;可以有效地提高电路的性能和可靠性。本文将从合金电阻的基本原理、选型方法及设计要点等方面进行详细介绍。 一、合金电阻的基…

简单认识下with和上下文管理器

with 对于系统资源如文件、数据库连接、socket&#xff0c;应用程序打开这些资源并执行完业务逻辑之后&#xff0c;必须关闭&#xff08;断开&#xff09;该资源。系统允许打开的最大文件数量是有限的&#xff0c;如果我们打开文件后没有及时关闭&#xff0c;极端情况下会出现…

21天学会C++:Day2----命名空间的那些事儿

CSDN的uu们&#xff0c;大家好。这里是C入门的第二讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 为什么要有命名空间 2. 命名空间的定义 3. 访问命名空间域中成员的三种方…

基于Java+SpringBoot+vue的人职匹配推荐系统设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;300套&#xff09; 目录 一、效果演示 二、…

virtualbox如何配网

配网搞了一天&#xff01;&#xff01;&#xff01; 百度到的所有教程都是垃圾&#xff01;&#xff01; 就没有一个写全的&#xff01;&#xff01;写明白怎么配的&#xff01;&#xff01;&#xff01; 我自己来&#xff01;&#xff01;&#xff01;不会配的看我&#xf…

浅析 Queue 和 Deque

终于开始了 LeetCode 的练习&#xff0c;看到 102. 二叉树的层序遍历 有种解法利用到了队列&#xff0c;想着挨个看看基础队列中的方法&#xff0c;便有了这篇文章。 基于 Java 对 Queue 以及 Deque&#xff08;double ended queue&#xff09; 实现进行学习介绍&#xff0c;JD…

Vue之代码传送(teleport)

代码传送是啥 在Vue中&#xff0c;代码传送就是将某部分的代码从Vue的template标签下传送到指定的地方&#xff0c;这个地方通常是body标签下。在使用Vue编写界面时&#xff0c;我们都是在html的Body中写一个div&#xff0c;然后指定一个id&#xff0c;然后在Vue的实例中的tem…

2023春招offer收割机,阿里架构师耗时半月写的《Java面试手册》

程序猿在世人眼里已经成为高薪、为人忠诚的代名词。 然而&#xff0c;小编要说的是&#xff0c;不是所有的程序员工资都是一样的。 世人所不知的是同为程序猿&#xff0c;薪资的差别还是很大的。 众所周知&#xff0c;目前互联网行业是众多行业中薪资待遇最好的&#xff0c;包…

Java语法理论和面经杂疑篇《九. 网络编程》

目录 1. 网络编程概述 1.1 软件架构 1.2 网络基础 2. 网络通信要素 2.1 如何实现网络中的主机互相通信 2.2 通信要素一&#xff1a;IP地址和域名 2.2.1 IP地址 2.2.2 域名 2.3 通信要素二&#xff1a;端口号 2.4 通信要素三&#xff1a;网络通信协议 2. 谈传输层协议…

时间序列教程 四、自回归和移动平均模型

一、本节目标 了解自相关函数(ACF)。 了解部分自相关函数(PACF)。 了解自回归和移动平均模型是如何工作的。 使用Python来拟合自相关模型。 二、ACF和PACF 1、自相关函数(ACF) 测量信号与自身延迟数据的相关性。 它用于发现信号中的重复模式,例如周期性信号的存…

Spring相关概念

Spring家族 官网&#xff1a;Spring | Home&#xff0c;从官网我们可以大概了解到&#xff1a; Spring能做什么:用以开发web、微服务以及分布式系统等,光这三块就已经占了JavaEE开发 的九成多。Spring并不是单一的一个技术&#xff0c;而是一个大家族&#xff0c;可以从官网的…