【SpringⅡ】简单高效地存储读取对象

目录

🧥1 配置扫描路径

🧤2 类注解实现 Bean 对象的存储

🩱2.1 五大类注解的使用

🎁2.2 五大类注解之间的关系

🎏2.3 Java 项目的标准分层

🎃3 方法注解实现 Bean 对象的存储

🎈3.1 Bean 注解必须配合五大类注解一起使用

✨3.2 重命名 @Bean 的几种方式

🎁4 依赖注入


在上一篇的文章的最后(Spring 的创建与使用),我介绍了往 Spring 里存储 Bean 的方式:在 spring_config 中添加一行 bean 注册内容如下:

采用这种写法的话,每一个类都必须在 spring-config 里写上这么一行。然而有另一种更加便捷的方式,可以在 spring-config 里只添加一行,便可以存储且获取同一路径下的所有对象。

1 配置扫描路径

与上述写法不同的是,不再使用 bean 标签了,而是换成了以下形式:

<?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.java.demo"></content:component-scan>
</beans>

配置 bean 的扫描路径意味着,只有当前目录下的类才会扫描是否添加了注解。如果添加了注解,就将这些添加了注解的类存放到 IoC 容器中。

下面介绍两种更加简单存储 Bean 对象的方式

2 类注解实现 Bean 对象的存储

五大类注解:

1. @Controller【控制器】校验参数的合法性(安检系统)

2. @Service【服务】业务组装(客服中心)

3. @Repository【数据持久层】实际业务处理(实际办理的业务)

4. @Component【组件】工具类层(基础的工具)

5. @Configuration【配置层】配置

2.1 五大类注解的使用

package com.java.demo;

import org.springframework.stereotype.Controller;

@Controller
public class User {
    public void sayHi(){
        System.out.println("Hi User~");
    }
}
package com.java.demo;

import org.springframework.stereotype.Service;

@Service
public class Student {
    public void sayHi(){
        System.out.println("Hi! Student!");
    }
}
package com.java.demo;

import org.springframework.stereotype.Repository;

@Repository
public class ABCdefH {
    public void sayHi(){
        System.out.println("Hi! ABCdefH!");
    }
}
package com.java.demo;

import org.springframework.stereotype.Component;

@Component
public class TEacher {
    public void sayHi(){
        System.out.println("Hi! TEacher!");
    }
}
package com.java.demo;

import org.springframework.context.annotation.Configuration;

@Configuration
public class Hello {
    public void sayHi(){
        System.out.println("Hello! !");
    }
}
import com.java.demo.*;
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");
        User user = context.getBean("user", User.class);
        user.sayHi();
        TEacher teacher = context.getBean("TEacher", TEacher.class);
        teacher.sayHi();
        ABCdefH abcdefh = context.getBean("ABCdefH", ABCdefH.class);
        abcdefh.sayHi();
        Hello hello = context.getBean("hello", Hello.class);
        hello.sayHi();
        Student student = context.getBean("student", Student.class);
        student.sayHi();
    }
}

输出:

Hi User~
Hi! TEacher!
Hi! ABCdefH!
Hello! !
Hi! Student!

类注解存储 Bean 命名时,有一个默认的命名规则:

如果首字母大写,第二个字母小写,那么 Bean 的名称就是类名小写:如上的 User、Student 以及 Hello 类。但如果不满足上述情况,那么 Bean 的名称就为原类名,如上述的 TEacher 以及 ABCdefH 类。

来看一下 Bean 生成名称的源代码:

public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                        Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char[] chars = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }

可以看到,五类注解方法功能上都是一样的,但为什么要分出五类来呢?为了后续代码的分层管理。

2.2 五大类注解之间的关系

依次点开五大类注解的源代码:

 

可以看出其他四类都是基于 Component 的,所以以后实在不知道用哪个注解比较好的话,就使用 Component 吧~

2.3 Java 项目的标准分层

 

3 方法注解实现 Bean 对象的存储

3.1 Bean 注解必须配合五大类注解一起使用

一起来看怎么样使用吧!

首先给定一个文章的实体类来:

package com.java.demo;

import java.time.LocalDateTime;

/*
* 普通的文章实体类
 */
public class ArticlesInfo {
    private int id;
    private String title;
    private String content;
    private LocalDateTime time;

