Spring—IoC

目录

1. IoC的提出

2. Spring容器

2.1. Spring容器实现原理

2.2. Spring组件

2.2.1 XML标签方式

2.2.2. 类注解方式

2.2.3. 方法注解方式

2.3. Spring容器分类

2.3.1. BeanFactory容器

2.3.2. ApplicationContext容器

2.3.3. WebApplicationContext容器

3. Spring中的常用注解


1. IoC的提出

       在采用面向对象方法设计的软件系统中,底层实现是由一组对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。对象之间的耦合关系就像手表齿轮的啮合,彼此之间存在复杂依赖关系,往往牵一发而动全身,如图1所示。因此,如何降低系统之间、模块之间和对象之间的耦合度,是软件工程追求的目标之一1996年,软件专家Michael mattson首次提出了控制反转(Inversion of Control, IoC)概念。控制反转的核心思想是:借助于“第三方(IoC容器)” 实现具有依赖关系的对象之间的解耦,如图2所示。

图1. 传统面向对象系统

图2. 使用IoC容器的面向对象系统

        在使用IoC容器的面向对象系统中,全部对象的控制权都交给IoC容器来管理,所以,IoC容器成为整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用。

       2004年,Martin Fowler探讨了同一个问题,既然IoC是控制反转,那么到底是“哪些方面的控制被反转了呢”?最后,他得出结论是“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为由IoC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection, DI)”。所以,依赖注入(DI)和控制反转(IoC)是从不同的角度来描述同一件事情,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦。

2. Spring容器

       Spring容器是Spring框架的核心,它是一种IoC容器,负责管理应用程序中对象的生命周期和依赖关系。Spring容器通过读取Spring组件的元数据((XML文件、注解或Java配置))来创建、配置、装配并管理应用程序中的对象。

2.1. Spring容器实现原理

        实现Spring容器的最主要技术是Java反射编程Java的反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。简单来说,只要给定类的名字,就可以通过反射机制来获得类的所有信息。Spring容器的工作模式可以看作是工厂模式的升华。可以把Spring容器看作是一个对象工厂,这个工厂里要生产的对象都在元数据中给出定义,然后利用反射编程,根据元数据(XML文件、注解或Java配置)中给出的类名生成相应的对象。从实现来看,Spring是把工厂模式里写死的对象生成代码,改变为由元数据来定义,也就是把工厂和对象生成这两者独立离开来,目的是提高灵活性和可维护性。Spring容器的实现原理如图3所示。

  图3. Spring容器实现原理

2.2. Spring组件

      纳入Spring容器管理的Java类称为Spring组件(简称组件),Spring容器对组件进行实例化所创建的对象称为Bean。一个Java类可以标识为多个Spring组件,每个Spring组件可以创建一个或多个Bean。定义Spring组件主要有三种方式:XML标签、类注解和方法注解。

2.2.1 XML标签方式

       该方式通过在XML配置文件中使用<bean>标签来定义Spring组件。下面通过一个例子来说明如何通过<bean>标签来定义组件和创建Bean。

(1)类的定义

          在包com.my.examples.example1中定义Java类Login和User,类的声明如下:

package com.my.examples.example1;public class Login {String username;String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
package com.my.examples.example1;public class User {Login login;public void print(){System.out.println("login user: "+login.getUsername());}public Login getLogin() {return login;}public void setLogin(Login login) {this.login = login;}
}

 (2)Spring组件定义

        在项目的resources目录下创建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"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 定义Spring组件 --><bean id="login" class="com.my.examples.example1.Login"><!--为属性code和name注入初始值 --><property name="username" value="admin"></property><property name="password" value="123456"></property></bean><bean id="currentUser" class="com.my.examples.example1.User"><!-- 为属性login注入引用值(Spring组件login) --><property name="login" ref="login"></property></bean>
</beans>

(3)配置Spring应用上下文

       根据XML配置文件创建Spring容器,利用容器所提供的getBean()方法获取相应的Bean,从容中获取Bean后就可以调用其方法来执行。

package com.my.examples.example1;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {//根据XML配置文件创建Spring容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//获取Spring容器中的BeanLogin login= context.getBean("login", Login.class);User user=context.getBean("currentUser", User.class);user.print();}
}

运行类Test,在控制台中输出如下信息:

login user: admin

2.2.2. 类注解方式

       该方式通过@Component、@Respository、@Service、@Controller注解来定义Spring组件,利用Java配置类(用@Configuration注解定义的类)代替XML配置文件。@Component注解用于标识一个类为Spring组件,当Spring框架扫描到该注解时,会创建该类的实例并纳入Spring容器中管理。@Respository、@Service、@Controller都是@Component注解的特殊形式,分别用于标识数据访问层、服务层和控制层的Spring组件。

      下面将2.1.1节中的例子改为类注解方式。

(1)Spring组件的定义

      在包com.my.examples.example2中定义Java类Login和User,在类上加入@Component注解使其成为Spring组件。

package com.my.examples.example2;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;@Component  //定义Spring组件
@PropertySource("classpath:my-config.properties") //引入外部属性文件
public class Login {@Value("${my.username}")  //注入属性文件中的account值String username;@Value("${my.password}")  //注入属性文件中的password值String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
package com.my.examples.example2;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component   //定义Spring组件
public class User {@Autowired  //注入注入依赖的Spring组件的BeanLogin login;public void print(){System.out.println("login user: "+login.getUsername());}
}

       @PropertySource注解的功能是引入外部属性文件:my-config.properties,该文件位于项目的resources目录下,文件的内容如下:

my.username=admin
my.password=123456

(2)Java配置类的定义

      在包com.my.examples.example2中定义类Config,在该类上加入@Configuraton注解使其成为Java配置类。在该配置类上加入@ComponentScan注解,其功能是让Spring容器扫描com.my.examples.example2包及其子包下面所有的Spring组件,并将这些组件进行例化为Bean。

package com.my.examples.example2;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration   //定义Java配置类
//扫描包com.my.examples.example2及其子包下面的所有Spring组件
@ComponentScan("com.my.examples.example2")
public class Config {
}

(3)配置Spring应用上下文

      根据Java配置类创建Spring容器,利用容器提供的getBean()方法获取相应的Bean,调用Bean提供的方法来执行任务。

package com.my.examples.example2;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Test {public static void main(String[] args) {//根据Java配置类创建Spring容器AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(Config.class);//获取容器中的BeanLogin login=context.getBean(Login.class);User user=context.getBean(User.class);user.print();}
}

运行类Test,在控制台中输出如下内容:

login user: admin

2.2.3. 方法注解方式

       该方式不需要在类上加入@Component等注解来定义Spring组件,而是通过在Java配置类中的方法上加入@Bean注解,该方法的返回值是一个Spring组件的Bean。

      下面把第2.1.2节中的应用改为采用Java配置的方式来实现。

(1)类的定义

       在包com.my.examples.example3中定义Java类Login和User。

package com.my.examples.example3;public class Login {String username;String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
package com.my.examples.example3;public class User {Login login;public void print(){System.out.println("login user: "+login.getUsername());}public Login getLogin() {return login;}public void setLogin(Login login) {this.login = login;}
}

(2)定义Java配置类

package com.my.examples.example3;import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;@Configuration   //定义Java配置类
//扫描包com.my.examples.example3及其子包下面的所有Spring组件
@ComponentScan("com.my.examples.example3")
@PropertySource("classpath:my-config.properties") //引入外部属性文件
public class Config {@Value("${my.username}")String username;@Value("${my.password}")String password;@Bean    //定义Spring组件并返回Beanpublic Login login(){Login login = new Login();//注入属性值login.setUsername(username);login.setPassword(password);return login;}@Bean   //定义Spring组件并返回Beanpublic User user(){User user = new User();//注入组件Login的Bean时,直接调用方法login()user.setLogin(login());return user;}
}

(3)配置Spring应用上下文

       根据Java配置类创建Spring容器,根据容器提供的getBean()方法获取相应的Bean,调用Bean的方法执行任务。

package com.my.examples.example3;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Test {public static void main(String[] args) {//根据Java配置类创建Spring容器AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(Config.class);//获取容器中的BeanLogin login = context.getBean(Login.class);User user = context.getBean(User.class);user.print();}
}

运行类Test,在控制台中输出如下内容:

login user: admin

2.3. Spring容器分类

     Spring框架主要提供三种类型的容器:BeanFactory容器、ApplicationContext容器和WebApplicationContext

2.3.1. BeanFactory容器

       BeanFactory是Spring框架中用于管理 Bean的最基本接口,它提供了一系列用于获取Bean和管理 Bean依赖的方法。BeanFactory使用懒加载方式,即只有在需要时才创建和配置bean。

       BeanFactory接口包含的的主要方法:

  • Object getBean(String name):根据bean的名称在Spring容器中获取对应的Bean实例。
  • Object getBean(String name, Object... args):根据 Bean 的名称和给定的构造函数参数获取一个 Bean 实例。
  • boolean containsBean(String name):判断Spring容器中是否包含指定名称的bean。
  • boolean isSingleton(String name):判断指定名称的bean是否是单例。
  • boolean isPrototype(String name):判断指定名称的bean是否是原型。

     BeanFactory接口的主要实现类:

  • XmlBeanFactory:这是一个简单的实现,它从 XML 文件中加载 Bean 定义,从 Spring 3.1 开始,该类已被标记为过时。
  • DefaultListableBeanFactory:它提供了一套完整的服务来管理不同的 Bean,包括注册 Bean、解析依赖、管理 Bean 生命周期、以及提供不同的 Bean 作用域等。

2.3.2. ApplicationContext容器

       ApplicationContext是BeanFactory的子接口,它在BeanFactory的基础上增加了更多的功能。除了提供BeanFactory的所有功能外,ApplicationContext还提供了更多企业特定的功能,如国际化支持、事件发布、应用层特定的上下文等。ApplicationContext在容器启动时就创建和配置所有的单例bean,提供了更多的高级特性。

      ApplicationContext接口的主要实现类:

  • ClassPathXmlApplicationContext:从类路径下的XML文件加载Spring应用上下文。这是在传统的 Spring 应用中常见的一种方式,适合那些配置存储在项目内部的XML文件中的应用。
  • FileSystemXmlApplicationContext:从文件系统指定的位置的XML文件加载Spring应用上下文。这种方式适用于需要从外部文件系统(而非类路径)加载配置的场景。
  • AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。这种方式专门为基于Java注解的配置提供支持。

2.3.3. WebApplicationContext容器

       WebApplicationContext是专门为 Web 应用程序设计的,它扩展了 ApplicationContext 接口,添加了一些针对Web环境的特定功能。WebApplicationContext通常在基于Spring的Web应用程序中使用,特别是在使用Spring MVC框架时,它通常在web.xml文件中配置,或者通过Spring 的WebApplicationInitializer接口在Java配置中启动。

       WebApplicationContext接口的主要实现类:

  • XmlWebApplicationContext:从XML文件加载配置的Web应用上下文,这是一个传统的方法,适合那些已经使用XML配置文件的项目。
  • AnnotationConfigWebApplicationContext:支持基于Java注解的配置,允许通过Java代码直接配置Spring,使得配置更加直观和类型安全。

3. Spring中的常用注解

      在Spring框架中,与Spring容器相关的注解如下表。

注解功能
@Component

通用注解,用于标识一个类为Spring组件,当Spring框架扫描到该注解时,会创建该类的实例并纳入Spring容器管理。

@Respository、@Service、@Controller都是这个注解的特殊形式,分别用于标识数据访问层、服务层和控制层的Spring组件。

@Respository该注解用于标注数据访问层组件,数据访问层组件通常用于数据操作。
@Service

该注解用于标注服务层组件,服务层组件通常用于业务逻辑处理。

@Controller

该注解用于标注控制层组件,控制层组件通常用于处理HTTP请求。

@Autowired

自动装配注解,它可以放在类的成员变量、方法以及构造方法上,用于自动注入依赖,@Autowired是按照类型注入依赖,如果想要按照名称来注入依赖,则需要结合@Qualifier注解一起使用。

@Resource与@Autowired功能一样,区别在于该注解默认是按照名称来注入依赖,只有当找不到与名称匹配的Bean时才会按照类型来注入依赖
@Qualifier与@Autowired一起使用,用于指定要注入的Bean的名称
@Configuration用于定义配置类,可替代XML文件,类中的方法可以使用@Bean注解,以声明Spring容器管理的Bean。
@Bean用于标识一个方法,该方法返回一个Bean实例,并将其注册到Spring容器中。
@Scope

用于指定Bean的作用域,分为如下几种:

1)singleton(单例):只创建一个Bean,这是默认的作用域,适用于无状态Bean,比如服务层Bean、数据访问层Bean;

2)prototype(原型):每次请求(通过getBean方法)都会创建一个新的Bean,适用于有状态的Bean;

3)request(请求):在Web应用中,每一次HTTP请求都会产生一个新的Bean,该Bean仅在当前HTTP请求内有效;

4)session(会话):在Web应用中,每个HTTP会话都会创建一个新的Bean,该请求仅在当前HTTP会话内有效;

5)global-session(全局会话):仅在Portlet应用中使用,每个全局HTTP会话会创建一个Bean,适用于需要在全局HTTP会话期间保持状态的Bean。

