前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Spring】——Spring简单 读和取

【Spring】——Spring简单 读和取

作者头像
终有救赎
发布2023-10-16 10:21:45
1760
发布2023-10-16 10:21:45
举报
文章被收录于专栏:多线程

前言

❤️❤️❤️Spring专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️ Spring + Spring MVC + MyBatis专栏

上期我们讲解了Spring的创建与使用,发现将Bean 注册到容器这一步中,如果Bean对象过多,在注册到容器时,我们有几个Bean对象就需要几行注册,在实际开发中这是非常麻烦的,我们需要有更简单的方法去实现这一过程,这便是本篇文章的主题——Spring简单 读和取。

image.png
image.png

一、存储Bean对象[读]🍭

在Spring中我们可以使用注解存储和读取Bean对象,而其中我们有两种注解类型可以实现这个功能。

  1. 类注解:@Controller(控制器存储)、@Service(服务存储) 、@Repository(仓库存储)、@Component(组件存储)、@Configuration(配置存储)。
  2. 方法注解:@Bean。

1、配置扫描路径🍉

但是在使用注解去进行存储和读取Bean对象之前,我们还需要进行配置扫描路径。在spring-config.xml中添加如下配置:

image.png
image.png
代码语言:javascript
复制
<?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.demo.component"></content:component-scan>
</beans>

 2、类注解🍉

Ⅰ、@Controller(控制器存储)🍓

ArticleController类:

代码语言:javascript
复制
package com.demo.component;
 
import org.springframework.stereotype.Controller;
 
@Controller// 将对象存储到 Spring 中
public class ArticleController {
    public String sayHi(){
        return "Hello word";
    }
}

还是使用上篇讲的方法 去读取Bean对象:

代码语言:javascript
复制
import com.demo.component.ArticleController;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
 
public class App {
    public static void main(String[] args) {
        //1、获取spring对象
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        //2、从Spring中取出Bean对象
        ArticleController articleController=(ArticleController) context.getBean("articleController");
        //3、使用Bean(可选)
        System.out.println(articleController.sayHi());//输出Hello word
    }
}

Ⅱ、@Service(服务存储)🍓

ArticleController类:

代码语言:javascript
复制
package com.demo.component;
 
import org.springframework.stereotype.Service;
 
@Service// 将对象存储到 Spring 中
public class ArticleController {
    public String sayHi(){
        return "Hello word";
    }
}

还是使用上篇讲的方法 去读取Bean对象:

代码语言:javascript
复制
import com.demo.component.ArticleController;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
 
public class App {
    public static void main(String[] args) {
        //1、获取spring对象
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        //2、从Spring中取出Bean对象
        ArticleController articleController=(ArticleController) context.getBean("articleController");
        //3、使用Bean(可选)
        System.out.println(articleController.sayHi());//输出Hello word
    }
}

Ⅲ、@Repository(仓库存储)🍓

ArticleController类:

代码语言:javascript
复制
package com.demo.component;
 
import org.springframework.stereotype.Repository;
 
 
@Repository// 将对象存储到 Spring 中
public class ArticleController {
    public String sayHi(){
        return "Hello word";
    }
}

还是使用上篇讲的方法 去读取Bean对象:

代码语言:javascript
复制
import com.demo.component.ArticleController;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
 
public class App {
    public static void main(String[] args) {
        //1、获取spring对象
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        //2、从Spring中取出Bean对象
        ArticleController articleController=(ArticleController) context.getBean("articleController");
        //3、使用Bean(可选)
        System.out.println(articleController.sayHi());//输出Hello word
    }
}

Ⅳ、@Component(组件存储)🍓

ArticleController类:

代码语言:javascript
复制
package com.demo.component;
 
import org.springframework.stereotype.Component;
 
@Component// 将对象存储到 Spring 中
public class ArticleController {
    public String sayHi(){
        return "Hello word";
    }
}

还是使用上篇讲的方法 去读取Bean对象:

代码语言:javascript
复制
import com.demo.component.ArticleController;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
 
public class App {
    public static void main(String[] args) {
        //1、获取spring对象
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        //2、从Spring中取出Bean对象
        ArticleController articleController=(ArticleController) context.getBean("articleController");
        //3、使用Bean(可选)
        System.out.println(articleController.sayHi());//输出Hello word
    }
}

Ⅴ、@Configuration(配置存储)🍓

代码语言:javascript
复制
package com.demo.component;
 
import org.springframework.context.annotation.Configuration;
 
@Configuration// 将对象存储到 Spring 中
public class ArticleController {
    public String sayHi(){
        return "Hello word";
    }
}

还是使用上篇讲的方法 去读取Bean对象:

代码语言:javascript
复制
import com.demo.component.ArticleController;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
 
public class App {
    public static void main(String[] args) {
        //1、获取spring对象
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        //2、从Spring中取出Bean对象
        ArticleController articleController=(ArticleController) context.getBean("articleController");
        //3、使用Bean(可选)
        System.out.println(articleController.sayHi());//输出Hello word
    }
}

大家一路看下来,可能会吐槽一下:为什么全都是一样的代码啊?这有什么区别啊😂!

为什么有这么多类注解?🍓 Spring框架有很多类注解是为了让开发者以更简洁、方便的方式来定义各种不同类型的Bean(如控制器、服务、存储库等),并且能够更容易地使用Spring的各种功能(如事务管理、缓存、安全性等)。虽然Spring框架中的注解很多,但大多数都有特定的功能和用途,使得开发者可以根据需求选择合适的注解来使用,也可以让程序员看到类注解之后,就能直接了解当前类的用途,比如:

  • @Controller(控制器):业务逻辑层,用来控制用户的行为,它用来检查用户参数的有效性。
  • @Servie(服务): 服务层,调用持久化类实现相应的功能。[不直接和数据库交互的,它类似于控制中心]
  • @Repository (仓库):持久层,是直接和数据库进行交互的。通常每一个表都会对应一个 @Repository。
  • @Configuration(配置):配置层,是用来配置当前项目的一些信息。
  • @Component (组件) : 公共工具类,提供某些公共方法。

程序的工程分层,调用流程如下:

image.png
image.png

五大类注解的联系🍓

直接看@Controller 、@Service 、@Repository 、@Configuration 等注解的源码:

@Service

image.png
image.png

@Repository

image.png
image.png

我们可以发现这些注解里面都有⼀个注解 @Component,说明它们是属于 @Component 的,是@Component的“子类”(其他源码也都类似,大家可以自行去查看查看他们的源码,理解更深刻哦!)。

3、Bean 的命名规则🍉

连续按两下 Shift 进行搜索或者通过下图方式去打开搜索框

image.png
image.png

Classes中搜索 BeanName,打开我红色框选择的类

image.png
image.png

划到最下面:

image.png
image.png

我们就找到了Bean对象的命名方法,它使用的是 JDK Introspector 中的 decapitalize 方法,源码如下:

代码语言:javascript
复制
    public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        // 如果第⼀个字⺟和第⼆个字⺟都为⼤写的情况,是把 bean 的⾸字⺟也⼤写存储了
        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);
    }

看源码,可以发现获取Bean时 ,Bean的命名只有两种:

  • 首字母和第二个字母都非大写,首字母小写来获取 Bean,
  • 首字母和第二个字母都是大写,那么直接使用原 Bean 名来获取

类名为:ArticleController

正确命名方法:

image.png
image.png

错误命名方法:

image.png
image.png

类名为:AController

正确命名方法:

image.png
image.png

错误命名方法:

image.png
image.png

4、方法注解Bean🍉

类注解是添加到某个类上的,而方法注解是放到某个方法上的。

Ⅰ、方法注解要配合类注解使用🍓

Bean注解需要配合五大类注解使用。

ArticleController

代码语言:javascript
复制
package com.demo.component;
 
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
 
@Component// 将对象存储到 Spring 中
public class ArticleController {
    private int id;
    private String name;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String toString() {
        return "ArticleController{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
 
    @Bean//方法注解
    public ArticleController acSet(){
        ArticleController articleController=new ArticleController();
        articleController.setId(1);
        articleController.setName("java");
        return articleController;
    }
}

使用ArticleController中的acSet方法

代码语言:javascript
复制
import com.demo.component.ArticleController;
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、从Spring中取出Bean对象
        ArticleController articleController=(ArticleController) context.getBean("acSet");//命名规则和获取Bean一样
        //3、使用Bean(可选)
        System.out.println(articleController);
    }
}

当我们把acSet方法的@Component注解删除时,就会报错:

image.png
image.png

因此,在使用Bean注解时需要配合使用五大类注解,才能将对象正常的存储到 Spring 容器中

Ⅱ、重命名 Bean🍓

可以通过设置 name 属性给 Bean 对象进行重命名操作。

image.png
image.png

将acSet方法重命名为ac,并运行代码:

image.png
image.png

我们可以注意到重命名的name名是使用大括号进行存储,其实这就是一个数组,一个 bean 可以有多个名字。

image.png
image.png

aS:

代码语言:javascript
复制
import com.demo.component.ArticleController;
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、从Spring中取出Bean对象
        ArticleController articleController=(ArticleController) context.getBean("aS");
        //3、使用Bean(可选)
        System.out.println(articleController);//输出:ArticleController{id=1, name='java'}
    }
}

