Java EE 进阶:Spring IoCDI

news2025/3/10 8:58:05

IOC的简单介绍

什么是Spring?Spring是一个开源的框架,让我们的开发更加的简单,我们可以用一句更加具体的话来概括Spring,就是Spring是一个包含众多工具方法的IOC容器。

简单介绍一下IOC,我们之前说过通过@ReqestController和@Controller注解,把对象交给Spring管理,在启动Spring框架时,就会加载类交给Spring管理,这就是IOC思想

IoC: Inversion of Control (控制反转),也就是说Spring是⼀个"控制反转"的容器。

控制反转

就是控制权反转,什么的控制权发⽣了反转? 获得依赖对象的过程被反转了 也就是说,当需要某个对象时,传统开发模式中需要⾃⼰通过new创建对象,现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊(DependencyInjection,DI)就可以了。

传统的开发思路

例如:造一辆小汽车

根据如下的代码:

public class Tire {

    int size;
    public Tire(Integer size){
        this.size=size;
        System.out.println("Tire size ="+size);
    }
}
public class Bottom {
    private Tire tire;
    public Bottom(Integer size){
        this.tire=new Tire(size);
        System.out.println("bootom size"+size);
    }
}
public class Framework {
    private Bottom bottom;
    public Framework(Integer size){
        this.bottom=new Bottom(size);
        System.out.println("framework size"+size);
    }
}
public class Car {
    private Framework framework;
    public Car(Integer size){
        this.framework=new Framework(size);
        System.out.println("car size"+size);
    }
    public void run(){
        System.out.println("car can run ");
    }
}
public class Main {
    static int size;
    public static void main(String[] args) {
        Car car=new Car(12);
        car.run();
    }
}

这样的代码维护性很低

如果我们把Tire类中构造方法的参数去掉,那么其他有关的调用程序就会报错,会连续报错一连串的错误,程序的耦合性很高,而我们写代码讲究高内聚,低耦合,所以这样的传统的开发思路已经不实用了

 我们可以尝试一种新的设计思路

根据如下的代码:

public class Tire {
    int size;
    public Tire(Integer size){
        this.size=size;
        System.out.println("Tire size ="+size);
    }
}
public class Bottom {
    private Tire tire;
    public Bottom(Tire tire){
        this.tire=tire;
        System.out.println("bootom size"+tire.size);
    }
}
public class Framework {
    private Bottom bottom;
    public Framework(Bottom bottom){
        this.bottom=bottom;
        System.out.println("framework size");
    }
}
public class Car {
    private Framework framework;
    public Car(Framework framework){
        this.framework=framework;
        System.out.println("car size");
    }
    public void run(){
        System.out.println("car can run ");
    }
}
public class Main {
    static int size;
    public static void main(String[] args) {
        Tire tire=new Tire(12);
        Bottom bottom=new Bottom(tire);
        Framework framework=new Framework(bottom);
        Car car=new Car(framework);
        car.run();
    }
}

我们只需要将原先创建的下级类,改为传递的方法,这样我们在修改或者添加一些参数时,不需要重新修改创建的下级类,下级类也不会改变,这样我们就实现了解耦。

这部分代码就是IOC容器做的事情

DI(依赖注入)

容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。(也可以说DI是IOC的一种实现)

IOC & DI的使用

Spring 容器管理的主要是对象,这些对象,我们称之为"Bean".我们把这些对象交由Spring管理,由 Spring来负责对象的创建和销毁.我们程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出 对象

我们可以使用@Component注解和@Autowired注解来完成这个过程