6)application(应用):在整个ServletContext范围内,Bean都是单例的,适用于需要在整个Web用用范围内共享的Bean。

@Value用于注入简单类型的属性值,如字符串、数字等。
@Async用于标识一个方法或类,表示其中的操作应该异步执行。
@PostConstruct用于标识一个方法,该方法在Bean实例化后自动执行,用于初始化操作。
@PreDestroy用于标识一个方法,该方法在Bean销毁前自动执行,用于清理操作。

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

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

相关文章

Srping 历史

一、History of Spring and the Spring Framework Spring came into being in 2003 as a response to the complexity of the early J2EE specifications. While some consider Java EE and its modern-day successor Jakarta EE to be in competition with Spring, they are …

idea启动报错:java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory

文章目录 一、问题二、解决方法 一、问题 问题描述&#xff1a;idea整合Mybatis-plus的时候&#xff0c;启动报错&#xff1a;java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory 二、解决方法 可能原因&#xff1a;仔细检查了一下&#xff0c;发现 mybati…

《王者荣耀》4月狂揽2.34亿美元 单日流水1亿美元 全球销量第二

易采游戏网5月24日消息&#xff0c;在刚刚过去的四月&#xff0c;全球手游市场迎来了一场收益的盛宴&#xff0c;其中《王者荣耀》以其惊人的吸金能力&#xff0c;以2.34亿美元的月收入在全球手游排行榜上位列第二。4月5日&#xff0c;这款由腾讯游戏开发的多人在线战斗竞技游戏…

