Spring 框架核心技术全解析
Spring 框架作为 Java 后端开发的基石,核心围绕控制反转(IOC) 和面向切面编程(AOP) 两大思想,旨在简化开发、降低模块耦合。本文基于 Spring 5.0.2 版本,从框架介绍、IOC/DI 核心用法、注解开发到 JUnit 整合,全方位拆解 Spring 上半部分核心知识点,附带完整实战代码,适合入门者系统学习。
一、Spring 框架核心认知
1. 什么是 Spring?
Spring 是 2003 年兴起的轻量级 Java EE 一站式框架,由 Rod Johnson 创建。它以 IOC 和 AOP 为核心,解决了业务逻辑层与其他层的耦合问题,支持分层开发(表现层、业务层、持久层),且能无缝集成 MyBatis、Struts2 等主流框架。
2. Spring 的核心优势
- 解耦简化开发:IOC 容器统一管理对象创建和依赖关系,无需手动 new 对象。
- AOP 编程支持:轻松实现权限拦截、日志记录等横切逻辑,不侵入业务代码。
- 声明式事务:通过配置而非硬编码管理事务,降低开发复杂度。
- 便捷测试:与 JUnit 深度整合,简化测试代码编写。
- 兼容优秀框架:内置对 MyBatis、Hibernate、Quartz 等框架的支持。
- 封装复杂 API:简化 JDBC、JavaMail 等难用的 Java EE API。
二、核心技术:IOC 控制反转
1. IOC 核心概念
IOC(Inverse of Control)即控制反转,指将对象的创建权从开发者手中 “反转” 给 Spring 框架。开发者无需手动通过new关键字创建对象,而是由 Spring 容器根据配置文件或注解自动实例化对象,彻底解决代码耦合问题。
2. IOC 入门实战(XML 配置方式)
(1)导入依赖(Maven)
<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)编写业务接口与实现类
// 接口
public interface UserService {void hello();
}// 实现类
public class UserServiceImpl implements UserService {@Overridepublic void hello() {System.out.println("Hello IOC!!");}
}
(3)编写 Spring 配置文件(applicationContext.xml)
在resources目录下创建配置文件,声明 Bean 交给 Spring 管理:
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 配置Bean:id为Bean名称,class为全类名 --><bean id="userService" class="com.qcbyjy.service.UserServiceImpl" />
</beans>
(4)编写测试类
通过 Spring 容器获取 Bean 并调用方法:
public class Demo1 {@Testpublic void run1() {// 加载Spring配置文件,初始化容器ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");// 从容器中获取Bean(按id查找)UserService userService = (UserService) ac.getBean("userService");// 调用方法userService.hello(); // 输出:Hello IOC!!}
}
3. Bean 的核心配置详解
(1)Bean 的作用范围(scope 属性)
singleton:单例(默认值),容器中只创建一个 Bean 实例,全局共享。prototype:多例,每次调用getBean()都会创建新实例。request:Web 环境专用,每次 HTTP 请求创建新 Bean。session:Web 环境专用,同一个 Session 共享一个 Bean。
配置示例:
<bean id="userService" class="com.qcbyjy.service.UserServiceImpl" scope="prototype" />
(2)Bean 的生命周期配置
init-method:Bean 初始化后执行的方法。destroy-method:Bean 销毁前执行的方法(单例 Bean 随容器关闭销毁,多例 Bean 由垃圾回收销毁)。
配置示例:
// 实现类中添加初始化和销毁方法
public class UserServiceImpl implements UserService {public void init() {System.out.println("Bean初始化...");}public void destroy() {System.out.println("Bean销毁...");}// 业务方法...
}
<bean id="userService" class="com.qcbyjy.service.UserServiceImpl" init-method="init" destroy-method="destroy" />
(3)Bean 的三种实例化方式
默认无参构造(推荐):最常用,要求类必须有默认无参构造方法。
<bean id="userService" class="com.qcbyjy.service.UserServiceImpl" />静态工厂实例化:通过静态方法创建 Bean。
// 静态工厂类 public class StaticFactory {public static UserService createUserService() {return new UserServiceImpl();} }<bean id="userService" class="com.qcbyjy.demo1.StaticFactory" factory-method="createUserService" />实例工厂实例化:通过工厂实例的非静态方法创建 Bean。
// 实例工厂类 public class InstanceFactory {public UserService createUserService() {return new UserServiceImpl();} }<!-- 先配置工厂Bean --> <bean id="factory" class="com.qcbyjy.demo1.InstanceFactory" /> <!-- 通过工厂Bean创建目标Bean --> <bean id="userService" factory-bean="factory" factory-method="createUserService" />
三、核心技术:DI 依赖注入
1. DI 核心概念
DI(Dependency Injection)即依赖注入,是 IOC 的具体实现。Spring 容器在创建 Bean 时,会自动将依赖的其他 Bean 或属性值注入到当前 Bean 中,无需开发者手动设置。
2. 依赖注入的三种常用方式
(1)Set 方法注入(最常用)
通过 Bean 的setXxx()方法注入依赖,适用于大多数场景。
示例:注入引用类型(Service 依赖 Dao)+ 基本类型
// Service实现类
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;}@Overridepublic void saveOrder() {System.out.println("业务层:保存订单..." + msg + " - " + age);orderDao.saveOrder();}
}// Dao实现类
public class OrderDaoImpl implements OrderDao {@Overridepublic void saveOrder() {System.out.println("持久层:保存订单...");}
}
配置文件:
<!-- 配置Dao Bean -->
<bean id="orderDao" class="com.qcbyjy.dao.OrderDaoImpl" /><!-- 配置Service Bean,注入依赖 -->
<bean id="orderService" class="com.qcbyjy.service.OrderServiceImpl"><!-- 注入引用类型:ref指向目标Bean的id --><property name="orderDao" ref="orderDao" /><!-- 注入基本类型:value直接赋值 --><property name="msg" value="Spring DI" /><property name="age" value="20" />
</bean>
(2)构造方法注入
通过 Bean 的带参构造方法注入依赖,适用于依赖必须存在的场景。
示例:
public class Car {private String cname;private Double money;// 带参构造方法public Car(String cname, Double money) {this.cname = cname;this.money = money;}@Overridepublic String toString() {return "Car{" + "cname='" + cname + '\'' + ", money=" + money + '}';}
}
配置文件:
xml
<bean id="car" class="com.qcbyjy.demo2.Car"><constructor-arg name="cname" value="大奔" /><constructor-arg name="money" value="400000" />
</bean>
(3)集合类型注入
支持数组、List、Set、Map、Properties 等集合类型的注入。
示例:
public class CollectionBean {private String[] strs; // 数组private List<String> list; // Listprivate Map<String, String> map; // Mapprivate Properties properties; // Properties// 提供set方法public void setStrs(String[] strs) { this.strs = strs; }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; }// toString方法...
}
配置文件:
<bean id="collectionBean" class="com.qcbyjy.demo3.CollectionBean"><!-- 数组注入 --><property name="strs"><array><value>张三</value><value>李四</value></array></property><!-- List注入 --><property name="list"><list><value>王五</value><value>赵六</value></list></property><!-- Map注入 --><property name="map"><map><entry key="user1" value="小明" /><entry key="user2" value="小红" /></map></property><!-- Properties注入 --><property name="properties"><props><prop key="username">root</prop><prop key="password">123456</prop></props></property>
</bean>
四、IOC 注解开发(简化配置)
XML 配置繁琐,Spring 提供注解方式替代 XML,更适合现代开发。
1. 注解开发入门
(1)核心依赖
与 XML 方式一致,无需额外导入依赖。
(2)开启注解扫描
在 XML 配置文件中添加注解扫描,Spring 会自动扫描指定包下的注解:
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 开启注解扫描:扫描com.qcbyjy包下所有类 --><context:component-scan base-package="com.qcbyjy" />
</beans>
(3)Bean 注册注解
使用以下注解将类交给 Spring 管理(作用相同,分层标识不同):
@Component:通用注解,适用于任意类。@Controller:表现层(Web 层)专用。@Service:业务层专用。@Repository:持久层专用。
示例:
// 业务层类,指定Bean名称为"userService"
@Service(value = "userService")
public class UserServiceImpl implements UserService {@Overridepublic void hello() {System.out.println("Hello IOC注解...");}
}
(4)依赖注入注解
@Value:注入基本类型(String、int 等)。@Autowired:默认按类型注入引用类型,需容器中存在唯一对应类型的 Bean。@Qualifier:与@Autowired搭配,按名称注入(解决同类型多个 Bean 的冲突)。@Resource:Java 原生注解,按名称注入(name属性指定 Bean 名称)。
示例:
@Component(value = "car")
public class Car {// 注入基本类型(无需set方法)@Value("大奔")private String cname;@Value("400000")private Double money;// 注入引用类型(按类型+名称)@Autowired@Qualifier(value = "person")private Person person;// 初始化方法(替代init-method)@PostConstructpublic void init() {System.out.println("Car初始化...");}// toString方法...
}@Component(value = "person")
public class Person {@Value("张三")private String pname;// toString方法...
}
(5)Bean 作用范围注解
@Scope:指定 Bean 作用范围,取值singleton(默认)或prototype。
示例:
@Service
@Scope(value = "prototype") // 多例
public class UserServiceImpl implements UserService {// 业务方法...
}
2. 纯注解开发(无 XML)
纯注解开发是 Spring Boot 的基础,通过配置类替代 XML 文件。
(1)核心注解
@Configuration:声明当前类为 Spring 配置类。@ComponentScan:指定注解扫描包(替代<context:component-scan>)。@Import:导入其他配置类(拆分配置时使用)。@Bean:在方法上使用,手动创建 Bean 并交给 Spring 管理(适用于第三方类,如连接池)。
(2)纯注解开发实战
① 编写配置类
@Configuration // 声明为配置类
@ComponentScan(basePackages = "com.qcbyjy.demo4") // 扫描包
@Import(SpringConfig2.class) // 导入其他配置类
public class SpringConfig {// 手动创建第三方Bean(如Druid连接池)@Bean(name = "dataSource") // Bean名称为dataSourcepublic DataSource createDataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_db");dataSource.setUsername("root");dataSource.setPassword("root");return dataSource;}
}// 其他配置类
@Configuration
public class SpringConfig2 {// 可配置其他Bean...
}
② 编写业务类
java
运行
@Component
public class Order {@Value("北京")private String address;@Overridepublic String toString() {return "Order{" + "address='" + address + '\'' + '}';}
}
③ 编写测试类
public class Demo4 {@Testpublic void run1() {// 加载配置类,初始化容器ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);// 获取BeanOrder order = (Order) ac.getBean("order");DataSource dataSource = (DataSource) ac.getBean("dataSource");System.out.println(order); // 输出:Order{address='北京'}System.out.println(dataSource); // 输出Druid连接池对象}
}
五、Spring 整合 JUnit 单元测试
传统测试需要手动加载 Spring 容器,整合 JUnit 后可自动注入 Bean,简化测试代码。
1. 导入依
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version><scope>test</scope>
</dependency>
2. 整合方式一:XML 配置
// 指定JUnit运行器为Spring提供的运行器
@RunWith(SpringJUnit4ClassRunner.class)
// 加载XML配置文件
@ContextConfiguration(locations = "classpath:applicationContext_test.xml")
public class Demo5 {// 自动注入Bean@Autowiredprivate User user;@Testpublic void run1() {user.sayHello(); // 直接调用方法,无需手动创建容器}
}
3. 整合方式二:纯注解配置
@RunWith(SpringJUnit4ClassRunner.class)
// 加载配置类
@ContextConfiguration(classes = SpringConfig6.class)
public class Demo6 {@Autowiredprivate Customer customer;@Testpublic void run1() {customer.save(); // 输出:保存客户...}
}// 配置类
@Configuration
@ComponentScan("com.qcbyjy.demo6")
public class SpringConfig6 {
}
六、总结
Spring 上半部分核心围绕 IOC/DI 展开,关键在于理解 “对象由容器管理,依赖由容器注入” 的思想。开发中可根据场景选择 XML 或注解方式:
- 小型项目:XML 配置简单直观。
- 中大型项目 / 微服务:纯注解开发更高效,是 Spring Boot 的基础。
后续将深入学习 Spring AOP、声明式事务等高级特性,掌握这些技术后,能大幅提升开发效率和代码质量。
