JavaEE >> Spring(2)

news2024/12/29 8:58:53

前面已经介绍了 Spring 的基本使用以及创建,本文将介绍使用注解的方式实现对 Spring 更简单的存储对象读取对象.

将对象存储到 Spring 中

创建 Spring 项目

前面已经做过详细步骤,此处不再赘述. 链接在此 Spring 基本使用及创建

pom.xml 和 Spring 配置项

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring_review</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
    </dependencies>
</project>

Spring 配置项:即配置扫描路径(想要将对象成功的存储到 Spring 中,我们需要配置⼀下存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 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="demo"></content:component-scan>
   
</beans>

在这里插入图片描述
在这里插入图片描述

这样一来,demo 包下的所有类都可以让 Spring 识别到.

添加注解存储 Bean 对象

/**
 * Created with IntelliJ IDEA.
 * Description: 使⽤ @Controller 存储 bean
 */
@Controller
public class CarController {
    public void crateCar(String component){
        System.out.println("[Controller] 用 " + component + " 部件造车!!!");
    }
}

创建启动类

和前面一样.

public class App2 {
    public static void main(String[] args) {
        // 1. 得到对象容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2. 加载 Bean 对象
        CarController carController = (CarController) context.getBean("carController");
        // 3. 使用 Bean 对象
        carController.crateCar("定制轮胎");
    }
}

结果如下:
在这里插入图片描述
上述使用 Controller 注解对 Bean 对象进行存储,是注解的一种,下面对 Spring 中其余的注解进行举例说明.
使用 @Service 注解存储 Bean 对象:

/**
 * Created with IntelliJ IDEA.
 * Description: 使⽤ @Service 存储 bean
 */
@Service
public class CarService {
    public void crateCar(String component){
        System.out.println("[Service] 用 " + component + " 部件造车!!!");
    }
}
public class App2 {

    public static void main(String[] args) {
        // 1. 得到对象容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2. 加载 Bean 对象
        CarService carService = (CarService) context.getBean("carService");
        // 3. 使用 Bean 对象
        carService.crateCar("定制轮胎");
    }
}

在这里插入图片描述
使用 @Component 注解存储 Bean 对象:

/**
 * Created with IntelliJ IDEA.
 * Description: 使⽤ @Component 存储 bean
 */
@Component
public class CarComponent {
    public void crateCar(String component){
        System.out.println("[Component] 用 " + component + " 部件造车!!!");
    }
}
public class App2 {
    public static void main(String[] args) {
        // 1. 得到对象容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2. 加载 Bean 对象
        CarComponent carComponent = (CarComponent) context.getBean("carComponent");
        // 3. 使用 Bean 对象
       carComponent.crateCar("定制车身");
    }
}

在这里插入图片描述
使用 @Repository 注解存储 Bean 对象:

/**
 * Created with IntelliJ IDEA.
 * Description: 使⽤ @Repository 存储 bean
 */
@Repository
public class CarRepository {
    public void crateCar(String component){
        System.out.println("[Repository] 用 " + component + " 部件造车!!!");
    }
}
public class App2 {
    public static void main(String[] args) {
        // 1. 得到对象容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2. 加载 Bean 对象
        CarRepository carRepository = (CarRepository) context.getBean("carRepository");
        // 3. 使用 Bean 对象
        carRepository.crateCar("定制车身");
    }
}

在这里插入图片描述
看到此处就会发现,其实它们的功能是一样的,那么为什么还需要这么多的类注解呢?

Spring 注解

原因:就是让程序员看到类注解之后,就能直接了解当前类的⽤途,如下:
注解分为类注解方法注解两大类.
类注解:

  1. @Component:以下4个注解的父类
  2. @Controller:表示这个类是业务逻辑层的类;
  3. @Service:服务层的类;
  4. @Repository:持久层的类;
  5. @Configuration:配置层的类;

它们之间的关系:属于@Component 的“⼦类”。 看下面源码
在这里插入图片描述
在这里插入图片描述

就会发现它们其中都会存在 @Component 注解,说明它们本身就是属于 @Component 的“⼦类”.

方法注解:

  • @Bean

下面为方法注解的举例说明,方法注解就是放到某个方法上的。
创建一个 CarPossess 类,将 carPossess 对象存储到 Spring 容器中:

@Controller
public class CarPossess {
    private String name;
    private int id;
    @Bean //将对象注入到 Spring 容器中
    public CarPossess carPossess1(){
        CarPossess carPossess = new CarPossess();
        carPossess.setName("张先生");
        carPossess.setId(666);
        return carPossess;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

    @Override
    public String toString() {
        return "CarPossess{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}
public class App2 {
    public static void main(String[] args) { // 从 Spring 容器中得到 carPossess 对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        CarPossess carPossess = (CarPossess) context.getBean("carPossess1");
        System.out.println(carPossess.toString());
    }
}

在这里插入图片描述

补充:

  1. Bean 的命名规则
  • ⾸字⺟和第⼆个字⺟都不为⼤写,⾸字⺟⼩写来获取 Bean;如:
    在这里插入图片描述
    在这里插入图片描述

  • ⾸字⺟和第⼆个字⺟都是⼤写,那么直接使⽤原 Bean 名来获取 Bean.
    例如 CRepository 类,就需要用 context.getBean(“CRepository”) 来获取 Bean.

  1. Bean 的重命名
    可以通过 name 属性给 Bean 对象进行重命名操作,如下:
@Bean(name = {"p1"}) //将对象注入到 Spring 容器中
    public CarPossess carPossess1(){
        CarPossess carPossess = new CarPossess();
        carPossess.setName("张先生");
        carPossess.setId(666);
        return carPossess;
    }

在这里插入图片描述
在这里插入图片描述
这里 name 属性其实是一个数组,也可以设置多个名字:
在这里插入图片描述
在这里插入图片描述

注意:

  • 使用重命名后 Bean 默认获取方法就不行了,即不能使用方法名进行获取
  • 如果多个 Bean 使用相同的名称,那么程序执行不会报错,但是第一个 Bean 之后的对象不会被存放到容器中,也就是只有在第一次创建 Bean 的时候会将容器和 Bean 名称关联起来,后续再有相同名称的 Bean 存储时候,容器会自动忽略。
  • @Bean(name ={}) 中 name ={} 可以不写, 可以直接重命名(下面例子会用到)

从 Spring 中获取对象(对象装配)

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

例如将 CarPossess 类注入到 CarService 类中。其中 CarPossess 类中包含 carPossess 对象,换言之就是将该对象注入到 CarService 类中,能在 CarService 这个类中对该对象进行使用以及操作.

有以下三种实现方式

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

属性注入

属性注入使用 @Autowired 注解实现
实现将 CarPossess 类注入到 CarService 类中.
CarPossess 类实现:

@Controller
public class CarPossess {
    private String name;
    private int id;
    @Bean(name = {"p1","p2"}) //将对象注入到 Spring 容器中
    public CarPossess carPossess1(){
        CarPossess carPossess = new CarPossess();
        carPossess.setName("张先生");
        carPossess.setId(666);
        return carPossess;
    }

    /*
    *  属性注入
    * */
    public CarPossess getCarPossess(String name,int id){
        CarPossess carPossess = new CarPossess();
        carPossess.setId(id);
        carPossess.setName(name);
        return carPossess;
    }

    /*
    *  构造方法注入 / Setter 注入
    * */
    public int add(){
        System.out.println("执行 CarPossess 中的 add方法");
        return 1;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

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

CarService 类实现:

@Service
public class CarService {

    /*
    * 属性注入
    * */
    @Autowired
    private CarPossess carPossess;  // 将 CarPossess 类注入到 CarService 类中
    
    public CarPossess getCarPossess(String name,int id){
        return carPossess.getCarPossess(name,id); // 调用 CarPossess 类里面的方法
    }
}

检验是否获取到对象:

public class App3 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        CarService carService = (CarService) context.getBean(CarService.class);
        System.out.println(carService.getCarPossess("王五",777).toString());
    }
}

输出结果:
在这里插入图片描述

构造方法注入(Spring 推荐注入方式)

构造⽅法注⼊是在类的构造⽅法中实现注⼊.

@Service
public class CarService2 {

    private CarPossess carPossess;

    @Autowired
    public CarService2(CarPossess carPossess){
        this.carPossess = carPossess;
    }

    public void sayHi(){
        System.out.println("执行 CarService2 中的 sayHi 方法");
        carPossess.add();
    }
}

检测是否可以获取到 carPossess 对象:

/*
    * 构造方法测试
    * */
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        CarService2 carService2 = (CarService2) context.getBean("carService2");
        carService2.sayHi();
    }

在这里插入图片描述

其中需要注意,当类中只有一个构造方法时 @Autowired 注解可以省略,当类中有多个构造方法时需要使用 @Autowired 注解来明确指定到底使⽤哪个构造⽅法,否则会报错.

Setter 注入

@Service
public class CarService3 {
    private CarPossess carPossess;

    @Autowired
    public void  setCarPossess(CarPossess carPossess){
        this.carPossess = carPossess;
    }

    public void sayHi(){
        System.out.println("执行 CarService3 中的 sayHi 方法");
        carPossess.add();
    }
}
/*
    * Setter
    * */
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        CarService3 carService3 = (CarService3) context.getBean("carService3");
        carService3.sayHi();
    }

在这里插入图片描述

三种注入方式的区别

  1. 属性注入简洁方便,但只能用于 IoC 容器中(即通用性低),即且无法注入一个不可变的对象(被final 修饰的对象);
  2. 构造方法注入是 Spring 推荐的方式,可注入不可变对象、注入对象不会被修改(因为构造方法只加载一次)、通用性好(可适用于任何环境,无论是 IoC 框架还是非 IoC 框架);
  3. Setter 注入,每一个 Setter 只针对一个对象,无法注入不可变的对象、注入的对象可被修改(setter 本来就是一个方法,是方法就有可能被调用和修改)

多个同类型的 Bean 存储到容器中,获取时报错

准备工作:创建一个 Students 类,生成两个 Student 对象,创建 StuController 类,将 Student 对象注入到 StuController 类中.
代码如下:

public class Student {
    private String name;
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
@Component
public class Students {

    @Bean("stu1")
    public Student student1(){
        Student student = new Student();
        student.setName("王五");
        return student;
    }

    @Bean("stu2")
    public Student student2(){
        Student student = new Student();
        student.setName("李四");
        return student;
    }
}
@Controller
public class StuController {
    @Autowired
    private Student student;

    public void test(){
        System.out.println(student.toString());
    }
}
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        StuController stuController = (StuController) context.getBean("stuController");
        stuController.test();
    }
}

以上为多个 Student 对象存储到容器中 问题,运行后会发现报错,
在这里插入图片描述

意思是找不到唯一的 Bean. 解决方法

  1. 将 StuController 类中属性注入改为具体的 Bean 名称;如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  2. 在注入的时候使用 @Qualifier 注解,如下:
    在这里插入图片描述
    在这里插入图片描述

  3. 使用 @Resource 注解
    上面已经提到属性注入时使用 @Autowired 注解,而 @Resource 注解是属性注入的另一个注解,换言之,属性注入还可以使用 @Resource 注解。
    对于 @Resource 注解,它可以设置一个 name 属性,用这个属性来描述 Spring 启动的时候到底注入哪个对象,如下:
    在这里插入图片描述
    在这里插入图片描述

@Autowired 与 @Resource 注解的区别:

  • @Autowired 由 Spring 提供,@Resource 来⾃于 JDK;
  • @Autowired 默认通过 byType 方式注入,@ Resource 默认通过 byName 方式注入;
  • @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊;
  • @Autowired 默认通过 byType 方式注入,当有同一个类型多个对象的时候,会根据 byName 方式注入。

byName:拿变量名,去匹配 IoC 容器里面的对象,如下:
在这里插入图片描述
当设置 name 属性的时候,就会根据 name 属性来进行注入,如上述 使用 @Resource 注解举例,输出的是 stu1 对象王五,而不是 stu2 对象李四。

byType:拿变量类型,去匹配 IoC 容器里面的该类型,如下:
在这里插入图片描述
此处会发现,同一个类型存在多个 Bean(对象),对于这种情况上面已经提到过,需要将 student 改为具体的对象名,如 stu1/stu2.
在这里插入图片描述
这也说明了上述两个注解区别的最后一条。

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

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

相关文章

机器学习模型效果不好及其解决办法

当训练出来的机器学习模型效果不佳时&#xff0c;可能涉及多个方面的原因。为了改善模型的效果&#xff0c;需要系统地检查和分析问题的根源&#xff0c;并采取相应的措施进行优化。 一、数据问题 数据质量 检查数据是否干净、完整&#xff0c;是否存在噪声、异常值或缺失值。…

【后端】python2和python3的安装与配置

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、python是什么二、python环境的安装与配置Python 2的安装与配置Python 3的安装与配置注意事项 三、总结 前言 随着开发语言及人工智能工具的普及&#xff0…

C++ //练习 13.17 分别编写前三题中所描述的numbered和f,验证你是否正确预测了输出结果。

C Primer&#xff08;第5版&#xff09; 练习 13.17 练习 13.17 分别编写前三题中所描述的numbered和f&#xff0c;验证你是否正确预测了输出结果。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /*************************…

git提交注释规范插件

1、前言 为什么要注重代码提交规范&#xff1f; 在团队协作开发时&#xff0c;每个人提交代码时都会写 commit message。 每个人都有自己的书写风格&#xff0c;翻看我们组的git log, 可以说是五花八门&#xff0c;十分不利于阅读和维护。 一般项目开发都是多分支共存&#x…

浅涉ROS世界中的坐标系及其他

声明&#xff1a;文中图片素材均采用了其他博主文章&#xff08;文末参考来源&#xff09;&#xff0c;如有侵权或不妥&#xff08;确有不妥和不安&#xff0c;奈何苦于佳图难觅&#xff09;&#xff0c;还望告知&#xff0c;立即删除&#xff01; 坐标系统 ROS中的…

影视后期特效合成:DaVinci Fusion Studio19 激活版

DaVinci Fusion Studio是一款功能强大的影视后期特效合成软件&#xff0c;可广泛应用于视觉效果、广播电视设计、动态图形设计、3D动画设计等领域。 如综合的绘图、动态掩蔽、遮片、图层叠加、字幕等工具&#xff0c;结合高效的粒子生成系统&#xff0c;通过它可以创建各种精细…

51单片机入门_江协科技_35~36_OB记录的自学笔记_AD与DA转换(XPT2046)

35. AD_DA 35.1. AD/DA介绍 •AD&#xff08;Analog to Digital&#xff09;&#xff1a;模拟-数字转换&#xff0c;将模拟信号转换为计算机可操作的数字信号 •DA&#xff08;Digital to Analog&#xff09;&#xff1a;数字-模拟转换&#xff0c;将计算机输出的数字信号转换…

【Word中如何对比文档修改前后的不同之处】

1、准备两个word文档&#xff08;一个是修改前文档&#xff0c;一个是修改后文档&#xff09; 2、双击打开两个文档&#xff0c;点击【审阅】-【比较】-选择修改前的文档和修改后的文档-【确定】&#xff0c;进入文档比较界面。 3、在比较结果文档中&#xff0c;可以查看修改前…

杰出贡献!51Sim助力ASAM新版本智驾标准发布

日前&#xff0c;ASAM&#xff08;德国自动化及测量系统标准协会&#xff09;正式发布了自动驾驶仿真场景标准OpenSCENARIO XML V1.3.0和OpenSCENARIO DSL V2.1.0&#xff0c;这两项标准是自OpenSCENARIO标准版本V1及V2拆分为两个独立标准以来首次正式发布。 作为ASAM会员单位…

stripe.js踩坑日记

stripe.js踩坑日记 先附上代码【选择支付方式并唤起对应支付后重定向到支付结果页面】 先安装依赖包 npm install stripe/stripe-js代码【vue3语法】 <template><div class"stripe-pay-ment-box"><div id"payment-element"></div…

shopify二次开发在首页调用最新的博客文章

在section分区里面新建一个 article.json {"type": "header","name": "Group name","sections": {"blog-posts": {"type": "blog-posts","disabled": true,"settings":…

移动零 ----双指针

题目链接 题目: 分析: 上述题目, 是将数组分块, 分为前半非零, 后半零, 这种数组分块题我们首先想到双指针 思路: 定义两个指针, 一个cur 一个dest, cur用来遍历数组, dest 指向分界处的第一个零位置, 将数组分块首先让cur 0; dest 0;cur 遍历数组, 如果cur 0, 那么cur…

基于springboot+vue+Mysql的漫画网站

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

dubbo本地调试说明

1、连接dubbo服务 telnet ip 端口号比如&#xff1a;dubbo的端口你配置的是20980连接本地&#xff1a; telnet localhost 20980连接之后&#xff0c;输入ls进入dubbo命令行&#xff0c;然后invoke接口进行调试了 2、传入单独参数实例 dubbo>invoke com.kaishustory.userx.…

Maven基础篇6

Idea环境中资源上传与下载 具体问题本地仓库如何与私服打交道&#xff1b; 本地仓库向私服上传文件&#xff0c;上传的文件位置在哪里&#xff1f; 访问私服配置相关信息&#xff1a;用户名密码&#xff1b; 下载东西&#xff0c;需要的各种信息&#xff0c;需要的仓库组的…

串口服务器可以直接连接工业路由器吗

串口服务器可以直接连接工业路由器吗 在工业物联网的架构中&#xff0c;串口服务器和工业路由器都是不可或缺的重要组件。串口服务器的主要功能是将串口通信转换为网络通信&#xff0c;实现数据的远程传输和管理&#xff1b;而工业路由器则负责在工业环境中提供稳定、可靠的网…

C语言——联合与枚举

大家好&#xff0c;上篇文章和大家分享了C语言中的自定义类型结构体。接下来&#xff0c;我们再来了解一下其他的自定义类型——联合与枚举&#xff0c;记得三连支持一下哦&#xff01; 一、联合体 像结构体⼀样&#xff0c;联合体也是由⼀个或者多个成员构成&#xff0c;这些…

AI预测福彩3D第9套算法实战化测试第1弹2024年4月24日第2次测试

今天继续进行新算法的测试&#xff0c;今天是第2次测试。好了&#xff0c;废话不多说了&#xff0c;直接上图上结果。 2024年4月24日福彩3D预测结果 6码定位方案如下&#xff1a; 百位&#xff1a;1、0、2、3、6、7 十位&#xff1a;2、4、1、6、0、5 个位&#xff1a;3、2、4、…

企业工商信息查询API接口如何对接

企业工商信息查询API接口指的是输入公司名全称/注册号/社会统一信用代码的任意一种&#xff0c;获得企业工商注册登记中包含的各类重要信息&#xff0c;主要信息包括&#xff1a;注册号&#xff0c;注册资金&#xff0c;登记机关&#xff0c;注册地址&#xff0c;核准时间&…

力扣HOT100 - 543. 二叉树的直径

解题思路&#xff1a; class Solution {int ans;//记录节点数public int diameterOfBinaryTree(TreeNode root) {ans 1;depth(root);return ans - 1;//节点数减 1 就是路径长度}public int depth(TreeNode root) {if (root null) return 0;int l depth(root.left);int r de…