C++相关概念和易错语法(14)(初始化注意事项、vector、编译器向上查找规则)

1.当我们在代码中想要终止运行的话&#xff0c;我们可以采用Ctrl C或Ctrl Z&#xff0c;其中^C代表杀进程&#xff0c;^Z设置结束2.编码表&#xff1a;我们目前比较熟悉的是ASCII码编码方式&#xff0c;但是我们发现平时使用的汉字无法通过ASCII编码&#xff0c;除此之外&…

自动化测试用例结构

标准的用例结构&#xff1a; 用力标题前提条件用例步骤预期结果实际结果 测试用例对比&#xff1a;

酷开系统 | 酷开科技把握智慧先机 AI赋能家庭场景

智慧化是当今世界科技发展的前沿领域之一。现在的智慧化&#xff0c;也正在逐步成为我们日常生活的一部分。电视系统也进入了数字化时代&#xff0c;AI的应用正在不断扩展&#xff0c;其潜力似乎无穷无尽。 酷开科技深耕人工智能技术&#xff0c;在提升语音体验、强化智能家居…

第二证券:新股申购配号数什么意思?

股配号数量便是我们参与抽签的数量&#xff0c;投资者申购新股之后&#xff0c;交易所会根据持有的股票市值进行配号。 投资者的市值越大&#xff0c;申购新股的配号越多&#xff0c;其中签机会越大。主板、创业板、科创板一个申购单位是500股&#xff0c;意味着1万元的市值有…

Java 定义类型处理MySQL point类型数据

1.三个类来处理 引入maven依赖 <!-- 引入 jts 库解析 POINT --><dependency><groupId>com.vividsolutions</groupId><artifactId>jts</artifactId><version>1.13</version></dependency>import javax.validation.constr…

【C++入门】—— C++入门 (下)_内联函数

前言&#xff1a;在了解完前面的C基础内容后&#xff0c;马上我们就要真正不如C的学习了&#xff0c;但在之前让我们最后了解最后一点点C入门知识&#xff01;来迟的520特别篇&#xff01; 本篇主要内容&#xff1a; 内联函数 auto关键字 范围for 指针空值nullptr C入门 1. 内联…

