Spring 框架作为 Java 领域的 "武林盟主",自 2003 年由 Rod Johnson 创建以来,凭借其轻量级、一站式、松耦合 的设计理念,彻底改变了企业级应用开发的模式。本文将围绕 Spring 的两大核心 ------控制反转(IOC)与面向切面编程(AOP),结合配置文件、半注解、全注解三种开发方式,带你从入门到精通 Spring 核心技术。
一、Spring 框架概述:为什么它能成为 Java 开发的 "标配"?
1. Spring 是什么?
Spring 是一个分层的 JavaSE/EE 全栈轻量级开源框架 ,核心解决业务逻辑层与其他层的耦合问题 ,将面向接口的编程思想贯穿整个系统。它不是要替代现有技术,而是通过整合各类优秀框架(如 MyBatis、Struts2 等),为开发者提供一套统一的开发规范。
简单来说,Spring 就像一个 "超级工厂",帮你管理所有对象的创建和依赖关系;又像一把 "手术刀",通过 AOP 实现对业务逻辑的精准切入 ------ 这一切都源于它的两大灵魂:IOC(控制反转)和AOP(面向切面编程)。
2. Spring 的六大核心优势
- 解耦神器:通过 IOC 将对象创建权交给 Spring,彻底摆脱 "new 对象" 的强依赖,让代码更灵活;
- AOP 赋能:无需修改业务代码,就能实现权限拦截、日志监控等横向功能;
- 声明式事务 :只需简单配置,就能完成事务管理,再也不用手动写
try-catch-commit-rollback; - 测试友好:对 JUnit 深度支持,通过注解可一键测试 Spring 组件;
- 框架整合王:无缝集成 MyBatis、Hibernate、Quartz 等主流框架,避免重复造轮子;
- 简化 API 使用:对 JDBC、JavaMail 等 "难用" 的 JavaEE API 进行封装,降低开发门槛。
二、IOC 核心技术:把对象创建权 "反转" 给 Spring
1. 什么是 IOC?
IOC(Inverse of Control,控制反转)是 Spring 的核心设计思想 ------将对象的创建权从开发者手中 "反转" 给 Spring 框架。
举个例子:以前你需要手动new UserService(),现在只需告诉 Spring"我要一个 UserService",Spring 就会自动帮你创建好对象。这种模式彻底解决了程序耦合性高的问题,让代码维护性飙升。
2. IOC 入门实战:从 0 到 1 搭建 Spring 工程
步骤 1:导入依赖(Maven 坐标)
XML
<dependencies>
<!-- Spring核心容器 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- 日志相关 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
步骤 2:编写业务接口与实现类
java
// 接口:UserService.java
package com.spring.demo.service;
public interface UserService {
void hello();
}
// 实现类:UserServiceImpl.java
package com.spring.demo.service;
public class UserServiceImpl implements UserService {
@Override
public void hello() {
System.out.println("Hello, Spring IOC!");
}
}
步骤 3:编写 Spring 配置文件(applicationContext.xml)
在src/main/resources下创建applicationContext.xml,配置需要 Spring 管理的 Bean:
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">
<!-- 配置UserService Bean,id是Bean的唯一标识,class是实现类全路径 -->
<bean id="userService" class="com.spring.demo.service.UserServiceImpl"/>
</beans>
步骤 4:编写测试类
java
package com.spring.demo.test;
import com.spring.demo.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IocDemo {
@Test
public void testIoc() {
// 加载Spring配置文件,创建工厂
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从工厂中获取Bean
UserService userService = (UserService) context.getBean("userService");
// 调用方法
userService.hello();
}
}
运行测试方法,控制台将输出Hello, Spring IOC!------ 这意味着 Spring 已经成功帮你创建并管理了UserService对象!
3. IOC 的 Bean 管理:配置文件方式详解
(1)Bean 的基础属性
- id:Bean 的唯一标识,命名需以字母开头,可包含字母、数字、下划线等(不能有特殊字符);
- class:Bean 的实现类全路径,Spring 通过反射创建对象;
- scope :Bean 的作用范围:
singleton(默认):单例,整个 Spring 容器中只有一个实例;prototype:多例,每次getBean都会创建新实例;request/session:仅在 Web 环境下生效,分别对应一次请求或一个会话的作用域。
(2)Bean 的生命周期配置
Spring 允许在 Bean创建时 和销毁时执行自定义方法:
XML
<bean id="userService" class="com.spring.demo.service.UserServiceImpl"
init-method="init" destroy-method="destroy"/>
java
public class UserServiceImpl implements UserService {
public void init() {
System.out.println("Bean初始化时执行...");
}
public void destroy() {
System.out.println("Bean销毁时执行...");
}
// 其他方法...
}
- 单例 Bean 的
destroy方法在 Spring 容器关闭时执行; - 多例 Bean 的
destroy方法由 JVM 垃圾回收机制管理,Spring 不主动调用。
(3)Bean 的三种实例化方式
Spring 支持三种创建 Bean 的方式:
-
默认构造方法(最常用):
<bean id="userService" class="com.spring.demo.service.UserServiceImpl"/> -
静态工厂方式:
java// 静态工厂类 public class StaticFactory { public static UserService createUserService() { return new UserServiceImpl(); } }XML<bean id="userService" class="com.spring.demo.factory.StaticFactory" factory-method="createUserService"/> -
实例工厂方式:
java// 实例工厂类 public class InstanceFactory { public UserService createUserService() { return new UserServiceImpl(); } }XML<bean id="instanceFactory" class="com.spring.demo.factory.InstanceFactory"/> <bean id="userService" factory-bean="instanceFactory" factory-method="createUserService"/>
三、DI 依赖注入:让 Spring 自动解决对象依赖
DI(Dependency Injection,依赖注入)是 IOC 的具体实现方式------Spring 在创建 Bean 时,会自动将其依赖的对象 "注入" 进来。
1. Set 方法注入(最常用)
通过 Bean 的 setter 方法注入依赖,步骤如下:
步骤 1:在 Bean 中定义依赖属性并提供 set 方法
java
public class OrderServiceImpl implements OrderService {
// 依赖的Dao层对象
private OrderDao orderDao;
// 普通属性
private String msg;
private int age;
// 提供set方法,Spring通过set方法注入值
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
public void setMsg(String msg) {
this.msg = msg;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void saveOrder() {
System.out.println("保存订单:" + msg + ",年龄:" + age);
orderDao.saveOrder();
}
}
public interface OrderDao {
void saveOrder();
}
public class OrderDaoImpl implements OrderDao {
@Override
public void saveOrder() {
System.out.println("DAO层:执行保存订单SQL");
}
}
步骤 2:在配置文件中配置依赖注入
XML
<bean id="orderDao" class="com.spring.demo.dao.OrderDaoImpl"/>
<bean id="orderService" class="com.spring.demo.service.OrderServiceImpl">
<!-- 注入Dao对象,ref引用其他Bean的id -->
<property name="orderDao" ref="orderDao"/>
<!-- 注入普通字符串,value直接赋值 -->
<property name="msg" value="Spring依赖注入演示"/>
<property name="age" value="20"/>
</bean>
步骤 3:测试依赖注入
java
@Test
public void testDI() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderService orderService = (OrderService) context.getBean("orderService");
orderService.saveOrder();
}
运行后控制台将输出:
保存订单:Spring依赖注入演示,年龄:20
DAO层:执行保存订单SQL
2. 构造方法注入
通过构造方法注入依赖,适合必须在对象创建时就初始化依赖的场景:
java
public class Car {
private String name;
private Double price;
public Car(String name, Double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Car{name='" + name + "', price=" + price + "}";
}
}
<bean id="car" class="com.spring.demo.entity.Car">
<!-- constructor-arg指定构造方法参数,name对应参数名 -->
<constructor-arg name="name" value="奔驰"/>
<constructor-arg name="price" value="400000"/>
</bean>
3. 集合类型注入(数组、List、Map、Properties)
Spring 支持对数组、集合等复杂类型的注入:
java
public class CollectionBean {
private String[] array;
private List<String> list;
private Map<String, String> map;
private Properties properties;
// 提供set方法
public void setArray(String[] array) { this.array = array; }
public void setList(List<String> list) { this.list = list; }
public void setMap(Map<String, String> map) { this.map = map; }
public void setProperties(Properties properties) { this.properties = properties; }
@Override
public String toString() {
return "CollectionBean{" +
"array=" + Arrays.toString(array) +
", list=" + list +
", map=" + map +
", properties=" + properties +
'}';
}
}
XML
<bean id="collectionBean" class="com.spring.demo.entity.CollectionBean">
<!-- 数组注入 -->
<property name="array">
<array>
<value>元素1</value>
<value>元素2</value>
</array>
</property>
<!-- List注入 -->
<property name="list">
<list>
<value>列表项1</value>
<value>列表项2</value>
</list>
</property>
<!-- Map注入 -->
<property name="map">
<map>
<entry key="key1" value="值1"/>
<entry key="key2" value="值2"/>
</map>
</property>
<!-- Properties注入 -->
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
四、多配置文件管理:大型项目的解耦方案
在大型项目中,单个applicationContext.xml会变得非常臃肿。Spring 支持多配置文件拆分与合并,让配置更清晰:
方式 1:主配置文件导入子配置文件
<!-- applicationContext.xml(主配置) -->
<import resource="applicationContext-dao.xml"/>
<import resource="applicationContext-service.xml"/>
方式 2:加载时指定多个配置文件
// 同时加载多个配置文件
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext-dao.xml",
"applicationContext-service.xml"
);
五、半注解与全注解开发:简化配置的终极方案
Spring 从 3.x 开始支持注解开发 ,大幅减少 XML 配置的工作量。我们可以根据场景选择半注解(XML + 注解)或全注解模式。
1. 半注解开发:XML 配置 + 注解注入
步骤 1:开启组件扫描
在applicationContext.xml中配置注解扫描,指定需要扫描的包:
<context:component-scan base-package="com.spring.demo"/>
步骤 2:在类上添加注解
@Component:通用组件注解,可指定 Bean 的 id(不指定则默认类名首字母小写);@Service:业务层组件(本质是@Component的别名);@Repository:持久层组件(本质是@Component的别名);@Controller:控制层组件(Web 环境下使用,本质是@Component的别名)。
java
// 业务层:@Service注解,id默认为userService
@Service
public class UserServiceImpl implements UserService {
@Override
public void hello() {
System.out.println("Hello, 注解开发!");
}
}
// 持久层:@Repository注解,id默认为orderDao
@Repository
public class OrderDaoImpl implements OrderDao {
@Override
public void saveOrder() {
System.out.println("DAO层保存订单");
}
}
步骤 3:依赖注入注解
@Autowired:自动按类型注入,若类型冲突则按名称注入(需配合@Qualifier("beanId"));@Resource:先按名称注入,再按类型注入(JDK 原生注解,需 JDK8 + 支持);@Value:注入普通字符串或配置文件值。
java
@Service
public class OrderServiceImpl implements OrderService {
// 自动注入OrderDao(按类型匹配)
@Autowired
private OrderDao orderDao;
// 注入普通字符串
@Value("Spring半注解演示")
private String msg;
@Override
public void saveOrder() {
System.out.println("保存订单:" + msg);
orderDao.saveOrder();
}
}
2. 全注解开发:零 XML 配置
通过@Configuration和@ComponentScan注解,完全替代 XML 配置:
java
// 配置类,替代applicationContext.xml
@Configuration
// 组件扫描,等同于<context:component-scan>
@ComponentScan(basePackages = "com.spring.demo")
public class SpringConfig {
// 若有其他配置(如数据源),可在此类中定义Bean
}
java
// 测试类:加载配置类
public class AnnotationDemo {
@Test
public void testFullAnnotation() {
// 加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean(UserService.class);
userService.hello();
}
}
六、AOP 面向切面编程:不修改业务代码实现功能增强
AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 的另一大杀器 ------ 它允许你在不修改业务代码的前提下,对方法进行功能增强(如日志、权限、事务等)。
1. AOP 核心概念
- 切面(Aspect):封装的增强功能(如日志切面、事务切面);
- 连接点(JoinPoint):可以被增强的方法(所有方法理论上都是连接点);
- 切入点(Pointcut):实际被增强的方法(通过表达式指定);
- 通知(Advice):增强的具体逻辑(如前置通知、后置通知等);
- 织入(Weaving):将切面应用到目标对象的过程。
2. AOP 入门实战:日志切面
步骤 1:导入 AOP 依赖
XML
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
步骤 2:编写业务接口与实现类
java
public interface UserService {
void addUser();
void deleteUser();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("执行添加用户业务...");
}
@Override
public void deleteUser() {
System.out.println("执行删除用户业务...");
}
}
步骤 3:编写切面类
java
@Component // 让Spring管理切面类
@Aspect // 声明这是一个切面
public class LogAspect {
// 切入点表达式:execution(返回值 包名.类名.方法名(参数))
// * com.spring.demo.service.*.*(..) 表示:service包下所有类的所有方法,参数任意
@Pointcut("execution(* com.spring.demo.service.*.*(..))")
public void pointcut() {}
// 前置通知:方法执行前增强
@Before("pointcut()")
public void beforeAdvice() {
System.out.println("前置通知:记录方法开始执行时间...");
}
// 后置通知:方法正常执行后增强(异常时不执行)
@AfterReturning("pointcut()")
public void afterReturningAdvice() {
System.out.println("后置通知:记录方法执行耗时...");
}
// 环绕通知:方法执行前后都增强(最灵活)
@Around("pointcut()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前:记录日志开始...");
// 执行目标方法
Object result = joinPoint.proceed();
System.out.println("环绕通知后:记录日志结束...");
return result;
}
}
步骤 4:开启 AOP 注解支持
在配置文件中开启 AOP 自动代理:
<aop:aspectj-autoproxy/>
步骤 5:测试 AOP
java
@Test
public void testAOP() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean(UserService.class);
userService.addUser();
}
运行后控制台输出:
环绕通知前:记录日志开始...
前置通知:记录方法开始执行时间...
执行添加用户业务...
环绕通知后:记录日志结束...
后置通知:记录方法执行耗时...
可以看到,业务方法addUser()的执行被切面 "无侵入" 地增强了------ 这就是 AOP 的魅力!
七、总结:Spring 核心技术学习路径
Spring 的核心是IOC(控制反转)和AOP(面向切面编程) ,掌握它们的关键在于理解 "将控制权交给 Spring,让框架帮你做更多事" 的设计理念。
- 入门阶段:从配置文件方式的 IOC 和 DI 入手,理解 Spring 如何管理对象和依赖;
- 进阶阶段:学习注解开发(半注解 / 全注解),减少 XML 配置的冗余;
- 高阶阶段:深入 AOP 原理,结合事务、缓存等场景,实现业务功能的无侵入增强。
Spring 框架的生态极其庞大,但只要抓住 IOC 和 AOP 这两个核心,就能在 Java 开发的海洋中乘风破浪!