但是需要注意的是,如果进行了重命名原类名就无法再进行获取方法了!

image.png
image.png

二、获取 Bean 对象(对象装配)[取]🍭

获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注入。

1、依赖注入的常见方式 🍉

对象装配(对象注入)的实现方法以下 3 种:

  1. 属性注入
  2. 构造方法注入
  3. Setter 注入

刚刚好这里有一篇有关Spring依赖注入的文章,写得很好,我就不重复造轮子了。

面试突击77:Spring 依赖注入有几种?各有什么优缺点? - 掘金 (juejin.cn)

Ⅰ、三种注入优缺点分析🍓

  1. 属性注入的优点是简洁,使同方便;缺点是只能用于 IoC 容器,如果是非 IoC 容器不可用,并且只有在使用的时候才会出现 NPE(空指针异常)。
  2. 构造⽅法注入是Spring 推荐的注入方式,它的缺点是如果有多个注⼊会显得比较臃肿,但出现这种情况你应该考虑一下当前类是否符合程序的单一职责的设计模式了,它的优点是通用性,在使用之前⼀定能把保证注⼊的类不为空。
  3. Setter方式是 Spring 前期版本推荐的注入方式,但通用性不如构造方法,所有 Spring 现版本已经推荐使用构造方法注入的方式来进行类注入了。

2、@Resource:另一种注入关键字🍉

在进行类注入时,除了可以使用 @Autowired 关键字之外,我们还可以使用 @Resource 进行注入

image.png
image.png

@Autowired 和 @Resource 的区别:

  • 出身不同:@Autowired 来自于 Spring,而@Resource 来自于 JDK 的注解;
  • 使用时设置的参数不同:相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如 name 设置,根据名称获取 Bean。
  • @Autowired 可用于 Setter 注入、构造函数注入和属性注入,而@Resource 只能用于 Setter 注入和属性注入,不能用于构造函数注入。

可以看到 @Resource是JDK自带的方法:

image.png
image.png

在构造函数注入时, @Resource 会报错:

image.png
image.png
image.png
image.png

其实在官方文档中并没有明确指出为什么构造方法不可以使用@Resource,可能是官方类加载顺序的问题或者循环引用的问题。(可以评论区讨论,给出你的看法)

3、同一类型多个 @Bean 报错🍉

image.png
image.png

User

代码语言:javascript
复制
package com.demo.component;
 
public class User {
    private int id;
    private String name;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String toString() {
        return "ArticleController{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

Users

代码语言:javascript
复制
package com.demo.component;
 
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
 
@Component
public class Users {
    @Bean
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("Java");
        return user;
    }
    @Bean
    public User user2() {
        User user = new User();
        user.setId(2);
        user.setName("MySQL");
        return user;
    }
}

UserController

代码语言:javascript
复制
package com.demo.Controller;
 
import com.demo.component.User;
import org.springframework.stereotype.Controller;
 
import javax.annotation.Resource;
 
@Controller
public class UserController {
    @Resource
    private User user;
 
    public User getUser(){
        return user;
    }
}

运行APP

image.png
image.png

就可以看到没有唯一Bean定义异常

同一类型多个 Bean 报错处理 🍓

解决同一个类型,多个 bean 的解决方案有以下两个:

  • 使用@Resource(name="user1") 定义。
  • 使用@Qualifier 注解定义名称。

使用@Resource(name="user1")

image.png
image.png
image.png
image.png

使用@Qualifier 注解定义名称

image.png
image.png
image.png
image.png

点个关注支持一下吧~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、存储Bean对象[读]🍭
    • 1、配置扫描路径🍉
      •  2、类注解🍉
        • Ⅰ、@Controller(控制器存储)🍓
        • Ⅱ、@Service(服务存储)🍓
        • Ⅲ、@Repository(仓库存储)🍓
        • Ⅳ、@Component(组件存储)🍓
        • Ⅴ、@Configuration(配置存储)🍓
        • 五大类注解的联系🍓
      • 3、Bean 的命名规则🍉
        • 4、方法注解Bean🍉
          • Ⅰ、方法注解要配合类注解使用🍓
          • Ⅱ、重命名 Bean🍓
      • 二、获取 Bean 对象(对象装配)[取]🍭
        • 1、依赖注入的常见方式 🍉
          • Ⅰ、三种注入优缺点分析🍓
        • 2、@Resource:另一种注入关键字🍉
          • 3、同一类型多个 @Bean 报错🍉
            • 同一类型多个 Bean 报错处理 🍓
        相关产品与服务
        对象存储
        对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档