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

深入理解 Spring 框架的 Bean 管理与 IOC​

        在 Java 企业级开发领域,Spring 框架以其强大且灵活的特性成为众多开发者的首选。而 Spring 框架的核心基石之一,便是 Bean 管理与控制反转(Inversion of Control,简称 IOC)。这两项技术不仅极大地简化了应用程序的开发流程,还显著提升了代码的可维护性与可扩展性。

一、认识 Spring 框架的 Bean​

1.1 Bean 的定义​

        在 Spring 框架中,Bean 是指被 Spring 容器管理的对象。Spring 容器负责创建、配置和管理 Bean,通过依赖注入(Dependency Injection,DI,IOC 的一种实现方式)将 Bean 之间的依赖关系进行连接。简单来说,任何一个被 Spring 容器管理的 Java 对象,都可以称之为 Bean。例如,在一个 Web 应用中,业务逻辑层的 Service 类、数据访问层的 DAO 类,都可以被配置为 Spring 容器中的 Bean,由 Spring 容器统一管理其生命周期。​

1.2 Bean 的配置方式​

Spring 提供了多种配置 Bean 的方式,常见的有 XML 配置、注解配置以及 Java 配置。​

  • XML 配置:早期 Spring 项目中常用的方式,通过在 XML 文件中定义 Bean 的相关信息,如 Bean 的 id、class、属性值等。例如,定义一个简单的 UserService Bean:
  • <bean id="userService" class="com.example.service.UserService"><property name="userDao" ref="userDao"/>
    </bean>
    <bean id="userDao" class="com.example.dao.UserDao"/>

    在上述代码中,userService Bean 依赖于userDao Bean,通过<property>标签将userDao的引用注入到userService中。​

  • 注解配置:随着 Spring 版本的更新,注解配置逐渐成为主流。常用的注解有@Component、@Service、@Repository、@Controller等,这些注解用于将类标记为可被 Spring 容器扫描并管理的 Bean。例如:
@Service
public class UserService {private UserDao userDao;@Autowiredpublic UserService(UserDao userDao) {this.userDao = userDao;}
}@Repository
public class UserDao {// 数据访问层逻辑
}

@Service注解将UserService类标记为业务逻辑层的 Bean,@Repository注解将UserDao类标记为数据访问层的 Bean,@Autowired注解则实现了依赖注入,自动将UserDao的实例注入到UserService的构造函数中。​

  • Java 配置:通过 Java 类和注解来配置 Bean,使用@Configuration和@Bean注解。例如:
@Configuration
public class AppConfig {@Beanpublic UserService userService() {return new UserService(userDao());}@Beanpublic UserDao userDao() {return new UserDao();}
}

@Configuration注解标识该类为配置类,@Bean注解定义了具体的 Bean 实例,通过方法调用的方式实现 Bean 之间的依赖关系。

二、深入理解控制反转(IOC)​

2.1 IOC 的概念​

控制反转(IOC)是一种设计思想,它将对象的创建和依赖关系的管理从程序代码中转移到外部容器(即 Spring 容器)中。在传统的编程模式下,对象的创建和依赖关系的维护都由开发者在代码中显式实现,这导致代码耦合度高,难以维护和扩展。而引入 IOC 后,Spring 容器负责创建对象,并根据配置将对象之间的依赖关系进行注入,开发者只需关注业务逻辑的实现,无需关心对象的创建和管理细节。​

2.2 IOC 的实现方式 —— 依赖注入(DI)​

依赖注入是 IOC 的具体实现方式,它有三种常见的注入方式:构造函数注入、Setter 方法注入和字段注入。​

  • 构造函数注入:通过类的构造函数将依赖对象传递进来。如前面UserService的例子中,通过构造函数注入UserDao实例,这种方式保证了依赖对象在对象创建时就已被初始化,并且不可变,安全性较高。​
  • Setter 方法注入:通过类的 Setter 方法将依赖对象设置进去。例如:
