当前位置: 首页 > news >正文

【Spring框架】SpringIOC

Spring 是一个开源的 Java 企业级应用开发框架,它的核心思想是简化 Java 开发,通过提供一系列组件和服务,解决了传统 Java 开发中代码耦合度高、配置复杂、测试困难等问题。Spring 框架包含多个模块,其中SpringIOC(Inverse of Control,控制反转) 是 Spring的核心思想,作用简单来说就是来创建对象获取对象的。

我们传统手动创建对象需要先new一个对象,再调用对象,而现在我们可以让Spring框架创建对象,需要用到对象时,通过Spring把对象给我们(前提是需要在 Spring 容器中配置或声明这个类,告诉容器需要管理该类的对象)。

下面我们来实际体会一下SpringIOC是如何创建对象获取对象的。

创建项目

首先创建maven项目,配置Maven环境

之后在pom.xml文件中导入相关依赖,其中springframework是当前spring主体框架,junit做测试

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope></dependency></dependencies>

传统方法创建获取对象

我们先来看一下传统创建对象、获取对象的方式,首先创建Demo类

public class Demo {public void hello(){System.out.println("Hello");}
}

之后创建Test类,创建Demo类的对象demo,调用hello方法,输出hello方法中的内容

public class Test {@org.junit.Testpublic void run(){Demo demo=new Demo();demo.hello();}
}

利用Spring IOC创建获取对象

我们想用Spring创建对象要怎么做呢?首先要进行一些配置,在resource中新建xml配置中的Spring配置文件

这个文件就是我们当前Spring的核心配置类,我们之后的配置在这里面进行

因为我们想要获取Demo类对象,所以对其进行配置,将创建Demo对象的权利交给Spring框架,其中id表示对象名,class是全类名、类所在路径,这样就能通过Spring框架拿对象

<!--将创建Demo对象的权利交给Spring框架-->
<!--Spring创建对象的能力,使用的是反射--><bean id="demo" class="com.qcby.Demo"/>

之后来看一下如何在测试类中调用利用Spring框架创建的对象

首先创建ApplicationContext对象,去读取Spring.xml文件,Spring.xml文件中创建了demo对象;然后调用getBean方法,通过Spring.xml文件中的id值直接获取demo对象

@org.junit.Test
public void run1(){ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");//强制类型转换Demo demo=(Demo) ac.getBean("demo");demo.hello();
}

其中在 Spring 中,调用ac.getBean("demo") 方法返回的是 Object 类型的对象,因为 Spring在设计时需要兼容各种类型的 Bean,无法在编译期确定具体返回类型。

而我们实际使用时需要的是特定类型(这里是 Demo 类型)的对象,以便调用其特有的方法和属性。因此需要进行强制类型转换,将 Object 类型转换为我们需要的 Demo 类型。

IOC容器提供了两种创建对象的方式,一种是通过ApplicationContext,一种是通过BeanFactory。

ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
BeanFactory ac=new ClassPathXmlApplicationContext("Spring.xml");

两者有什么区别呢?

BeanFactory:1.本身是Spring内部提供的一个接口,不提供给开发人员使用;2.加载配置文件时不会创建对象,只有调用时才创建对象。

ApplicationContext:1.是BeanFactory的一个子接口,提供更强大的功能,提供给开发人员使用;2.一进来就加载,加载时就会把对象创建出来。

使用Spring框架创建获取对象的原因

上面我们成功利用Spring框架创建获取了对象,实际上在Spring当中这叫做控制权反转----即将创建对象的权利交给Spring框架

为什么要将创建对象的权利交给Spring框架呢?目的是解除耦合性。耦合性(Coupling)是编程和系统设计中描述两个模块(或组件、类、函数等)之间依赖关系紧密程度的概念。

假设这里有三个类A/B/C,我们自己手动创建对象:A创建B对象,B创建C对象,C创建A对象,这样就形成了死循环死依赖,耦合性过高,使用过程中可能就会出现问题。