import org.springframework.stereotype.Component;+
@Component
public class Tire {
    int size=12;
    public Tire(){
        System.out.println("Tire size ="+size);
    }
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("/bottom4")
public class Bottom {
    private Tire tire;
    @Autowired
    public Bottom(Tire tire){
        this.tire=tire;
        System.out.println("bootom size"+tire.size);
    }
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;+
@Component
public class Framework {
    private Bottom bottom;
    @Autowired
    public Framework(Bottom bottom){
        this.bottom=bottom;
        System.out.println("framework size");
    }
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Car {
    private Framework framework;
    @Autowired
    public Car(Framework framework){
        this.framework=framework;
        System.out.println("car size");
    }
    public void run(){
        System.out.println("car can run ");
    }
}

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
//在 Spring 框架中,Bean 是指 Spring 容器 中的一个对象。
// 简单来说,Spring 管理的任何对象都可以被称为 Bean。
// 这些对象由 Spring 容器 创建、初始化、管理,并根据需要进行生命周期管理。
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Main.class, args);
        // 获取 Spring 管理的 Bean
        Car car = context.getBean(Car.class);
        car.run();
    }
}

IOC详解

bean的存储

共有两类注解类型可以实现:

类注解:@Controller  @Component  @Configuration   @Repository   @Service

方法注解:@Bean

@Controller(控制器存储)

注:记得在对象前加@Controller注解

用原始的方法获取对象其中的方法

public class HelloController {

    public void print(){
        System.out.println("controller");
    }
}
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);

        //用原始的方法来获得对象及其中的方法
        HelloController helloController=new HelloController();
        helloController.print();
}

利用@controller来获取bean对象的三种方法

1.根据bean的名称来获取bean

@Controller("controller")
public class HelloController {

    public void print(){
        System.out.println("controller");
    }
HelloController bean=(HelloController) context.getBean("controller");
        bean.print();

2.根据bean的类型来获取bean

@Controller("controller")
public class HelloController {

    public void print(){
        System.out.println("controller");
    }
HelloController bean2=context.getBean(HelloController.class);
        bean2.print();

3.根据bean的名称和方法来获取bean

@Controller("controller")
public class HelloController {

    public void print(){
        System.out.println("controller");
    }
 HelloController bean3=context.getBean("controller",HelloController.class);
        bean3.print();

运行结果: 

 当然还有其他的方法

注:bean的名称使用小驼峰的写法 

@Service(服务储存)

利用@Service存储bean

@Service
public class UseService {
    public void print(){
        System.out.println("service");
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UseService bean6 = context.getBean(UseService.class);
        bean6.print();
}

@Repository(仓库存储) 

利用@Repository存储bean

@Repository
public class UseRepository {
    public void print(){
        System.out.println("repository");
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UseRepository bean7 = context.getBean(UseRepository.class);
        bean7.print();
}

@Component(组件存储)

利用@Component存储bean

@Component
public class UseComponent {
    public void print(){
        System.out.println("component");
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UseComponent bean4 = context.getBean(UseComponent.class);
        bean4.print();
}

@Configuration(配置存储)

利用@Configuration存储bean

@Configuration
public class UseConfiguration {
    public void print(){
        System.out.println("configuration");
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UseConfiguration bean5 = context.getBean(UseConfiguration.class);
        bean5.print();
}

注解的作用

@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.

@Servie:业务逻辑层,处理具体的业务逻辑.

@Repository:数据访问层,也称为持久层.负责数据访问操作

@Configuration:配置层.处理项⽬中的⼀些配置信息.

程序的应用分层,调用方式

通过看这些注解的源码,我们发现这些注解中都有@Component注解,都是其子类 

方法注解@Bean 

注:方法注解要配合类注解才可以正常的存储到Spring容器中

@Component
public class StudentComponent {

    @Bean
    public Student stu1(){
        return new Student("zs",12);
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Student bean8 =(Student) context.getBean(Student.class);
        System.out.println(bean8);
}

如果是多个对象的时候

@Component
public class StudentComponent {

    @Bean
    public Student stu1(){
        return new Student("zs",12);
    }

    @Bean
    public Student stu2(){
        return new Student("xx",5);
    }