public class UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}

在 XML 配置中,可以通过<property>标签的name属性指定 Setter 方法对应的属性名,来实现 Setter 方法注入。Setter 方法注入的优点是更加灵活,可以在对象创建后动态地设置依赖对象。​

  • 字段注入:直接在类的字段上使用@Autowired等注解进行依赖注入。例如:
@Service
public class UserService {@Autowiredprivate UserDao userDao;
}

2.3 IOC 的优势​

IOC 带来的优势主要体现在以下几个方面:​

  • 降低代码耦合度:通过将对象的创建和依赖管理交给 Spring 容器,不同组件之间的依赖关系变得更加清晰,降低了代码之间的耦合度,提高了代码的可维护性和可扩展性。​
  • 提高代码的可测试性:由于对象的依赖关系由 Spring 容器注入,在进行单元测试时,可以方便地替换依赖对象,使用模拟对象(Mock 对象)来进行测试,从而提高测试的效率和准确性。​
  • 便于代码的复用:IOC 使得组件更加独立,可复用性增强。不同的项目或模块可以共享相同的 Bean,减少了重复开发的工作量。​

三、Spring 容器对 Bean 的生命周期管理​

Spring 容器对 Bean 的生命周期管理是其 Bean 管理的重要组成部分。一个 Bean 从创建到销毁,通常会经历以下几个阶段:​

  1. 实例化:Spring 容器根据配置信息创建 Bean 的实例,这相当于 Java 中的new操作。​
  2. 属性注入:在 Bean 实例化后,Spring 容器会根据配置将 Bean 的依赖属性注入到相应的位置,如通过构造函数注入、Setter 方法注入等。​
  3. 初始化:如果 Bean 实现了InitializingBean接口,Spring 容器会调用其afterPropertiesSet方法;或者在配置文件中指定了init-method属性,Spring 容器会调用该方法,用于执行一些初始化操作,如资源的加载、连接的建立等。​
  4. 使用:Bean 完成初始化后,就可以在应用程序中被使用,执行相应的业务逻辑。​
  5. 销毁:当 Spring 容器关闭时,如果 Bean 实现了DisposableBean接口,Spring 容器会调用其destroy方法;或者在配置文件中指定了destroy-method属性,Spring 容器会调用该方法,用于释放资源,如关闭连接、释放内存等。​

通过对 Bean 生命周期的管理,Spring 容器确保了 Bean 在合适的时机执行相应的操作,保证了应用程序的稳定性和可靠性。

四、实战演练

类组成如下

实体类

package com.qcby;import org.springframework.stereotype.Component;public class Cat {private String name;private int age;private Integer num;private double height ;private Demo demo;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 Integer getNum() {return num;}public void setNum(Integer num) {this.num = num;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}public Demo getDemo() {return demo;}public void setDemo(Demo demo) {this.demo = demo;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +", age=" + age +", num=" + num +", height=" + height +", demo=" + demo +'}';}public Cat() {}public Cat(String name, int age, Integer num, double height, Demo demo) {this.name = name;this.age = age;this.num = num;this.height = height;this.demo = demo;}public void eat() {System.out.println("猫吃鱼");}
}

package com.qcby;import org.springframework.stereotype.Service;@Service
public class Demo {private String name;public void hello() {System.out.println("Hello World!");}
}

package com.qcby;import java.util.Arrays;
import java.util.List;
import java.util.Map;public class Dog {private int[] arr;private List<String> List;private Map<String,String> map;public int[] getArr() {return arr;}public void setArr(int[] arr) {this.arr = arr;}public java.util.List<String> getList() {return List;}public void setList(java.util.List<String> list) {List = list;}public Map<String, String> getMap() {return map;}public void setMap(Map<String, String> map) {this.map = map;}@Overridepublic String toString() {return "Dog{" +"arr=" + Arrays.toString(arr) +", List=" + List +", map=" + map +'}';}public void jump(){System.out.println("狗会跳");}
}

