Spring 作为 Java 企业级开发的事实标准,以其轻量级、非侵入式的设计理念和强大的依赖注入能力,彻底改变了 Java 应用的开发方式。从最初解决 EJB 复杂性的轻量级框架,发展到如今涵盖微服务、云原生、响应式编程的全栈生态,Spring 已经成为 Java 开发者必须掌握的核心技能。本文将系统全面地梳理 Spring 框架的核心知识点,从基础概念到高级特性,帮助初学者建立完整的知识体系,也为有经验的开发者提供深入的技术参考。
一、Spring 概述
1.1 什么是 Spring
Spring 是一个开源的轻量级 Java 应用开发框架,旨在简化企业级应用开发的复杂性。它通过 IoC(控制反转)和 AOP(面向切面编程)等核心特性,实现了代码的解耦和模块化。
核心特性:
轻量级:非侵入式设计,对容器依赖小
控制反转(IoC):将对象创建和依赖管理的控制权交给容器
依赖注入(DI):容器动态地将依赖关系注入到组件中
面向切面编程(AOP):将横切关注点与业务逻辑分离
容器:管理对象的生命周期和配置
一站式框架:提供数据访问、Web、安全、消息等完整解决方案
1.2 Spring 体系结构
Spring 框架模块化结构:
┌─────────────────────────────────────────────────────────────┐
│ 测试模块 (Test) │
├─────────────────────────────────────────────────────────────┤
│ Web 模块 (Web MVC, WebSocket, WebFlux) │
├─────────────────────────────────────────────────────────────┤
│ 数据访问模块 (JDBC, ORM, Transactions) │
├─────────────────────────────────────────────────────────────┤
│ AOP 模块 (Aspects, Instrumentation) │
├─────────────────────────────────────────────────────────────┤
│ 核心容器 (Core, Beans, Context, SpEL) │
└─────────────────────────────────────────────────────────────┘
核心模块:
Core Container:IoC 容器基础,提供 BeanFactory 和 ApplicationContext
AOP:面向切面编程支持
Data Access:JDBC、ORM、事务管理
Web:Web MVC、WebSocket、WebFlux
Test:单元测试和集成测试支持
1.3 环境搭建
Maven 依赖:
xml
<dependencies>
<!-- Spring 核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.30</version>
</dependency>
<!-- Spring 测试支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.30</version>
<scope>test</scope>
</dependency>
<!-- 日志框架 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
二、IoC 容器
2.1 控制反转与依赖注入
控制反转(IoC):将对象的创建和依赖关系的管理从代码中转移给容器,由容器负责对象的生命周期和对象之间的关系。
依赖注入(DI):容器在创建对象时,自动将依赖的对象注入到当前对象中。
依赖注入方式:
java
// 1. 构造器注入(推荐,用于必需依赖)
@Component
public class UserService {
private final UserDao userDao;
private final EmailService emailService;
public UserService(UserDao userDao, EmailService emailService) {
this.userDao = userDao;
this.emailService = emailService;
}
}
// 2. Setter 注入(用于可选依赖)
@Component
public class OrderService {
private OrderDao orderDao;
@Autowired
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
}
// 3. 字段注入(最简洁,但不推荐)
@Component
public class ProductService {
@Autowired
private ProductDao productDao;
}
2.2 Bean 配置方式
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 配置 -->
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
<!-- 构造器注入 -->
<bean id="userService" class="com.example.service.UserService">
<constructor-arg ref="userDao"/>
<constructor-arg value="张三"/>
</bean>
<!-- Setter 注入 -->
<bean id="orderService" class="com.example.service.OrderService">
<property name="orderDao" ref="orderDao"/>
<property name="timeout" value="5000"/>
</bean>
<!-- 静态工厂方法 -->
<bean id="dateFormat" class="java.text.SimpleDateFormat"
factory-method="getInstance"/>
<!-- 实例工厂方法 -->
<bean id="serviceFactory" class="com.example.ServiceFactory"/>
<bean id="service" factory-bean="serviceFactory" factory-method="createService"/>
</beans>
注解配置方式:
java
// @Configuration 声明配置类
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// @Bean 声明 Bean
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
// 条件创建 Bean
@Bean
@Conditional(DevCondition.class)
public DevService devService() {
return new DevService();
}
// Bean 生命周期回调
@Bean(initMethod = "init", destroyMethod = "cleanup")
public SomeService someService() {
return new SomeService();
}
}
混合配置:
java
@Configuration
@ImportResource("classpath:spring-config.xml") // 导入 XML 配置
@ComponentScan(basePackages = "com.example")
@PropertySource("classpath:application.properties") // 导入属性文件
public class MixedConfig {
@Value("${jdbc.url}")
private String jdbcUrl;
@Autowired
private Environment env;
}
2.3 Bean 的作用域
java
@Component
// 单例(默认)
@Scope("singleton")
public class SingletonBean {
}
@Component
// 原型(每次获取都创建新实例)
@Scope("prototype")
public class PrototypeBean {
}
@Component
// 请求作用域(Web 应用)
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestBean {
}
@Component
// 会话作用域(Web 应用)
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionBean {
}
@Component
// 应用作用域(Web 应用)
@Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ApplicationBean {
}
// 自定义作用域
@Component
@Scope("thread")
public class ThreadScopeBean {
}
// 配置自定义作用域
@Configuration
public class CustomScopeConfig {
@Bean
public static CustomScopeConfigurer customScopeConfigurer() {
CustomScopeConfigurer configurer = new CustomScopeConfigurer();
configurer.addScope("thread", new SimpleThreadScope());
return configurer;
}
}
2.4 Bean 生命周期
@Component
public class LifecycleBean implements InitializingBean, DisposableBean,
BeanNameAware, BeanFactoryAware {
private String name;
public LifecycleBean() {
System.out.println("1. 构造器执行");
}
// 属性注入后执行
@Autowired
public void setName(String name) {
System.out.println("2. 属性注入");
this.name = name;
}
// Bean 名称感知
@Override
public void setBeanName(String name) {
System.out.println("3. BeanNameAware: " + name);
}
// BeanFactory 感知
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4. BeanFactoryAware");
}
// 初始化前执行
@PostConstruct
public void postConstruct() {
System.out.println("5. @PostConstruct");
}
// 初始化方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6. InitializingBean.afterPropertiesSet");
}
// 自定义初始化方法
@Bean(initMethod = "customInit")
public void customInit() {
System.out.println("7. 自定义初始化方法");
}
// 销毁前执行
@PreDestroy
public void preDestroy() {
System.out.println("8. @PreDestroy");
}
// 销毁方法
@Override
public void destroy() throws Exception {
System.out.println("9. DisposableBean.destroy");
}
// 自定义销毁方法
@Bean(destroyMethod = "customDestroy")
public void customDestroy() {
System.out.println("10. 自定义销毁方法");
}
}
2.5 条件化 Bean 装配
// 条件接口实现
public class DevCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return "dev".equals(env.getProperty("spring.profiles.active"));
}
}
// 使用 @Conditional
@Configuration
public class ConditionalConfig {
@Bean
@Conditional(DevCondition.class)
public DataSource devDataSource() {
return new HikariDataSource();
}
@Bean
@Conditional(ProdCondition.class)
public DataSource prodDataSource() {
return new HikariDataSource();
}
// 基于配置属性
@Bean
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
// 基于类的存在
@Bean
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public RedisTemplate redisTemplate() {
return new RedisTemplate();
}
// 基于 Bean 的存在
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource defaultDataSource() {
return new HikariDataSource();
}
}
// Spring Boot 条件注解
@Configuration
public class BootConditionalConfig {
@Bean
@ConditionalOnWebApplication
public WebConfig webConfig() {
return new WebConfig();
}
@Bean
@ConditionalOnNotWebApplication
public CliConfig cliConfig() {
return new CliConfig();
}
@Bean
@ConditionalOnResource(resources = "classpath:config.xml")
public XmlParser xmlParser() {
return new XmlParser();
}
@Bean
@ConditionalOnExpression("${my.property:true} && ${another.property:false}")
public ComplexBean complexBean() {
return new ComplexBean();
}
}
三、依赖注入详解
3.1 @Autowired 注解
java
@Component
public class InjectionDemo {
// 字段注入
@Autowired
private UserDao userDao;
// 构造器注入(推荐)
private final OrderDao orderDao;
@Autowired
public InjectionDemo(OrderDao orderDao) {
this.orderDao = orderDao;
}
// Setter 注入
private ProductDao productDao;
@Autowired
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
// 任意方法注入
@Autowired
public void injectDependencies(EmailService emailService, SmsService smsService) {
// 注入多个依赖
}
// 集合注入
@Autowired
private List<PaymentService> paymentServices; // 注入所有实现
@Autowired
private Map<String, PaymentService> paymentServiceMap; // 注入带名称的 Map
// 可选注入
@Autowired(required = false)
private Optional<CacheService> cacheService;
// 精确匹配
@Autowired
@Qualifier("mysqlDataSource")
private DataSource dataSource;
}
3.2 @Qualifier 注解
@Component
public class QualifierDemo {
@Autowired
@Qualifier("mysqlDataSource")
private DataSource primaryDataSource;
@Autowired
@Qualifier("oracleDataSource")
private DataSource secondaryDataSource;
// 自定义 Qualifier 注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MySQL {}
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Oracle {}
@Autowired
@MySQL
private DataSource mysqlDataSource;
@Autowired
@Oracle
private DataSource oracleDataSource;
}
// 使用自定义 Qualifier
@Configuration
public class DataSourceConfig {
@Bean
@MySQL
public DataSource mysqlDataSource() {
return new HikariDataSource();
}
@Bean
@Oracle
public DataSource oracleDataSource() {
return new HikariDataSource();
}
}
3.3 @Resource 和 @Inject
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
@Component
public class Jsr330Demo {
// @Resource 按名称注入(JSR-250)
@Resource(name = "userDao")
private UserDao userDao;
// @Resource 默认按字段名注入
@Resource
private OrderDao orderDao;
// @Inject 按类型注入(JSR-330)
@Inject
private ProductDao productDao;
// @Inject 结合 @Named 按名称注入
@Inject
@Named("paymentService")
private PaymentService paymentService;
// @Inject 支持 Provider 延迟注入
@Inject
private Provider<CacheService> cacheServiceProvider;
public void useCache() {
CacheService cache = cacheServiceProvider.get(); // 延迟获取
cache.get("key");
}
}
3.4 循环依赖解决
// 构造器注入无法解决循环依赖(会抛出异常)
// 解决方案1:使用 Setter 或字段注入
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB; // 字段注入解决循环依赖
}
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
// 解决方案2:使用 @Lazy 延迟加载
@Component
public class ServiceC {
private final ServiceD serviceD;
public ServiceC(@Lazy ServiceD serviceD) {
this.serviceD = serviceD;
}
}
@Component
public class ServiceD {
private final ServiceC serviceC;
public ServiceD(ServiceC serviceC) {
this.serviceC = serviceC;
}
}
// 解决方案3:使用 @PostConstruct 初始化
@Component
public class ServiceE {
@Autowired
private ServiceF serviceF;
@PostConstruct
public void init() {
// 使用 serviceF 初始化
}
}
@Component
public class ServiceF {
@Autowired
private ServiceE serviceE;
}