    @Bean(name={"stu4","stu5"})
    public Student stu3(){
        return new Student("lisi",14);
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Student bean8 =(Student) context.getBean(Student.class);
        System.out.println(bean8);
}

我们可以根据名称来获取对象

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Student bean8 =(Student) context.getBean("stu1");
        System.out.println(bean8);
}

 

我们也可以对Bean进行重命名

@Bean(name={"stu4","stu5"})

路径的扫描 

启动类的默认扫描路径为启动类所在的包及其子类,可以在启动类中看到扫描的路径

我们可以通过 @ComponentScan 来配置启动类的扫描路径

@ComponentScan("在里面写路径,为开始项的路径,开始项的默认路径为本类的路径")
也可以使用数组的写法
例如
@ComponentScan({"com.blame.ioc.service", "com.blame.ioc.component"})

DI详解

依赖注入

1.属性注入

是@Autowired注解实现的,将UserService类和UserConfiguration注⼊到HelloController类中

@Controller("controller")
public class HelloController {

    //属性的注入
    @Autowired
    private UseService useService;

    @Autowired
    private UseConfiguration useConfiguration;

    public void print(){
        System.out.println("controller");
        useService.print();
        useConfiguration.print();
    }
}

@Configuration
public class UseConfiguration {
    public void print(){
        System.out.println("configuration");
    }
}

@Service
public class UseService {
    public void print(){
        System.out.println("service");
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UseService service=context.getBean(UseService.class);
        service.print();

        UserController userController=context.getBean(UserController.class);
        userController.print();
}

2.构造方法注入

@Controller("controller")
public class HelloController {
    //构造方法注入
    private UseService useService;
    private UseConfiguration useConfiguration;


    public HelloController() {
    }

    public HelloController(UseService useService) {
        this.useService = useService;
    }

    @Autowired
    public HelloController(UseService useService, UseConfiguration useConfiguration) {
        this.useService = useService;
        this.useConfiguration = useConfiguration;
    }

    public void print(){
        System.out.println("controller");
        useService.print();
        useConfiguration.print();
    }
}

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UseService service=context.getBean(UseService.class);
        service.print();

        UserController userController=context.getBean(UserController.class);
        userController.print();
}

注:如果只要一个构造方法,在构造方法前不用加@Autowired,但是如果是多个构造方法,必须加@Autowired,否则无法识别用哪个构造方法

3.Setter注入

@Controller("controller")
public class HelloController {
        //Setter方法的注入
    private UseService useService;
    private UseConfiguration useConfiguration;

    @Autowired
    public void setUseService(UseService useService) {
        this.useService = useService;
    }

    @Autowired
    public void setUseConfiguration(UseConfiguration useConfiguration) {
        this.useConfiguration = useConfiguration;
    }

    public void print(){
        System.out.println("controller");
        useService.print();
        useConfiguration.print();
    }
}
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        UseService service=context.getBean(UseService.class);
        service.print();

        UserController userController=context.getBean(UserController.class);
        userController.print();
}

注:在每一Setter方法前都要加@Autowired注解

当同⼀类型存在多个bean时,使⽤@Autowired会存在问题

@Component
public class StudentComponent {

    @Bean
    public Student stu1(){
        return new Student("zs",12);
    }

    @Bean
    public Student stu2(){
        return new Student("xx",5);
    }

    @Bean(name={"stu4","stu5"})
    public Student stu3(){
        return new Student("lisi",14);
    }
}

@Controller
public class UserController {

    @Autowired
    private Student stu;


    public void print(){
        System.out.println("UserController");
        System.out.println();
    }
}

 就会报错,错误信息为不是唯一的bean

并且给你解决的方法,使用@Primary注解或者@Qualifier注解

@Primary

使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现

@Component
public class StudentComponent {

    @Primary
    @Bean
    public Student stu1(){
        return new Student("zs",12);
    }

    @Bean
    public Student stu2(){
        return new Student("xx",5);
    }