相反,Spring其实是把对象放在了一个容器中,这个容器就是IOC容器。Spring框架在一开始就创建好A/B/C三个类的对象放到IOC容器中,A/B/C需要对象时从其中拿就可以了,这样不会出现循环依赖的问题。

Spring对Bean(对象)的管理

Spring对Bean(对象)的管理分为:1.创建对象;2.注入属性(变量),也就是给变量赋值。

而创建对象和注入属性都有两种形式:1.基于xml配置的形式;2.基于注解的形式

基于xml配置的形式

创建对象

前面我们在Spring.xml文件中创建demo对象,就是创建对象基于xml配置的形式

注入属性

基于getset方法
给普通变量注入属性

我们创建一个User类,在Demo类中定义几个变量并加入get、set、toString方法,下一步来看看如何基于xml配置注入属性

package com.qcby;public class Demo {private String name;private int age;private String sex;//对象private User user;@Overridepublic String toString() {return "Demo{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +", user=" + user +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}public void hello(){System.out.println("Hello");}
}

我们在Spring.xml文件中使用property注入属性,name:类当中的属性名称 value:注入的值,其中user变量因为是引用的对象,所以需要额外创建一下user对象,再通过property注入name属性名称和ref:对象映射

映射(Mapping)简单来说,就是建立两种事物之间的对应关系,让一方能通过这种关系找到或关联到另一方。

<!--    将创建Demo对象的权利交给Spring框架--><!--Spring创建对象的能力,使用的是反射--><bean id="demo" class="com.qcby.Demo">
<!--        使用property注入属性 name:类当中的属性名称 value:注入的值 ref:对象映射--><property name="name" value="张三"/><property name="age" value="18"/><property name="sex" value="男"/><property name="user" ref="user"/></bean><bean id="user" class="com.qcby.User"/>
</beans>

之后我们在测试类中看看能否获取到注入的属性,可以看到能够正常输出