    @Override
    public String toString() {
        return "ArticlesInfo{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", time=" + time +
                '}';
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setTime(LocalDateTime time) {
        this.time = time;
    }

    public int getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public String getContent() {
        return content;
    }

    public LocalDateTime getTime() {
        return time;
    }
}

创建文章:

package com.java.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

import java.time.LocalDateTime;

@Controller
public class Articles {

    @Bean
    public ArticlesInfo articlesInfo(){
        // 伪代码
        ArticlesInfo articlesInfo = new ArticlesInfo();
        articlesInfo.setId(1);
        articlesInfo.setTitle("Know yourself");
        articlesInfo.setContent("Keep Learning ~");
        articlesInfo.setTime(LocalDateTime.now());
        sayHi();
        return articlesInfo;
    }
    
    public void sayHi(){
        System.out.println("Hi~~~");
    }
}
import com.java.demo.Articles;
import com.java.demo.ArticlesInfo;
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");
        ArticlesInfo articles = context.getBean("articlesInfo", ArticlesInfo.class);
        System.out.println(articles.toString());
    }
}

输出:

ArticlesInfo{id=1, title='Know yourself', content='Keep Learning ~', time=2023-07-19T15:29:30.731}

需要注意的是,本身的类也会被存储到 Spring 中:

        Articles articles1 = context.getBean("articles", Articles.class);
        articles1.articlesInfo();

输出:

Hi~~~

可以发现,使用 Bean 对方法进行注解时,@Bean 的默认命名是方法名。

3.2 重命名 @Bean 的几种方式

@Bean("aaa")
@Bean(name = "bbb")
@Bean(value = "ccc")

@Bean 支持指定多个名称

@Bean(value = {"aaa", "bbb"})

需要注意的是,当 @Bean 重命名之后,默认使用方法名获取 Bean 对象的方式就不能用了。

另一个要注意的是,如果多个 Bean 使用相同的名称,程序执行不会报错。除了第一次使用某一 Bean 名称的方法之外(根据加载顺序),后面使用相同 Bean 名称的方法,都不会被存放到容器当中,会被自动忽略。

4 依赖注入

依赖注入与依赖查找的对比

· 依赖查找依靠 Bean 名称来进行查找

· @Autowired 依赖注入流程:首先根据 getType(从容器中)获取对象,如果只获取一个,    那么直接将此对象注入到当前属性上;如果获取多个对象,就会使用 getName(根据名        称)来进行匹配。

 

package com.java.demo;

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
    public int add(){
        System.out.println("Do UserRepository add method");
        return 1;
    }
}

 

package com.java.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // Spring 2.0 使用属性注入的方式
    @Autowired  // DI (依赖注入)
    private UserRepository userRepository;

    public int add(){
        System.out.println("Do UserService add method.");

        // 1.传统写法
//        UserRepository userRepository = new UserRepository();
//        return userRepository.add();

        // 2. Spring 1.0
//        ApplicationContext context =
//                new ClassPathXmlApplicationContext("spring-config.xml");
//        UserRepository userRepository = context.getBean("userRepository", UserRepository.class);
//        return userRepository.add();

        //

        // 3. Spring 2.0
        return userRepository.add();


    }
}

对着需要测试的类,右击,点击 Generate,再点 Test 生成一个测试类。通过测试类来进行测试。

package com.java.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import static org.junit.jupiter.api.Assertions.*;

class UserServiceTest {

    @org.junit.jupiter.api.Test
    void add() {
        ApplicationContext context = 
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
}

