从0学会Spring框架

news2024/9/26 3:27:08

文章目录

  • 1. 对Spring的理解
  • 2. Spring IoC
  • 3. DI
  • 4. 如何创建一个Spring项目
    • 4.1 创建一个Maven项目
    • 4.2 添加Spring框架支持
    • 4.3 添加启动类
  • 5. 存储Bean对象
    • 5.1 添加配置文件
    • 5.2 创建Bean对象
    • 5.3 注册Bean
  • 6. 获取并使用Bean对象
  • 7. 更简单存储Bean对象的方式
    • 7.1 前置工作
    • 7.2 添加存储对象的注解
      • 7.2.1 类注解
      • 7.2.2 方法注解
  • 8. 对象装配/对象注入
    • 8.1 属性注入
    • 8.2 构造方法注入
    • 8.3 Setter注入
    • 8.4 @Resource注解
    • 8.5 @Bean将一个对象多次注入问题

1. 对Spring的理解

Spring是一个框架,包含了众多工具方法的IoC容器

什么是容器?

容器就是容纳物品的装置,比如:

  • List/Map,用来储存数据,说明它是一个数据存储容器
  • Tomcat,webapps目录下保存多个web应用程序,说明它是一个web容器

什么是IoC?

IoC的意思就是控制反转,是一种思想,主要通过IoC容器实现控制权发生反转,如对象的初始化及依赖关系(对象引用另一个对象),由程序自己控制这部分逻辑转变为由容器统一控制

在传统的开发中,如果A对象依赖B对象,那在A对象中就要new B对象,此时B对象的控制权就在A中,但是如果B对象一旦有所改变,如构造方法改变,那在A中也就要发生改变

控制反转呢就是控制权发生反转,B对象的控制权交给容器统一管理,此时B对象改变的话,A对象不用做任何处理,容器自动的将改动后的B对象交给A,此时A不必关注B的实现的方式,只管用就行

IoC的优点: 实现代码的解耦,将对象的生命周期交给IoC容器来管理,程序员无需管理

2. Spring IoC

前面说了Spring是一个包含众多工具方法的IoC容器,所以关键还是在容器上,所谓容器,就得具有容器的基本功能,取东西,存东西,对应这里的Spring容器,它具有最基本的功能为:

  • 将对象存储到容器
  • 从容器中将对象取出

Spring IoC就是一个实现了IoC思想的框架,具有存储Bean和取Bean的功能

将容器中存储的对象称为Bean对象(Java中的普通对象),Spring是一个IoC容器也就是将对象的创建和销毁的权利都交给Spring来管理,它本身具备了存储对象和获取对象的能力

3. DI

DI的意思为依赖注入,就是由IoC容器在运行期间,动态的将某种依赖关系注入到当前类中,就是将依赖的某个对象拿过来给当前类使用

DI与IoC的区别?

IoC是一种思想,DI为具体实现,它俩是从不同角度描述同一件事情,就是利用IoC容器,利用依赖关系注入的方式实现对象之间的解耦,例如:吃饭(IoC),吃米饭(DI)

4. 如何创建一个Spring项目

4.1 创建一个Maven项目

创建Maven项目
设置好创建项目的路径

设置路径

4.2 添加Spring框架支持

在pom.xml中添加Spring的框架支持,xml配置如下:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.23</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.3.23</version>
        </dependency>
    </dependencies>

4.3 添加启动类

在java文件夹下,创建一个启动类,包含main方法

启动类

5. 存储Bean对象

5.1 添加配置文件

