【Spring】——Spring概述、IOC、IOC创建对象的方式、Spring配置、依赖注入(DI)以及自动装配知识

🎼个人主页:【Y小夜】

😎作者简介:一位双非学校的大二学生,编程爱好者,

专注于基础和实战分享,欢迎私信咨询!

🎆入门专栏:🎇【 MySQLJava基础Rust

🎈热门专栏:🎊【 PythonJavawebVue框架

++感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️++

目录

[🎯 Spring概述](#🎯 Spring概述)

😎Spring简介

😎优缺点

😎组成

[🎯 IOC](#🎯 IOC)

😎本质

🎯IOC创建对象方式

😎无参构造

😎有参构造方法

🎯Spring配置

😎Bean的配置

🎯依赖注入(DI)

😎set注入

✨Bean注入

[✨ 数组注入](#✨ 数组注入)

✨List注入

✨Map注入

✨set注入

😎Bean的作用域

✨Singleton模式

😎Prototype模式

🎯自动装配

😎重点

😎byName

😎byType

😎使用注解

✨Autowired

✨Qualifier

✨@Resource

😎小结


🎯 Spring概述

😎Spring简介

Spring是一个轻量级、开源的Java EE应用程序框架,旨在解决企业级应用开发的复杂性,提供一种快速、可重用、易于测试的开发模式

Spring由Rod Johnson在2002年发起,并在2004年正式发布了1.0版本。它通过其核心功能------控制反转(IoC)和面向切面编程(AOP),极大地简化了Java应用的开发过程。

作为一个分层架构的全栈框架,Spring包含多个模块,从数据访问到业务层,再到表现层,几乎涵盖了开发过程中的所有方面。其中,Core Container是整个框架的基础,包括BeanFactory接口和上下文模块。BeanFactory使用控制反转模式,将对象的创建和管理交由Spring容器负责,从而降低了应用组件之间的耦合度。

Spring的AOP模块则提供了强大的支持,允许开发者在不修改原有业务逻辑的情况下,添加或修改系统级别的服务,如事务管理和安全控制。这使得代码的可重用性和可测试性得到了显著提升。

😎优缺点

  • 优点
    1. 方便解耦:通过Spring提供的IoC(控制反转)容器,对象的依赖关系可以交由Spring进行控制,避免硬编码所造成的过度耦合。这样,开发者可以更专注于业务逻辑的设计和实现。
    2. 面向切面编程:Spring的AOP(面向切面编程)功能,使开发者能够以声明式方式进行事务管理、权限拦截和运行监控等功能,显著提高开发效率和质量。
    3. 声明式事务支持:Spring提供了强大的声明式事务管理支持,使得原本繁琐的事务管理代码变得简单且易于维护。
    4. 集成各种框架:Spring可以与Struts、Hibernate、MyBatis等多种优秀的开源框架无缝集成,降低这些框架的使用难度,提升整体开发效率。
    5. 降低API使用难度:Spring对JavaEE API(如JDBC、JavaMail等)进行了薄薄的封装层,使得这些API的使用难度大为降低。
  • 缺点
    1. 学习曲线陡峭:Spring框架功能强大且内容丰富,涉及众多概念和技术,初学者需要花费大量时间来掌握。
    2. 配置文件较多:Spring需要管理多个配置文件,如果设置不当,可能导致应用程序出现各种问题,排查和修复这些问题可能比较麻烦。
    3. 运行效率相对较低:由于Spring提供了丰富的功能和组件,其运行效率可能低于一些轻量级框架,但在现代计算机硬件的支持下,这种差异通常可以忽略不计。
    4. 代码量较大:使用Spring意味着需要编写和维护更多的代码,这可能会增加项目的复杂度和维护难度。
    5. 版本更新较快:Spring的版本更新频繁,新版本可能引入新功能同时废弃旧功能,这要求开发者不断适应和学习。

😎组成


Spring 框架是一个分层架构,由 7 个定义良好的模块组成。 Spring 模块构建在核心容器之上,核心容器 定义了创建、配置和管理 bean 的方式 .

  1. 核心容器
    • spring-core模块:提供框架的基本组成部分,包括控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)功能。
    • spring-beans模块:提供BeanFactory,管理被称为"Bean"的对象。
    • spring-context模块:建立在Core和Beans模块之上,提供对象访问方式,并通过ApplicationContext接口进行访问。
    • spring-context-support模块:整合第三方库到Spring应用程序上下文,支持高速缓存和任务调度。
    • spring-expression模块:提供表达式语言以支持运行时查询和操作对象图。
  2. AOP和仪器支持
    • spring-aop模块:提供面向切面的编程实现,允许定义方法拦截器和切入点。
    • spring-aspects模块:与AspectJ集成,一个成熟的AOP框架。
    • spring-instrument模块:提供类植入支持和特定应用服务器中的类加载器实现。
  3. 数据访问与集成
    • spring-jdbc模块:提供JDBC抽象层,简化数据库操作。
    • spring-orm模块:集成Hibernate、JPA和JDO等ORM框架。
    • spring-oxm模块:提供Object-to-XML-Mapping的抽象层。
    • spring-jms模块:包含生产和使用消息的功能,自Spring4.1起,与spring-messaging模块集成。
    • spring-tx模块:事务模块,支持编程和声明式事务管理。
  4. Web
    • spring-websocket模块:实现双工异步通讯协议,提供Socket通信和推送功能。
    • spring-webmvc模块:包含Spring MVC和REST Web Services实现。
    • spring-web模块:提供基本Web开发集成功能,如文件上传支持和Filter类。
  5. 消息
    • spring-messaging模块:自Spring4.0新增,提供消息传递体系结构和协议支持。
  6. 测试
    • spring-test模块:支持使用JUnit或TestNG对Spring组件进行单元和集成测试。

🎯 IOC

😎本质

控制反转IoC(Inversion of Control) ,是一种设计思想, DI( 依赖注入 ) 是实现 IoC 的一种方法 ,也有人认 为DI 只是 IoC 的另一种说法。没有 IoC 的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系 完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为 所谓控制反转就是:获得依赖对象的方式反转了。

控制反转是一种通过描述(XML 或注解)并通过第三方去生产或获取特定对象的方式。在 Spring 中实现 控制反转的是 IoC 容器,其实现方法是依赖注入( Dependency Injection,DI )。

🎯IOC****创建对象方式

😎无参构造

实体类

java 复制代码
public class User {
private String name;
public User() {
System.out.println("user无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}

XML文件

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">
<bean id="user" class="com.aaa.pojo.User">
<property name="name" value="kkk"/>
</bean>
</beans>

测试类

java 复制代码
@Test
public void test(){
ApplicationContext context = new
ClassPathXmlApplicationContext("beans.xml");
//在执行getBean的时候, user已经创建好了 , 通过无参构造
User user = (User) context.getBean("user");
//调用对象的方法 .
user.show();
}

😎有参构造方法

java 复制代码
public class UserT {
private String name;
public UserT(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}

beans.xml 有三种方式编写

XML 复制代码
<!-- 第一种根据index参数下标设置 -->
<bean id="userT" class="com.aaa.pojo.UserT">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="aaa"/>
</bean>
XML 复制代码
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.aaa.pojo.UserT">
<!-- name指参数名 -->
<constructor-arg name="name" value="aaa"/>
</bean>
XML 复制代码
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.aaa.pojo.UserT">
<constructor-arg type="java.lang.String" value="aaa"/>
</bean>

🎯Spring配置

😎Bean****的配置

XML 复制代码
<!--bean就是java对象,由Spring创建和管理-->
<!--
id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
如果配置id,又配置了name,那么name是别名
name可以设置多个别名,可以用逗号,分号,空格隔开
如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;
class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.aaa.pojo.Hello">
<prop

🎯依赖注入(DI

依赖注入(DI)是一种通过将对象间的依赖关系转移给外部容器来管理的设计模式,以减少对象间的耦合性并提高代码的可重用性和可维护性

在软件开发中,依赖注入主要解决的是对象之间复杂的依赖关系,以及如何将这些依赖关系管理得更加灵活和可扩展。通过将对象的创建和依赖关系的管理交给外部容器,依赖注入不仅降低了组件之间的耦合度,还提高了系统的可测试性和灵活性。

😎set****注入

常量注入

XML 复制代码
<bean id="student" class="com.aaa.pojo.Student">
<property name="name" value="小明"/>
</bean>

测试

java 复制代码
@Test
public void test01(){
ApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}

Bean****注入

注意点:这里的值是一个引用, ref

XML 复制代码
<bean id="addr" class="com.aaa.pojo.Address">
<property name="address" value="重庆"/>
</bean>
<bean id="student" class="com.aaa.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
</bean>

数组注入

XML 复制代码
<bean id="student" class="com.aaa.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
</bean>

✨List****注入

XML 复制代码
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>爬山</value>
</list>
</property>

✨Map****注入

XML 复制代码
<property name="card">
<map>
<entry key="中国邮政" value="456456456465456"/>
<entry key="建设" value="1456682255511"/>
</map>
</property>

✨set****注入

XML 复制代码
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>

😎Bean****的作用域

✨Singleton模式

当一个bean 的作用域为 Singleton ,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。 Singleton是单例类型,就是 在创建起容器时就同时自动创建了一个bean **的对象,不管你是否使用,他都存在了,每次获取到的对象 都是同一个对象。**注意,Singleton 作用域是 Spring 中的缺省作用域。要在 XML 中将 bean 定义成 singleton,可以这样配置:

XML 复制代码
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

😎Prototype模式

当一个bean 的作用域为 Prototype ,表示一个 bean 定义对应多个对象实例。 Prototype作用域的bean会 导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。 Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是 当我们获取bean 的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经 验,对有状态的bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。在 XML中将 bean 定义成 prototype ,可以这样配置:

XML 复制代码
<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>

🎯自动装配

😎重点

  • 自动装配是使用spring满足bean依赖的一种方法
  • spring会在应用上下文中为某个bean寻找其依赖的bean。

Spring 中 bean 有三种装配机制,分别是:

  1. 在 xml 中显式配置;
  2. 在 java 中显式配置;
  3. 隐式的 bean 发现机制和自动装配。
    这里我们主要讲第三种:自动化的装配 bean 。
    Spring 的自动装配需要从两个角度来实现,或者说是两个操作:
  • 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
  • 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

组件扫描和自动装配组合发挥巨大威力,使的显示的配置降低到最少。
推荐不使用自动装配 xml 配置 , 而使用注解

😎byName

autowire byName (按名称自动装配 )
由于在手动配置xml 过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。
采用自动装配将避免这些错误,并且使配置简单化。
测试:

  1. 修改 bean 配置,增加一个属性 autowire="byName"
XML 复制代码
<bean id="user" class="com.aaa.pojo.User" autowire="byName">
<property name="str" value="qinjiang"/>
</bean>

当一个 bean 节点带有 autowire byName 的属性时。

  1. 将查找其类中所有的 set 方法名,例如 setCat ,获得将 set 去掉并且首字母小写的字符串,即 cat 。
  2. 去 spring 容器中寻找是否有此字符串名称 id 的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常。

😎byType

autowire byType ( 按类型自动装配 )
使用 autowire byType 首先需要保证:同一类型的对象,在 spring 容器中唯一。如果不唯一,会报不唯一 的异常。
测试:

XML 复制代码
<bean id="dog" class="com.aaa.pojo.Dog"/>
<bean id="cat" class="com.aaa.pojo.Cat"/>
<bean id="cat2" class="com.aaa.pojo.Cat"/>
<bean id="user" class="com.aaa.pojo.User" autowire="byType">
<property name="str" value="qinjiang"/>
</bean>

😎使用注解

**✨**Autowired

@Autowired 是按类型自动转配的,不支持 id 匹配。
需要导入 spring-aop 的包!

XML 复制代码
<context:annotation-config/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
java 复制代码
@Autowired(required = false)
private Cat cat;

✨Qualifier

@Autowired 是根据类型自动装配的,加上 @Qualifier 则可以根据 byName 的方式自动装配
@Qualifier 不能单独使用。

java 复制代码
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

@Resource

@Resource 如有指定的 name 属性,先按该属性进行 byName 方式查找装配;
其次再进行默认的 byName 方式进行装配;
如果以上都不成功,则按 byType 的方式自动装配。
都不成功,则报异常。

java 复制代码
@Resource
private Cat cat;
@Resource
private Dog dog;

😎小结

@Autowired与@Resource异同:

  1. @Autowired与 @Resource 都可以用来装配 bean 。都可以写在字段上,或写在 setter 方法上。
  2. @Autowired默认按类型装配(属于 spring 规范),默认情况下必须要求依赖对象必须存在,如果 要允许null 值,可以设置它的 required 属性为 false ,如: @Autowired(required=false) ,如果我 们想使用名称装配可以结合@Qualifier 注解进行使用
  3. @Resource(属于 J2EE 复返),默认按照名称进行装配,名称可以通过 name 属性进行指定。如果 没有指定name 属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在 setter方法上默认取属性名进行装配。 当找不到与名称匹配的 bean 时才按照类型进行装配。但是 需要注意的是,如果name 属性一旦指定,就只会按照名称进行装配。
    它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired 先byType,@Resource先 byName。
相关推荐
尚学教辅学习资料7 分钟前
基于SpringBoot的医药管理系统+LW示例参考
java·spring boot·后端·java毕业设计·医药管理
雷神乐乐23 分钟前
File.separator与File.separatorChar的区别
java·路径分隔符
小刘|28 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
逊嘘1 小时前
【Java语言】抽象类与接口
java·开发语言·jvm
morris1311 小时前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
monkey_meng1 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马1 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员1 小时前
java导出word文件(手绘)
java·开发语言·word