 输出:

Do UserService add method.
Do UserRepository add method

可以看到使用属性注入,代码更加简洁了。

如果是下面这种情况,会出现什么问题呢?

package com.java.demo;

public class User {
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.java.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class Users {
    @Bean("user1")
    public User user1(){
        User user = new User();
        user.setName("马冬梅");
        return user;
    }

    @Bean("user2")
    public User user2(){
        User user = new User();
        user.setName("王五");
        return user;
    }
}

同类型的 Bean 放入了同一个 Spring 当中,如果是 属性注入,该如何获取呢?

采用下面两种方式:

1. 将属性的名字与 Bean 的名字一一对应,是 user1 还是 user2,而不是写成的 user。


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService2 {
    // 属性注入
    @Autowired
    private User user1;

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

2. @Autowired 配合 @Qualifier 一起使用

package com.java.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@Service
public class UserService2 {
    // 属性注入
    @Autowired
    @Qualifier("user1")
    private User user;

    public void sayHi(){
        System.out.println(user.toString());
    }
}
package com.java.demo;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import static org.junit.jupiter.api.Assertions.*;

class UserService2Test {

    @Test
    void sayHi() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserService2 user = context.getBean("userService2",UserService2.class);
        user.sayHi();
    }
}

 


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【论文阅读】一些多轮对话文章的体会 ACL 2023

前言 本文是对昨天看到的ACL 2023三篇多轮对话文章的分享这三个工作都是根据一些额外属性控制输出的工作&#xff0c;且评估的方面比较相似&#xff0c;可以借鉴 方法 这几篇文章都不是做general任务的&#xff0c;倾向于通过一些额外信息&#xff0c;来做specific任务 【1】…

【ceph】存储池pg个数如何设置

存储池pg个数如何设置 参考官方文档说明&#xff1a;https://old.ceph.com/pgcalc/参数说明TargePGs per OSD&#xff1a;每个OSD的pg数OSD#存储池包含osd个数%Data存储池写入数据占总OSD容量百分比Size存储池冗余数

vue2watch监听遇到的问题

1 vue 父组件里引入子组件 显示与隐藏是v-if控制时 父传入子的参数通过watch 监听请求接口时 watch 时而监听不到 请求接口的参数就不对 如图 父组件这么引入子组件v-show 和v-if 是有区别的 2 子组件通过watch 监听后 清空页面要展示的列表数据 重新从第一页加载数据&#x…

微服务sleuth+zipkin——链路追踪

一、链路追踪&#x1f349; 1.什么是链路追踪&#xff1f;&#x1f95d; 在大型系统的微服务化构建中&#xff0c;一个系统被拆分成了许多模块。这些模块负责不同的功能&#xff0c;组合成系统&#xff0c;最终可以提供丰富的功能。在这种架构中&#xff0c;一次请求往往需要…

简单了解UML类图

前言 大话设计中&#xff0c;多次使用UML类图来表示&#xff0c;并也给了基本的介绍&#xff0c;这里从书中选出UML图和代码做成笔记&#xff0c;以方便查找。 1、类 注意前面的符号&#xff1a; &#xff1a;public -&#xff1a;private #&#xff1a;protected 抽象类&…

在阿里云linux上安装MySql数据库

我们先远程连接服务器 然后输入 sudo yum update重新运行一下 然后 sudo yum install mysql-server安装 mysql 服务 其中有两次 y n 选择 都选y就好了 然后 运行 sudo service mysqld start启动MySql 然后 我们查看一下MySql sudo service mysqld status

Debian 12上如何关闭nobody共享文件夹,一个能让INSCODE AI 创作助手不知所措的小问题

这个问题之前在Debian 10和11上都没有遇到过&#xff0c;换上Debian 12后Samba的设置就出现了状况&#xff0c;装上Samba后什么都没有设置就在局域网可以看到&#xff1a; 根据之前的经验在/etc/samba/smb.conf里查了很久也没有看出所以然来&#xff0c;后来又问了INSCODE AI…

[洛谷]P8662 [蓝桥杯 2018 省 AB] 全球变暖(dfs)

读题不规范&#xff0c;做题两年半&#xff01; 注意&#xff1a;被海水淹没后的陆地应用另一个字符表示&#xff0c;而不是把它变为海洋&#xff0c;这个点可以便利&#xff0c;但不能被当作起点&#xff0c;不然就只有 36 分。 ACocde: #include<bits/stdc.h> using…

静态数码管显示

学习芯片&#xff1a; EP4CE6F17C8 本次学习使用的为共阴极数码管&#xff0c;即用低电平点亮数码管&#xff0c;同样可知&#xff0c;共阳极数码管的阳极连在一起&#xff0c;即用高电平点亮数码管。 八段数码管示意图&#xff1a; a,b,c,d,e,f,g,dg表示八段数码管时&#…

微服务sleuth+zipkin---链路追踪+nacos配置中心

目录 1.分布式链路追踪 1.1.链路追踪Sleuth介绍 1.2.如何完成sleuth 1.3.zipkin服务器 2.配置中心 2.1.常见配置中心组件 2.2.微服务集群共享一个配置文件 2.2.1实时刷新--配置中心数据 2.2.2.手动写一个实时刷新的配置类 ----刷新配置文件 2.3.多个微服务公用一个配…

FPGA——点亮led灯

文章目录 一、实验环境二、实验任务三、实验过程3.1 编写verliog程序3.2 引脚配置 四、仿真4.1 仿真代码4.2仿真结果 五、实验结果六、总结 一、实验环境 quartus18.1 vscode Cyclone IV开发板 二、实验任务 每间隔1S实现led灯的亮灭&#xff0c;实现流水灯的效果。 三、实…

测试开发面试你需要知道的

面试前的准备&#xff1a; 1.简历优化 选择一个比较简洁明了的模板&#xff0c;简历中突出自己的技能和项目经验&#xff0c;项目经历最好按照时间倒叙阐述&#xff0c;描述清自己在项目中承担的职责&#xff0c;在这个职责中做的一些过程改进&#xff0c;效率提升的内容&…

Redis的缓存问题

说起Redis的缓存&#xff0c;我们知道前端发出的请求到后端&#xff0c;后端先从Redis中查询&#xff0c;如果查询到了则直接返回&#xff0c;如果Redis中未查询到&#xff0c;就去数据库中查询&#xff0c;如果数据库中存在&#xff0c;则返回结果并且更新到Redis缓存当中&…

Linux云服务器,docker compose文件部署多个jar,docker部署多模块boot项目

前提条件 Linux服务器 服务器已经安装docker docker已经安装jdk镜像 docker已经安装mysql镜像 将要部署的项目的jar包打包好&#xff0c;项目是多模块springboot项目 部署过程 项目是3个模块的Spring boot项目&#xff0c;打出来3个jar&#xff0c;将这些jar包拷贝到…

无线电音频-BPA600蓝牙协议分析仪名词解析

1 介绍 2 Baseband基带分析 (1)Delta 是什么含义? "Delta" 有多个含义,取决于上下文。以下是常见的几种含义: 希腊字母:Delta&#x

Halcon机器视觉-15种常用缺陷检测实例

一、Halcon 15种常用缺陷检测实例分享 缺陷检测是一种通过计算机视觉技术来检测产品制造过程中的缺陷的方法。该技术可以检测出产品表面的缺陷&#xff0c;如裂纹、凹陷、划痕、气泡等&#xff0c;并且可以实时监测和诊断制造过程中的问题。在制造业中&#xff0c;机器视觉缺陷…

提升内功之模拟实现库函数strlen/strncpy/strcmp/strcat/strstr/memcpy/memmove

strlenstrncpystrcmpstrcatstrstrmemcpymemmove strlen strlen函数的作用就是求字符串的首元素开始往后计算字符串的长度&#xff0c;直到’\0‘&#xff0c;但不会把\0的长度计算进去 #include<stdio.h>size_t Strlen(const char* src) {size_t count 0;while (*src ! …

Docker 安装 MongoDB开启认证,创建只读用户权限。

创建带认证的mongdb容器 docker run -itd --name mongo -p 27017:27017 mongo --auth --auth 就是开启mongodb权限认证。如果不加 --auth 则是无权限认证&#xff0c;连接成功后任何用户都可以对数据库进行读写操作。 进入容器并创建用户 docker run -itd --name mongo -p 27…

【gis插件】arcgis插件界址点编号工具、C#实现思路(附插件下载链接)

数据&#xff1a;界址点图层、宗地图层 要求&#xff1a;找出宗地对应的所有界址点号&#xff0c;对这些界址点号以J1开始按顺序排列 要找出宗地所对应的所有界址点号&#xff0c;这里只要执行一个标识 即可得到这样得到的结果。 难点在于对界址点的编号&#xff0c;经过检查…

APACHE KAFKA本机Hello World教程

目标 最近想要简单了解一下Apache Kafka&#xff0c;故需要在本机简单打个Kafka弄一弄Hello World级别的步骤。 高手Kafka大佬们&#xff0c;请忽略这里的内容。 步骤 Apacha Kafka要求按照Javak8以上版本的环境。从官网下载kafka并解压。 启动 # 生产kafka集群随机ID KA…