第一次添加需要在项目中添加Spring配置文件(只需第一次添加

resources目录下创建一个spring-config.xml(此文件名可以为别的,建议为spring-config)

xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

5.2 创建Bean对象

Bean对象就是Java中普通的对象,这里我们创建一个Dog类

public class Dog {
    public void say(String name){
        System.out.println(name+":旺旺~");
    }
}

5.3 注册Bean

将创建好的Bean对象通过配置文件注册到Spring中

<bean id="dog" class="com.beans.Dog"></bean>

id为bean的名称,相当于给bean对象起一个名字,class为bean的路径(包名+类名)

6. 获取并使用Bean对象

使用Spring上下文的方式获取Bean对象

  1. 先获取Spring上下文
  2. 再通过上下文对象提供的方法获取指定的Bean对象
public class App {
    public static void main(String[] args) {
    //ApplicationContext是一个接口,new其实现类,构造方法的参数为刚才创建的配置文件的名称
    //得到spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //使用spring容器获取bean对象,这里使用bean的名称获取,就是配置文件中bean的id
        //getBean的返回类型为Object,所以强转一下
        Dog dog = (Dog)context.getBean("dog"); //该句代码就是上述说的DI
        dog.say("旺财");
    }
}

打印结果

getBean的更多用法:

  • 使用bean id获取bean(需强转,返回类型为Object,id必须唯一
Dog dog = (Dog)context.getBean("dog");
  • 使用bean class获取bean(该类必须有唯一的bean,也就是多个该类型被注入到Spring中会报错)
Dog dog = context.getBean(Dog.class);

使用此种方式不用强转,但是该类必须唯一

  • 使用bean id和class获取bean
Dog dog = context.getBean("dog",Dog.class);

此种方式是为了解决使用class获取bean时存在多个相同类型的bean对象,此时加上id(因为id的唯一性)就可以获取唯一的bean对象,当相同的类多次注入到spring容器中时,此时多个相同类型的bean对象各不相同(每个bean都有其唯一的地址)

不管使用哪种方式获取,都必须保证能获取唯一的bean对象,否则会报错

推荐使用最后一种id和class获取bean对象

使用Bean工厂的方式获取Bean对象

  1. 先获取bean工厂对象
  2. 再使用该对象的getBean方法获取Bean对象
public class App {
    public static void main(String[] args) {
        BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
        Dog dog = factory.getBean("dog",Dog.class);
        dog.say("旺财");
    }
}

打印结果

ApplicationContext与BeanFactory有什么区别?

  • ApplicationContext属于BeanFactory的子类
  • BeanFactory只提供了基础访问Bean的方法,而ApplicationContext除了拥有BeanFactory的所有功能外,还提供了更多的方法实现,如对国际化的支持,资源访问的支持以及事件和传播等方面的支持
  • 性能两者不同,BeanFactory是按需加载Bean类似懒加载,而ApplicationContext在创建时会将所有Bean加载起来,属于饿汉式

在这里插入图片描述

使用ApplicationContext的方式,当代码执行完上述步骤的时候,所有的bean对象都会被初始化好加载到spring容器中

在这里插入图片描述

使用BeanFactory的方式,只有真正调用getBean的时候才会初始化对应的对象然后加载到spring容器中,类似懒加载的方式

7. 更简单存储Bean对象的方式

7.1 前置工作

更简单存储Bean的方式就是使用包扫描+注解的方式,此种方法可以和上述添加bean标签的方式共存

在Spring配置文件中设置bean扫描路径,将前面配置的xml文件换成下面的,但是注意下面存放bean对象的包名要和自己的创建的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">
<!--    com.beans 是所有要存放bean对象的根路径-->
    <content:component-scan base-package="com.beans"></content:component-scan>
</beans>

7.2 添加存储对象的注解

7.2.1 类注解

  • @Controller,控制层(前端参数校验)
  • @Service,服务层(数据组装和接口调用)
  • @Repository,数据持久层(负责和数据库进行交互)
  • @Component,组件(非其他四类)
  • @Configuration,配置层(系统运行前,提前加载一些资源)
@Controller
public class UserController {
    public void sayHello(){
        System.out.println("hello Controller");
    }
}

使用注解注入Bean对象时,bean的名称也就是bean id为类名小驼峰的表示
如果原类名的第一个字母和第二个字母都是大写,那么此时的bean id为原类名不变

public class Application1 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        //bean id为类名改写为小驼峰方式
        UserController userController = context.getBean("userController",UserController.class);
        userController.sayHello();
    }
}

结果

其他四个注解与此用法相同

为什么需要五大类注解

五大类注解
提高代码的可读性,让程序员能够直观的判断当前类的用途

类注解的关系

@Controller,@Service,@Repository,@Configuration都是基于@Component实现的,所以可以认为@Component是它们的父类

7.2.2 方法注解

@Bean注解加到方法上,将方法的返回值添加到容器中

