Spring 注解开发进阶实战:Bean 生命周期、 依赖注入及Properties配置(Spring系列4)

张开发
2026/4/4 23:06:51 15 分钟阅读

分享文章

Spring 注解开发进阶实战:Bean 生命周期、 依赖注入及Properties配置(Spring系列4)
Spring注解开发是现代Java项目的主流开发方式相比传统XML配置它更简洁、更符合Java代码的设计逻辑。本文将围绕Spring注解开发的核心进阶知识点展开Bean作用域与生命周期管理、多层级依赖注入Autowired/Qualifier/Resource、注解方式读取Properties配置文件通过完整的实战案例与源码解析帮你彻底掌握Spring注解开发的核心能力。一、Bean作用范围与生命周期管理1.1 环境准备首先搭建标准的Maven项目为后续注解开发做好基础环境。1.1.1 Maven核心依赖dependencies dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.2.10.RELEASE/version /dependency !-- 解决PostConstruct/PreDestroy注解缺失问题JDK9需手动引入 -- dependency groupIdjavax.annotation/groupId artifactIdjavax.annotation-api/artifactId version1.3.2/version /dependency /dependencies1.1.2 核心业务代码与配置类1. 配置类SpringConfigimport org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;Configuration ComponentScan(com.itheima) public class SpringConfig { }2. 数据访问层BookDao BookDaoImpl// BookDao接口 public interface BookDao { void save(); }// BookDaoImpl实现类 import org.springframework.stereotype.Repository;Repository public class BookDaoImpl implements BookDao { public void save() { System.out.println(book dao save ...); } }3. 运行类Appimport com.itheima.config.SpringConfig; import com.itheima.dao.BookDao; import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class App { public static void main(String[] args) { AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(SpringConfig.class); // 获取两次Bean观察地址 BookDao bookDao1 ctx.getBean(BookDao.class); BookDao bookDao2 ctx.getBean(BookDao.class); System.out.println(bookDao1); System.out.println(bookDao2); ctx.close(); } }1.2 Bean的作用范围单例/多例1.2.1 单例模式默认行为运行上述代码控制台会输出两个完全相同的地址说明Spring默认情况下Bean是单例的IOC容器中仅创建一个实例。1.2.2 改为多例模式Scope注解在BookDaoImpl上添加Scope注解指定作用范围为prototype多例import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository;Repository Scope(prototype) // 多例模式每次getBean都会创建新实例 public class BookDaoImpl implements BookDao { public void save() { System.out.println(book dao save ...); } }再次运行控制台输出两个不同的地址说明多例模式生效。1.3 Bean的生命周期Bean的生命周期包括初始化→使用→销毁。Spring通过注解精准控制生命周期的执行时机。1.3.1 核心生命周期注解注解作用执行时机PostConstruct初始化方法构造方法执行完毕后立即执行PreDestroy销毁方法容器关闭ctx.close()时执行1.3.2 实战代码实现修改BookDaoImpl添加生命周期注解import org.springframework.stereotype.Repository; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy;Repository public class BookDaoImpl implements BookDao { // 构造方法 public BookDaoImpl() { System.out.println(constructor ...); }public void save() { System.out.println(book dao save ...); }// 初始化方法 PostConstruct public void init() { System.out.println(init ...); }// 销毁方法 PreDestroy public void destroy() { System.out.println(destroy ...); } }1.3.3 运行验证public class App { public static void main(String[] args) { AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(SpringConfig.class); BookDao bookDao1 ctx.getBean(BookDao.class); // 关闭容器触发销毁方法 ctx.close(); } }1.4 生命周期与作用域核心对比特性单例Singleton多例Prototype实例数量容器中仅一个每次getBean创建新实例生命周期随容器创建随容器销毁容器创建实例后不再管理销毁方法执行PreDestroy不执行销毁方法二、注解开发依赖注入核心难点Spring注解注入分为引用类型注入、简单类型注入、多实现类注入。2.1 环境准备与问题复现// BookService接口 public interface BookService { void save(); }// BookServiceImpl实现类 import org.springframework.stereotype.Service;Service public class BookServiceImpl implements BookService { // 依赖BookDao private BookDao bookDao;public void save() { System.out.println(book service save ...); bookDao.save(); } }运行代码会抛出NullPointerException原因是bookDao未被注入为null。2.2 引用类型注入方案2.2.1 方案一Autowired按类型注入import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;Service public class BookServiceImpl implements BookService { // 按类型自动装配 Autowired private BookDao bookDao;public void save() { System.out.println(book service save ...); bookDao.save(); } }核心知识点Autowired 省略Setter方法原理1.Autowired可以写在属性上也可以写在setter方法上最简单的处理方式是写在属性上并将setter方法删除掉2.为什么setter方法可以删除✅ 自动装配基于暴力反射设计直接为私有属性设值✅ 普通反射只能操作public内容暴力反射可操作private内容✅ 因此无需提供setter方法Spring可直接赋值私有属性核心知识点Autowired 注入匹配规则1.Autowired默认按照类型自动装配2. 如果IOC容器中同类的Bean找到多个就按照变量名和Bean的名称匹配3. 示例变量名叫bookDao容器中存在一个同名同类型Bean则成功注入有多个同名同类型bean即使不指定bean名称默认类型名首字母小写为bean名会抛出NoUniqueBeanDefinitionException4. 如果变量名与所有Bean名称都不匹配如容器只有bookDao1、bookDao2则抛出NoUniqueBeanDefinitionException异常2.2.2 方案二多实现类冲突与Qualifier按名称注入如果BookDao有多个实现类Autowired会因类型冲突报错需配合Qualifier指定名称import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service;Service public class BookServiceImpl implements BookService { Autowired Qualifier(bookDao2) // 指定注入bean名称 private BookDao bookDao;public void save() { System.out.println(book service save ...); bookDao.save(); } }2.2.3 方案三ResourceJDK自带按名称优先import javax.annotation.Resource; import org.springframework.stereotype.Service;Service public class BookServiceImpl implements BookService { Resource(name bookDao2) private BookDao bookDao; }2.3 简单类型注入Value注入简单类型String、Integer等时使用Value注解支持直接赋值、SpEL表达式、读取Properties配置。Repository(bookDao) public class BookDaoImpl implements BookDao { // 直接赋值 Value(itheima888) private String name;public void save() { System.out.println(book dao save ... name); } }三、注解方式读取Properties配置文件3.1 基础使用根路径文件# jdbc.properties nameitheima888import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; Configuration ComponentScan(com.itheima) PropertySource(jdbc.properties) public class SpringConfig { }Repository(bookDao) public class BookDaoImpl implements BookDao { Value(${name}) private String name; }3.2 进阶使用子包路径文件3.2.1 项目结构src └── main └── resources └── config └── jdbc.properties // 在config子包下4.2.2 配置类指定路径Configuration ComponentScan(com.itheima) // classpath:指向类路径根进入config子目录 PropertySource(classpath:config/jdbc.properties) public class SpringConfig { }3.2.3 核心原理classpath指向类路径根src/main/resources或编译后的target/classes子包名对应目录层级Spring 自动解析开发 / 编译状态下的路径。3.3 多配置文件加载与注意事项3.3.1 加载多个配置文件PropertySource({jdbc.properties, jdbc2.properties})3.3.2 不支持通配符PropertySource(*.properties)会报错需手动列出所有文件。3.3.3 严格区分大小写Linux/Mac 环境下文件名大小写敏感需与实际文件一致。四、核心知识点总结Autowired基于暴力反射可直接注入私有属性无需setter方法Autowired注入规则先按类型类型多个则按变量名匹配不匹配则报错Scope控制单例/多例PostConstruct/PreDestroy控制生命周期PropertySourceValue实现注解方式读取Properties配置文件

更多文章