    @Bean(name={"stu4","stu5"})
    public Student stu3(){
        return new Student("lisi",14);
    }
}

@Qualifier

使⽤@Qualifier注解:指定当前要注⼊的bean对象。

注:@Qualifier注解不能单独使用,必须配合@Autowired注解使用。

@Controller
public class UserController {

    @Qualifier("stu1")
    @Autowired
    private Student stu;


    public void print(){
        System.out.println("UserController");
        System.out.println();
    }
}

@Resource

使用@Resource注解也可以解决这个问题

@Controller
public class UserController {

    @Resource(name = "stu1")
    private Student stu;


    public void print(){
        System.out.println("UserController");
        System.out.println();
    }
}

@Autowird与@Resource的区别

1.@Autowird是按类型注入,而@Resource是按名称进行注入。

2.@Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解

总结一下吧!

简单说一下Spring, Spring Boot和SpringMVC的关系以及区别

Spring 是基础框架Spring MVC 是 Spring 提供的一种 Web 开发方式(模块)Spring Boot 是简化 Spring 应用开发和部署的工具和框架(整合+自动配置)

我们可以把这三者的关系比作开一家餐厅

Spring就是这家餐厅的基础设施:桌子,椅子,电,水,人员管理。

Spring MVC就是这家餐厅的点餐系统和前台的服务人员。

Spring Boot就相当于这个餐厅的加盟系统,任何东西都给你提供好了,你只需要做菜和开门营业就行了。

希望能对大家有所帮助!!!

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

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

相关文章

Java数据结构第二十期:解构排序算法的艺术与科学(二)

专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、常见排序算法的实现 1.1. 直接选择排序 1.2. 堆排序 1.3. 冒泡排序 1.4. 快速排序 一、常见排序算法的实现 1.1. 直接选择排序 每⼀次从待排序的数据元素中选出最小的⼀个元素,存放在…

【算法day5】最长回文子串——马拉车算法

最长回文子串 给你一个字符串 s,找到 s 中最长的 回文 子串。 https://leetcode.cn/problems/longest-palindromic-substring/description/ 算法思路: class Solution { public:string longestPalindrome(string s) {int s_len s.size();string tmp …

《如何排查Linux系统平均负载过高》

【系统平均负载导读】何为系统平均负载?假设一台云服务主机,突然之间响应用户请求的时间变长了,那么这个时候应该如何去排查?带着这个问题,我们对“平均负载”展开深入的探讨和研究。 何为Linux系统的平均负载&#xf…

基于DeepSeek实现PDF嵌入SVG图片无损放大

1. PDF中效果图 2. 询问Deepseek进行代码书写,不断优化后结果 /*** SVG工具类,用于生成价格趋势的SVG图表*/ public class SvgUtils {// SVG画布尺寸private static final int WIDTH 800;private static final int HEIGHT 500;private static final i…

整型的不同类型和溢出

一、整数的不同类型 不同编程语言中的整数类型主要通过以下两个维度区分: 1. 存储大小 字节数:决定整数能表示的范围(如 1字节8位)。 常见类型: byte(1字节)、short(2字节&#x…

使用express创建服务器保存数据到mysql

创建数据库和表结构 CREATE DATABASE collect;USE collect;CREATE TABLE info (id int(11) NOT NULL AUTO_INCREMENT,create_date bigint(20) DEFAULT NULL COMMENT 时间,type varchar(20) DEFAULT NULL COMMENT 数据分类,text_value text COMMENT 内容,PRIMARY KEY (id) ) EN…

小程序 wxml 语法 —— 41列表渲染 - 进阶用法

这一节讲解列表渲染的两个进阶用法: 如果需要对默认的变量名和下标进行修改,可以使用 wx:for-item 和 wx:for-item: 使用 wx:for-item 可以指定数组当前元素的变量名使用 wx:for-index 可以指定数组当前下标的变量名 将 wx:for 用在 标签上&…

python语言总结(持续更新)

本文主要是总结各函数,简单的函数不会给予示例,如果在平日遇到一些新类型将会添加 基础知识 输入与输出 print([要输出的内容])输出函数 input([提示内容]如果输入提示内容会在交互界面显示,用以提示用户)输入函数 注释 # 单行注释符&…

FPGA学习篇——Verilog学习5(reg,wire区分及模块例化)

1 何时用reg,何时用wire? 这个我找了一些网上的各种资料,大概说一下自己的理解,可能还不太到位... wire相当于一根线,是实时传输的那种,而reg是一个寄存器,是可以存储数据的,需要立…

Redis 数据持久化之AOF

AOF(Append Only File) 以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换…

【芯片验证】verificationguide上的74道SystemVerilog面试题

诧异啊,像我这种没事在网上各处捡东西吃的人为什么之前一直没有用过verificationguide这个网站呢?总不能是大家都已经看过就留下我不知道吧。前几天在论坛上和朋友谈论验证面试题时才搜到这个网站的,感觉挺有意思: .: Verification Guide :.​verificationguide.com/https…

Java后端高频面经——计算机网络

TCP/IP四层模型?输入一个网址后发生了什么,以百度为例?(美团) (1)四层模型 应用层:支持 HTTP、SMTP 等最终用户进程传输层:处理主机到主机的通信(TCP、UDP&am…

面试题(二)--Object中的常见方法

Object Java的Object是所有Java类的父类,所有的Java类直接或者间接的继承了Object类,Object类位于java.lang包中(编译时自动导入),主要提供了11种方法。 /*** native 方法,用于返回当前运行时对象的 Class…

运行OpenManus项目(使用Conda)

部署本项目需要具备一定的基础:Linux基础、需要安装好Anaconda/Miniforge(Python可以不装好,直接新建虚拟环境的时候装好即可),如果不装Anaconda或者Miniforge,只装过Python,需要确保Python是3.…

设备管理系统功能与.NET+VUE(IVIEW)技术实现

在现代工业和商业环境中,设备管理系统(Equipment Management System,简称EMS)是确保设备高效运行和维护的关键工具。本文采用多租户设计的设备管理系统,基于.NET后端和VUE前端(使用IVIEW UI框架&#xff09…

数据类设计_图片类设计之2_无规则图类设计(前端架构基础)

前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 接续上一篇数据类设计_图片类设计之1_矩阵类设计(前端架构基础)-CSDN博客,讨论非规则图类型的设计 无规则图的简单定义 前面的矩阵类,有明显的特征:长,宽,行和…

aws(学习笔记第三十二课) 深入使用cdk(API Gateway + event bridge)

文章目录 aws(学习笔记第三十二课) 深入使用cdk学习内容:1. 使用aws API Gatewaylambda1.1. 以前的练习1.2. 使用cdk创建API Gateway lambda1.3. 确认cdk创建API Gateway lambda 2. 使用event bridge练习producer和consumer2.1. 代码链接2.2. 开始练习2.3. 代码部…

计算机视觉算法实战——老虎个体识别(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​ 1. 领域介绍 老虎个体识别是计算机视觉中的一个重要应用领域,旨在通过分析老虎的独特条纹图案,自动识别和区…

Qt添加MySql数据库驱动

文章目录 一. 安装MySql二.编译mysql动态链接库 Qt版本:5.14.2 MySql版本:8.0.41 一. 安装MySql 参考这里进行安装:https://blog.csdn.net/qq_30150579/article/details/146042922 将mysql安装目录里的bin,include和lib拷贝出来…

蓝桥杯备考:图论初解

1:图的定义 我们学了线性表和树的结构,那什么是图呢? 线性表是一个串一个是一对一的结构 树是一对多的,每个结点可以有多个孩子,但只能有一个父亲 而我们今天学的图!就是多对多的结构了 V表示的是图的顶点集…