注意: @Bean注解必须结合五大类注解来使用,并且方法必须有返回值

@Component
public class Students {
    @Bean
    public Student s1(){
        Student student = new Student();
        student.setName("张三");
        student.setAge(23);
        return student;
    }
}
public class App1 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        Student student = context.getBean("s1",Student.class);
        System.out.println(student);
    }
}

打印结果

@Bean重命名

@Bean命名规则:

  • 当没有设置name属性时,方法名为bean名称
  • 当设置了name属性,只能通过name属性对应的值来获取,使用方法名就获取不到
@Component
public class Students {
    @Bean(name = "student1")
    public Student s1(){
        Student student = new Student();
        student.setName("张三");
        student.setAge(23);
        return student;
    }
}
public class App1 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        Student student = context.getBean("student1",Student.class);
        System.out.println(student);
    }
}

打印结果

起名字的时候,可以起多个名字:

    @Bean(name = {"user1","user2","user3"})
    public User getUser(){
        User user = new User();
        user.setUsername("张三");
        user.setAge(10);
        return user;
    }

8. 对象装配/对象注入

8.1 属性注入

使用@Autowired注解获取到Spring中的Student对象,将其注入到UserController1的属性中

@Controller
public class UserController1 {

    @Autowired
    private Student student;

    public void sayHello(){
        System.out.println(student);
    }
}
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController1 userController1 = context.getBean(UserController1.class);
        userController1.sayHello();
    }
}

打印结果

8.2 构造方法注入

构造方法注入是在构造方法上加@Autowired,实现注入

@Service
public class UserService {

    private Student student;

    @Autowired
    public UserService(Student student1){
        this.student = student1;
    }
    public void say(){
        System.out.println(student);
    }
}
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserService userService = context.getBean(UserService.class);
        userService.say();
    }
}

打印结果

如果当前类中只存在一个构造方法,那么@Autowired可以省略,多个构造方法时则不可以省略

8.3 Setter注入

Setter注入是在设置的set方法上加@Autowired注解

@Controller
public class UserController2 {
    private Student student;

    @Autowired
    public void setStudent(Student student) {
        this.student = student;
    }

    public void say(){
        System.out.println(student);
    }
}
public class App1 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController2 userController2 = context.getBean(UserController2.class);
        userController2.say();
    }
}

注意: 属性注入与Setter注入不可往final修饰的变量中注入,但是构造方法注入可以往final修饰的变量中注入

原因:final修饰的变量必须直接赋值,或者使用构造方法赋值,构造方法只会执行一次

8.4 @Resource注解

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

public class UserService2 {
    @Resource(name = "student1")
    private Student student;
    
    public void say(){
        System.out.println(student);
    }
}

@Autowired与@Resource区别

  1. 出身不同:@Resource来自于jdk,@Autowired时Spring框架提供的
  2. 用法不同:@Autowried可以用于属性注入,构造方法注入,Setter注入,@Resource不支持构造方法注入
  3. 参数不同:@Resource支持更多的参数设置,比如name,type,而@Autowried只支持required参数

8.5 @Bean将一个对象多次注入问题

在spring容器中找bean有两种方式:

  1. 根据bean的名称也就是bean id
  2. 根据bean的类型也就是bean class

先创建一个Cat类,属性有name和color,并提供get,set,toString方法

往Spring中注入多个Cat对象

@Controller
public class Cats {
    @Bean
    public Cat cat1(){
        Cat cat = new Cat();
        cat.setName("糯米");
        cat.setColor("白色");
        return cat;
    }
    
    @Bean
    public Cat cat2(){
        Cat cat = new Cat();
        cat.setName("汤圆");
        cat.setColor("黑色");
        return cat;
    }
}

在另一个类中获取Cat对象

@Controller
public class CatController {

    @Autowired
    private Cat cat;

    public void getCat(){
        System.out.println(cat);
    }
}

创建启动类

public class App3 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        CatController catController = context.getBean(CatController.class);
        catController.getCat();
    }
}

报错

发现报错了,因为Spring中已经注入了两个Cat对象,所以此时不知道获取哪个对象

在这里插入图片描述