package com.qcby;public class User {private String name;private double height;private Demo demo;public User(String name, double height, Demo demo) {this.name = name;this.height = height;this.demo = demo;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", height=" + height +", demo=" + demo +'}';}public void fly (){System.out.println("我会飞");}
}

spring.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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--IOC--><!--    <bean id ="demo" class="com.qcby.Demo"/>--><!--    <bean id ="user" class="com.qcby.User"/>--><bean id="cat" class="com.qcby.Cat"><property name="age" value="10"/><property name="name" value="Tom"/><property name="num" value="1"/><property name="height" value="180.5"/><property name="demo" ref="demo"/></bean><bean id="demo" class="com.qcby.Demo"/><bean id="dog" class="com.qcby.Dog"><property name="arr" ><array><value>1</value><value>2</value><value>3</value></array></property><property name="list"><list><value>张三</value><value>李四</value><value>王五</value></list></property><property name="map" ><map><entry key="张三" value="zs"/><entry key="李四" value="ls"/><entry key="王五" value="ww"/></map></property></bean><bean id="user" class="com.qcby.User"><constructor-arg name="name" value="张三"/><constructor-arg name="height" value="180.5"/><constructor-arg name="demo" ref="demo"/></bean><context:component-scan base-package="com.qcby"/>
</beans>

测试类

import com.qcby.Cat;
import com.qcby.Demo;
import com.qcby.Dog;
import com.qcby.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserTest {@Testpublic void run (){Demo demo = new Demo();demo.hello();}@Testpublic void run1 (){ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");Demo demo = (Demo) context.getBean("demo");demo.hello();}@Testpublic void run2 (){ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");Dog dog = (Dog) context.getBean("dog");System.out.println( dog.toString());}@Testpublic void run3 (){ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");Cat cat = (Cat) context.getBean("cat");System.out.println( cat.toString());}@Testpublic void run4 (){ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");User user = (User) context.getBean("user");System.out.println( user.toString());}
}

运行结果

http://www.lqws.cn/news/523099.html

相关文章:

  • arthas助力Java程序Full GC频率大降!
  • 神经网络的运作方式类比讲解
  • TensorFlow Lite (TFLite) 和 PyTorch Mobile介绍2
  • 红外图像增强(dde):基于“基础层-细节层”分解的增强算法
  • 深入学习入门--(一)前备知识
  • 深度学习之分类手写数字的网络
  • 【Linux】Lniux基本指令(1)
  • Acrobat JavaScript 中的 util 对象
  • Windows下安装zookeeper
  • 玛哈特机械矫平机:精密制造的“应力消除师”与“平整度雕刻家”
  • 机器学习01
  • 鸿蒙 GridRow 与 GridCol 组件解析:响应式网格布局指南
  • 局域网环境下浏览器安全限制的实用方法
  • SpringBoot(九)--- HttpClient、Spring Cache、Spring Task、WebSocket
  • RegionServer热点问题解决方案
  • 企业级应用中的编程风格深度剖析与实践指南
  • ROI切割技术详解:从基础到实践
  • Vue计算属性与监视属性
  • 物流涂层科技赋能仓储:创冷科技引领高温环境下的仓储物流安全升级
  • 【GStreamer】减小延时的参数设置、从RTP中获取时间戳
  • npm(或pnpm)时报:证书过期 certificate has expired问题
  • 【网站内容安全检测】之3:获取所有外部域名访问后图像
  • VBA技术资料MF329:获得屏幕分辨率
  • python学习笔记(深度学习)
  • 二维前缀和与差分深度解析
  • Redis:持久化
  • dockerfile命令及构建
  • (C++)vector数组相关基础用法(C++教程)(STL库基础教程)
  • 多线程知识点
  • ffmpeg获取组播中指定视频流、音频流(通过pid、program)首发