智慧医疗时代:探索互联网医院开发的新篇章

在智慧医疗时代&#xff0c;互联网医院开发正引领着医疗服务的创新浪潮。通过将先进的技术与医疗服务相结合&#xff0c;互联网医院为患者和医生提供了全新的互动方式&#xff0c;极大地提升了医疗服务的便捷性和效率。本文将深入探讨互联网医院的开发&#xff0c;介绍其技术实…

一键部署!QQ AI 聊天机器人!支持ChatGPT、文心一言、讯飞星火、Bing、Bard、ChatGLM、POE,多账号,人设调教

随着人工智能技术的不断发展&#xff0c;智能聊天机器人已经成为我们日常生活中不可或缺的一部分。ChatGPT作为一款强大的人工智能聊天模型&#xff0c;能够为我们提供高效、便捷的聊天体验。那么&#xff0c;如何将ChatGPT接入QQ&#xff0c;实现智能聊天新体验呢&#xff1f;…

OTP8脚-全自动擦鞋机WTN6020-低成本语音方案

一&#xff0c;产品开发背景 首先&#xff0c;随着人们生活质量的提升&#xff0c;对鞋子的保养需求也日益增加。鞋子作为人们日常穿着的重要组成部分&#xff0c;其清洁度和外观状态直接影响到个人形象和舒适度。因此&#xff0c;一种能够自动清洁和擦亮鞋子的设备应运而生&am…

局部直方图均衡化去雾算法

目录 1. 引言 2. 算法流程 3. 代码 4. 去雾效果 1. 引言 局部直方图算法是一种基于块的图像去雾方法&#xff0c;它将图像分割为若干个块&#xff0c;并在每个块内计算块的局部直方图。通过对各个块的直方图进行分析和处理&#xff0c;该算法能够更好地适应图像中不同区域的…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-16讲 EPIT定时器

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

再谈Google I/O 2024:开发者必看亮点

在2024年Google I/O大会上&#xff0c;谷歌发布了许多令人兴奋的新技术和工具。本文将重点介绍其中的三大亮点&#xff1a;新一代TPU、Gemma模型以及Firebase GenKit。这些工具和技术对于开发者来说&#xff0c;将会带来前所未有的便利和强大功能。 新一代TPU&#xff1a;Tril…

在MySQL数据库中的视图和事务。

视图 view 临时表 作用&#xff1a;优化多表查询的效率 可以将经常使用的连接查询结果使用视图进行保存&#xff0c;避免多次重复的笛卡尔积运算 MySQL数据库在多表查询的时候会自动进行笛卡尔积运算。 如果将来经常要用到某一个多表查询的结果就可以使用视图将这个结果…

Visual Studio中MP编译参数

MP通常与OpenMP&#xff08;Open Multi-Processing&#xff09;关联&#xff0c;它是用于多平台共享内存并行编程的一个API。 在编译C或C代码时使用OpenMP&#xff0c;通常需要特定的编译参数来启用这一功能。对于GCC和G编译器&#xff0c;这些参数包括&#xff1a; -fopenmp…

云手机在软件测试中的作用,为软件测试工程师减负

针对每家企业来说&#xff0c;对于即将上线的软件进行测试这一步骤是不可忽视的&#xff0c;这决定产品上线后的质量和口碑&#xff1b; 传统的的真机测试可能面临设备大量的采购&#xff0c;管理和维护的成本提高&#xff0c;现在不少企业都开始用云手机来代替真机&#xff0…

24.zabbix高可用

环境准备 准备三台机器 主机名字IP地址软件环境zabbix-server01192.168.111.70httpdphpkeepalivedsshpasszabbix serveragentzabbix-server02192.168.111.71httpdphpkeepalivedsshpasszabbix serveragentzabbix-agent192.168.111.80zabbix agentmysql VIP规划&#xff1a;19…

《Ai-企业知识库》-讨论、构思01

阿丹&#xff1a; 经过几天的Ai学习&#xff0c;开始对于整个大模型&#xff0c;开始有清晰的认知了。开始准备上手操作&#xff0c;编程自己去写一些东西了。 什么是会话AI? 一个计算机程序&#xff0c;允许人类使用各种输入方法&#xff0c;如语音&#xff0c;文字&#x…