三种解决方案

  1. 精确的描述bean的名称(将注入的名称写对)
  2. 使用@Rsource设置name方式来重命名注入对象
  3. 使用@Autowired+@Qualifier来筛选bean对象

方案一:精确的描述bean的名称(将注入的名称写对)

@Controller
public class CatController {

    @Autowired
    private Cat cat1; //精确描述bean名称

    public void getCat(){
        System.out.println(cat1);
    }
}

方案1

方案二: 使用@Rsource设置name方式来重命名注入对象

@Controller
public class CatController {

    @Resource(name = "cat2")
    private Cat cat;

    public void getCat(){
        System.out.println(cat);
    }
}

结果

方案三:使用@Autowired+@Qualifier来筛选bean对象

@Controller
public class CatController {

    @Autowired
    @Qualifier(value = "cat1")
    private Cat cat;

    public void getCat(){
        System.out.println(cat);
    }
}

结果

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

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

相关文章

VScode里的终端,Anaconda下的命令提示符和 PowerShell的联系

目录 PowerShell和CMD的区别Anaconda Prompt 和 Anaconda PowerShell Prompt取消默认激活conda中的base环境在conda里设置取消默认激活base环境在VScode里设置取消默认激活base环境手动控制进出base环境 PowerShell和CMD的区别 PowerShell和CMD都是命令行界面工具&#xff0c;…

SuperMap GIS基础产品桌面GIS FAQ集锦(2)

SuperMap GIS基础产品桌面GIS FAQ集锦&#xff08;2&#xff09; 【iDesktop】【10.2.1】【11.0.1】 请问在 iDesktop 桌面端对线数据集进行打断线操作后&#xff0c;打断的线不显示是什么原因呢&#xff1f; 【问题原因】 当时操作的线数据集空间索引存在异常&#xff0c;导致…

C++之数据对齐

数据对齐 • 总说&#xff1a; ○ 对齐方式&#xff1a;表示的是一个类型的对象存放的内存地址应满足的条件 ○ 好处&#xff1a;对齐的数据在读写上有性能优势 ○ 对于不对齐的结构体&#xff0c;编译器会自动补齐以提高CPU的寻址效率 • 数据对齐&#xff1a;(四个函数/描述符…

【shell】shell结程规范与变量

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、shell脚本概述1.Shell脚本应用场景2.Shell的作用3.用户的登录Shell 二、Shell编程规范1.she11脚本的构成2.运行shel1脚本3.重定向与管道操作1.交互式硬件设备2.…

学习CTF一定要知道的网站!快快收藏!

今天在这里给大家介绍一些好用的学习网站&#xff1a; 首先是CTF做题平台&#xff1a; •BUUCTF •攻防世界 •ctf.show •catf1ag.cn •ctfhub.com •ctf.wgpsec.org •ctf-wiki.org •ctftime.org 学习论坛&#xff1a; •https://www.52pojie.cn/ •https://www.freebuf.…

【nvm 安装】使用nvm管理node版本,安装步骤

一、下载nvm 下载链接&#xff1a;Releases coreybutler/nvm-windows GitHub 建议下载安装版的&#xff0c;非安装版还需要额外配置环境变量。 二、安装 注意 &#xff1a; 都在说安装之前需要删除node版本&#xff0c;避免冲突&#xff0c;很听话的我删除了&#xff0c;…

每日学术速递5.4

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.IndoorSim-to-OutdoorReal: Learning to Navigate Outdoors without any Outdoor Experience 标题&#xff1a;IndoorSim-to-OutdoorReal&#xff1a;在没有任何户外经验的情况下学…

Linux系统中ARMv8架构u-boot启动流程分析

目录 ​ 本文基于 armv8 架构来对 u-boot 进行启动流程分析。 1 概述 2 armv8 u-boot的启动 3 u-boot源码整体结构和一些编译配置方式 3.1 编译配置方式 3.2 u-boot源码结构 4 u-boot armv8链接脚本 4.1 u-boot.lds 4.2 u-boot-spl.lds 本文基于 armv8 架构来对 u-bo…

Android LifecycleService

监听Service的生命周期-LifecycleService 为了方便我们对Service生命周期的监听&#xff0c;Android提供了一个名为LifecycleService的类&#xff0c;让该类继承自Service&#xff0c;并实现LifecycleOwner接口。 /*** A Service that is also a {link LifecycleOwner}.*/ pu…

项目实战——获取树形结构

获取树形结构 一、背景介绍二、 思路和方案方案一&#xff1a;使用递归查询的方式并构建树形结构方案二&#xff1a;使用临时表的方式构建树形结构使用临时表的优缺点 三、过程项目案例核心代码 四、总结五、升华 一、背景介绍 我们在开发中时常会遇到需要用到树形结构这种表示…

1分钟学会、3分钟上手、5分钟应用,快速上手责任链框架详解 | 京东云技术团队

作者&#xff1a;京东物流 覃玉杰 1. pie 简介 责任链模式是开发过程中常用的一种设计模式&#xff0c;在SpringMVC、Netty等许多框架中均有实现。我们日常的开发中如果要使用责任链模式&#xff0c;通常需要自己来实现&#xff0c;但自己临时实现的责任链既不通用&#xff0…

解决安装nrm,执行nrm ls时出现的const open=require(‘open’)问题

最开始安装的淘宝镜像源为npm config set registryhttps ://registry.npm.taobao.org/&#xff0c;后来看到镜像源变了&#xff0c;就换了下面的&#xff0c; 下载新的npm淘宝镜像资源包npm config set registry http://registry.npmmirror.com 查看&#xff0c;安装成功&…

【c语言】字符串的基本概念 | 字符串存储原理

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ …

Spring常用注解总结

目录 一、前言1、xml和注解的最佳实践&#xff1a;2、使用注解唯一需要注意的就是&#xff0c;必须开启注解的支持&#xff1a; 二、Spring的常用注解1、给容器中注入组件2、注入bean的注解3、JsonIgnore4、初始化和销毁方法5、Java配置类相关注解6、切面&#xff08;AOP&#…

DNS资源记录详解

资源记录&#xff08;resourse record&#xff09;就是域名服务器保存的记录&#xff0c;也是解析器请求的内容&#xff0c;资源记录保存在zone文件中。域&#xff08;domain&#xff09;&#xff1a;以 www.baidu.com 为例&#xff0c;com是一个域。baidu.com是一个域&#xf…

Selenium:三种等待方式

目录 一、显示等待 二、隐式等待 三、强制等待 UI自动化测试&#xff0c;大多都是通过定位页面元素来模拟实际的生产场景操作。但在编写自动化测试脚本中&#xff0c;经常出现元素定位不到的情况&#xff0c;究其原因&#xff0c;无非两种情况&#xff1a;1、有frame&#x…

Unity 光照

\\\\\\\ Unity烘焙&#xff08;Baking&#xff09;是指将场景中的动态光照转换为静态贴图。在烘焙过程中&#xff0c;Unity会将场景中的光源、材质和对象等信息计算出来&#xff0c;并存储为贴图。当玩家进入场景时&#xff0c;Unity只需要读取这些预计算好的贴图或者数据文件&…

2023年计算机视觉与模式识别国际会议(CCVPR 2023)

会议简介 Brief Introduction 2023年计算机视觉与模式识别国际会议(CCVPR 2023) 会议时间&#xff1a;2023年9月15日-17日 召开地点&#xff1a;英国牛津 大会官网&#xff1a;www.ccvpr.org 计算机视觉技术与模式识别是现代科学中备受关注的热点技术&#xff0c;它的革新对各行…

Monorepo开发策略详解

目录 一&#xff1a;什么是 Monorepo&#xff1f; 二&#xff1a;Monorepo 和其他结构的区别&#xff1a; 三&#xff1a;Monorepo的优缺点 3.1.优点 3.2.缺点 四&#xff1a;如何使用Monorepo 一&#xff1a;什么是 Monorepo&#xff1f; Monorepo 是一种将多个项目存放…

【iOS】—— RunLoop初学

RunLoop 文章目录 RunLoopRunLoop简介RunLoop基本使用Runloop伪代码Runloop模型图 Runloop对象Runloop对象的获取_CFRunLoopGet0方法 RunLoop的相关类RunLoop相关类的实现CFRunLoopRefCFRunLoopModeRef五种运行模式CommonModes什么是Mode Item&#xff1f;Mode到底包含哪些类型…