@org.junit.Testpublic void run1(){ApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
//        BeanFactory ac=new ClassPathXmlApplicationContext("Spring.xml");Demo demo= (Demo) ac.getBean("demo");System.out.println(demo.toString());}

给集合注入属性

前面我们给一些普通的变量成功注入属性,那如果是集合呢?

private String[] address;
private List<String> phone;
private Map<String,String> map;

在xml文件中我们需要这样配置:

String类型的集合本质是是数组,我们用array包住要传输的value值;

List集合用list标签包住;

Map集合用map标签包住,同时因为map集合内是key-value类型的数据,所以还需要用到entry标签

 <property name="address"><array><value>北京</value><value>上海</value><value>广州</value></array></property><property name="phone"><list><value>123456</value><value>456789</value></list></property><property name="map"><map><entry key="1" value="张三"/><entry key="2" value="李四"/></map></property>
</bean>

我们运行一下,属性也是能够正常获取到的

基于构造函数的方式

我们还可以利用构造器注入属性,首先在User类中添加一下构造方法

添加之后就会发现,Spring.xml文件中demo对象的class路径发生了报错,这是为什么呢?

我们前面说到Spring创建对象的能力利用的是反射,反射创建对象第一步:获取构造函数,第二步:利用构造函数生成对象

其中,在之前利用的构造函数是User类默认的无参构造函数,我们自己加入构造函数导致无参构造函数被覆盖,因此发生报错。

所以我们需要更改一下xml文件中的配置,将property标签改为constructor-arg标签,用于配置 Bean 的构造方法参数

<bean id="demo" class="com.qcby.Demo"><constructor-arg name="name" value="张三"/><constructor-arg name="age" value="18"/><constructor-arg name="sex" value="男"/><constructor-arg name="user" ref="user"/><constructor-arg name="address"><array><value>北京</value><value>上海</value><value>广州</value></array></constructor-arg><constructor-arg name="phone"><list><value>123456</value><value>456789</value></list></constructor-arg><constructor-arg name="map"><map><entry key="1" value="张三"/><entry key="2" value="李四"/></map></constructor-arg></bean><bean id="user" class="com.qcby.User"/>

之后就能正常运行了

基于注解的形式

什么是注解?

以@WebServlet("/aa")为例,aa配置的就是当前的路径。注解我们可以理解为是当前代码的注释,是对当前程序功能的一个解释

创建对象

Spring创建对象的几个常用注解:

@Controller  @Service

@Component  @Repository

它们的功能体现在Spring当中不区分,但是在其他框架当中是有区分的

我们创建几个类,分别运用几个注解,其中(value = "demo")表示对象名是demo

之后在xml配置文件中配置注解的扫描工作

<context:component-scan base-package="com.qcby"/>

ClassPathXmlApplicationContext类创建对象,专门读取xml文件配置

 @org.junit.Testpublic void run1(){ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
//        BeanFactory ac=new ClassPathXmlApplicationContext("Spring.xml");Demo demo= (Demo) ac.getBean("demo");demo.run();Animal animal= (Animal) ac.getBean("animal");animal.run();Person person= (Person) ac.getBean("per");person.run();User user= (User) ac.getBean("us");user.run();}

依旧能够获取对象

注入属性

String提供的注解:

@Value 注入普通类型的数据 (String+基本数据类型+包装类

@Autowired 按默认类型自动装配(引用数据类型

@Qualifier 不能单独使用,必须和@Autowired一起使用,强制使用名称注入(因为Autowired能单独用,所以这个很少用)

Java提供的注解:

@Resource 使用name属性,按名称注入

我们来测试一下:

输出:

注意:注解无法给数组注入值

纯注解开发

前面我们使用注解开发需要在xml文件中配置注解的扫描工作,而除了这种方式,我们也可以专门准备一个config配置注解类

@Configuration表明是一个配置类,@ComponentScan表示扫描工作,(basePackages)中写好扫描具体的包

之后我们把xml文件中的配置删除,测试类中重新创建一下专门读取config配置类的对象

// 专门读取xml文件配置
//ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("Spring.xml");
//专门读取config文件配置
ApplicationContext ac=new AnnotationConfigApplicationContext(config.class);

依旧正常输出:

http://www.lryc.cn/news/621702.html

相关文章:

  • 代码随想录二刷之“字符串”~GO
  • 状态管理中应用进程和宿主进程的概念及相互关系
  • 初识CNN02——认识CNN2
  • Jeecg后端经验汇总
  • redis-sentinel基础概念及部署
  • JVM执行引擎深入理解
  • 异步开发:协程、线程、Unitask
  • 关于C++的#include的超超超详细讲解
  • LCR 076. 数组中的第 K 个最大元素
  • IStoreOS(OpenWrt)开启IPV6
  • 【已解决】在Spring Boot工程中,若未识别到resources/db文件夹下的SQL文件
  • 10--C++模板参数与特化详解
  • Linux Namespace隔离实战:dd/mkfs/mount/unshare构建终极沙箱
  • 基于CodeBuddy的2D游戏开发实践:炫酷大便超人核心机制解析
  • 云手机存储和本地存储的区别
  • Ant-Design AUpload如何显示缩略图;自定义哪些类型的数据可以使用img预览
  • 用3D打印重新定义骑行-中科米堆CASAIM自行车座椅个性化设计
  • Spring Ai 如何配置以及如何搭建
  • Cursor CLI 技术解析:免费调用 GPT-5 的命令行方案
  • Flink的状态管理
  • 项目篇------------网页五子棋(知识预备)
  • GPT 解码策略全解析:从 Beam Search 到 Top-p 采样
  • spring ai-openai-vl模型应用qwen-vl\gpt-文字识别-java
  • 自学大语言模型之Transformer的Tokenizer
  • 用GPT解释“GPT-5”是什么,有什么优势
  • Spring IOC容器在Web环境中的启动奥秘:深入源码解析
  • Grafana 与 InfluxDB 可视化深度集成(一)
  • Al大模型-本地私有化部署大模型-大模型微调
  • 算法学习远程访问:借助 cpolar 内网穿透服务使用 Hello-Algo
  • 以下是对智能电梯控制系统功能及系统云端平台设计要点的详细分析,结合用户提供的梯控系统网络架构设计和系统软硬件组成,分点论述并补充关键要点: