Spring框架作为Java EE开发领域的标杆性框架,凭借其轻量级、分层架构设计,彻底解决了传统Java开发中代码耦合度高、配置繁琐等痛点。本文将从Spring框架基础认知出发,通过Hello World实战案例切入,逐步深入IOC容器、Bean管理、Bean作用域与生命周期等核心知识点,最后扩展Lombok与Spring的整合技巧,帮助开发者快速掌握Spring核心用法并提升开发效率。
一、Spring框架的核心认知
1.1 Spring框架概述
Spring是一款开源的设计层面框架,核心目标是解决业务逻辑层与其他各层的紧耦合问题,将面向接口的编程思想贯穿整个应用开发。它诞生于2003年,由Rod Johnson在其著作《Expert One-On-One J2EE Development and Design》中阐述的理念与原型衍生而来,专为简化企业级应用开发的复杂性而创建。
Spring最显著的优势在于其分层架构,开发者可按需选择使用框架中的特定组件,同时它为Java EE应用开发提供了一站式的集成解决方案。从本质上讲,Spring是一个分层的Java SE/EE full-stack(一站式)轻量级开源框架,其核心功能围绕两大核心机制展开:
-
IOC(控制反转) :将对象的创建权力从开发者手中反转给Spring框架管理,无需手动通过
new关键字创建对象,极大降低了代码耦合度。 -
AOP(面向切面):在不修改原有源代码的前提下,对代码功能进行增强(如权限拦截、运行监控、事务管理等),实现代码的解耦与复用。
1.2 Spring框架的核心优势
Spring之所以能成为Java开发的主流框架,源于其强大的功能特性与易用性,具体优势如下:
-
解耦简化开发:Spring充当"对象工厂"的角色,统一管理所有对象的创建与依赖关系维护,通过IOC机制彻底解决代码紧耦合问题。
-
原生支持AOP编程:提供完善的AOP解决方案,可轻松实现日志记录、性能监控、权限校验等横切逻辑,无需侵入业务代码。
-
声明式事务管理:通过简单的配置即可完成事务管理,无需手动编写事务控制代码,降低了事务管理的复杂度与出错率。
-
便捷的测试支持:无缝集成Junit4等测试框架,通过注解即可快速实现Spring程序的单元测试与集成测试。
-
兼容主流开源框架:不排斥其他优秀开源框架,内部提供了对Struts2、Hibernate、MyBatis等框架的直接集成支持,降低技术选型成本。
-
简化Java EE API使用:对JDBC、JavaMail、JMS等难用的Java EE API进行封装,提供简洁的API调用方式,降低开发难度。
二、Spring入门实战:Hello World案例
本节通过经典的Hello World案例,演示Spring框架的基础使用流程,包括Maven工程创建、依赖导入、配置文件编写、代码实现与测试。
2.1 环境准备:创建Maven工程并导入依赖
首先创建Maven工程,在pom.xml文件中导入Spring核心依赖及相关辅助依赖:
XML
<dependencies>
<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>
核心依赖说明:spring-context是Spring核心上下文依赖,包含IOC容器的核心实现;其他依赖用于日志输出与单元测试。
2.2 编写业务逻辑类
创建com.qcby.service.Demo类,实现简单的Hello World输出方法:
java
package com.xxx.service;
public class Demo {
public void hello() {
System.out.println("hello world");
}
}
2.3 编写Spring核心配置文件
在resources目录下创建Spring核心配置文件applicationContext.xml(文件名可自定义,推荐使用默认名称),通过配置将Demo类交由Spring IOC容器管理:
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">
<!--IOC管理bean-->
<!--id:类的唯一标识:类的全路径名-->
<bean id="demo" class="com.xxx.service.Demo" />
</beans>
配置说明:<bean>标签用于定义Spring管理的对象,id属性是对象的唯一标识,class属性指定类的全路径名。
2.4 编写测试类
创建测试类com.qcby.servic.UserServiceTest,分别通过传统方式与Spring方式调用hello()方法,对比两种方式的差异:
java
package com.xxx.servic;
import com.xxx.service.Demo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceTest {
//spring写法:从IOC容器获取对象
@Test
public void run1(){
//创建spring工厂
ApplicationContext ac = new ClassPathXmlApplicationCoApplicationContext.xml");
//获取bean对象
Demo us = (Demo) ac.getBean("us");
//调用方法
us.hello();
}
三、Spring核心:IOC容器深度解析
IOC(控制反转)是Spring框架的核心,而IOC容器则是IOC思想的具体落地实现。本节将深入讲解IOC思想的本质、IOC容器的底层原理及两种核心实现方式。
3.1 什么是IOC思想?
IOC(Inverse of Control,控制反转)是一种面向对象编程的设计原则,核心是"反转对象创建的控制权"。在传统Java开发中,若A类需要使用B类的方法,必须在A类内部通过new B()手动创建B对象,这种方式会导致代码紧耦合------若B类的构造方法发生变化,A类也需要同步修改。
更严重的是,若出现"循环依赖"(如A类依赖B类、B类依赖C类、C类依赖A类),传统方式会导致代码维护成本急剧增加。而Spring IOC容器则解决了这一问题:由IOC容器统一创建所有对象并管理对象间的依赖关系,开发者只需从容器中获取所需对象即可,无需关心对象的创建过程,彻底降低了代码耦合度。
一句话总结:IOC的核心价值是解耦,将对象的创建权从开发者反转给框架,实现代码的模块化与可维护性提升。
3.2 IOC容器的底层原理
Spring IOC容器的实现依赖于三大核心技术,缺一不可:
-
DOM4J:用于解析XML格式的配置文件,获取配置中定义的bean信息(如类的全路径名、属性等)。
-
工厂模式 :通过工厂类统一创建对象,替代手动
new操作,降低对象创建与使用的耦合度。 -
反射机制:根据XML配置中获取的类全路径名,通过Java反射机制动态创建对象,实现对象创建的灵活性。
IOC容器的核心工作流程(简化版)如下:
-
配置阶段 :开发者在XML配置文件中通过
<bean>标签定义需要Spring管理的对象,如:<bean id="demo" class="com.qcby.service.Demo" />。 -
解析阶段 :Spring容器启动时,通过DOM4J解析XML配置文件,获取
bean的id和class属性(类的全路径名)。 -
工厂创建对象 :Spring内部通过工厂类(如
BeanFactory),利用反射机制根据类全路径名创建对象。简化的工厂类实现如下:
java
public class DemoFactory {
//利用dom4j得到name所对应的value值(类全路径名)
public static Demo getDemo() throws Exception {
//通过DOM4J解析XML获取类全路径名
String value = "com.xxx.service.Demo";
//通过反射创建对象
Class clazz = Class.forName(value);
//返回创建的对象(默认调用无参构造方法)
return (Demo) clazz.newInstance();
}
}
通过以上流程,Spring容器即可完成对象的创建与管理,开发者只需调用工厂方法或容器API获取对象即可。
3.3 Spring IOC容器的两种实现方式
Spring提供了两种IOC容器的实现方式,均继承自BeanFactory接口,适用于不同的开发场景:
3.3.1 BeanFactory(基础容器)
BeanFactory是Spring IOC容器的最顶层接口,是Spring内部使用的核心接口,不推荐开发者直接使用。其核心特点是:懒加载 ------加载配置文件时不会立即创建对象,只有在调用getBean()方法获取对象时,才会创建对象。
这种方式的优势是节省内存资源,适用于资源有限的场景(如嵌入式设备),但由于对象创建时机较晚,无法提前发现配置错误(如类路径写错)。
3.3.2 ApplicationContext(增强容器)
ApplicationContext是BeanFactory的子接口,提供了更强大的功能(如国际化支持、事件发布、资源访问等),是开发者最常用的IOC容器实现。其核心特点是:预加载 ------加载配置文件时会立即创建所有配置的singleton类型对象。
这种方式的优势是提前初始化对象,后续获取对象时速度更快,且能提前发现配置错误,适用于绝大多数企业级应用开发。常用的实现类有:
-
ClassPathXmlApplicationContext:加载类路径下的XML配置文件。 -
FileSystemXmlApplicationContext:加载本地文件系统中的XML配置文件。 -
AnnotationConfigApplicationContext:加载注解式配置类(纯注解开发场景)。
四、Bean的作用域
Bean的作用域定义了Spring IOC容器中Bean实例的创建方式与存活范围。通过在<bean>标签中设置scope属性,可指定Bean的作用域。Spring 5共提供6种作用域,其中最常用的是singleton和prototype。
4.1 核心作用域详解
4.1.1 singleton(单例模式)
singleton是Spring容器的默认作用域。当Bean的作用域为singleton时,Spring IOC容器中只会创建一个该Bean的共享实例,所有获取该Bean的请求都会返回同一个实例(对象地址相同)。
特点:对象在容器初始化时创建(预加载),生命周期与容器一致(容器关闭时对象销毁),适用于无状态对象(如工具类、服务层对象)。
配置方式(默认可省略):<bean id="demo" class="com.qcby.service.Demo" scope="singleton" />
4.1.2 prototype(原型模式)
若Bean的作用域为prototype,则Spring容器会在每次调用getBean()方法获取该Bean时,创建一个新的实例。每次获取的Bean实例都是独立的,对象地址不同。
特点:懒加载(容器初始化时不创建对象),对象的销毁由JVM垃圾回收机制负责(Spring容器不管理prototype Bean的销毁),适用于有状态对象(如请求级别的数据模型)。
配置方式:<bean id="demo" class="com.qcby.service.Demo" scope="prototype" />

4.1.3 其他作用域(Web场景专用)
除上述两种核心作用域外,Spring还提供4种适用于Web应用的作用域,仅在Web环境下生效:
-
request:每次HTTP请求创建一个新Bean,请求结束后Bean销毁。 -
session:每个HTTP Session创建一个新Bean,Session失效后Bean销毁。 -
application:整个Web应用共享一个Bean,应用启动时创建,应用停止时销毁。 -
websocket:每个WebSocket连接创建一个新Bean,连接关闭时Bean销毁。
五、Spring框架的Bean管理
Bean管理是Spring IOC容器的核心功能,指Spring对Bean的"创建对象"和"注入属性"两大操作的管理。Spring提供两种Bean管理方式:基于XML配置文件的方式和基于注解的方式。

5.1 基于XML配置文件的Bean管理
基于XML的方式是Spring早期的主流Bean管理方式,通过XML配置文件定义Bean的创建规则与属性注入规则,适用于复杂的配置场景。
5.1.1 基于XML创建Bean对象
通过<bean>标签即可完成Bean对象的创建,核心配置如下:
XML
<bean id="demo" class="com.xxx.service.Demo" />
关键说明:
-
id:Bean的唯一标识符,用于在容器中定位Bean(不可重复)。 -
class:Bean对应的类的全路径名,Spring通过该路径反射创建对象。 -
创建对象的核心规则:Spring默认通过无参构造方法 创建Bean对象。若类中没有无参构造方法(仅定义了有参构造),且未在XML中指定构造方法参数,则会抛出
NoSuchMethodException异常。
5.1.2 基于XML注入属性(DI依赖注入)
DI(Dependency Injection,依赖注入)是IOC的具体体现,指Spring容器在创建Bean对象时,自动将依赖的属性值或其他Bean对象注入到当前Bean中。常用的注入方式有两种:set方法注入和构造方法注入。
1. set方法注入(最常用)
set方法注入要求Bean类中为需要注入的属性提供对应的setter方法,Spring容器通过反射调用setter方法完成属性注入。支持注入普通类型、引用类型、数组、集合等多种数据类型。
(1)注入普通类型与引用类型
创建User类,定义属性并提供setter方法:
java
public class User {
private int age;
private String name;
private Demo demo;
// 为每个属性提供setter方法
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setDemo(Demo demo) {
this.demo = demo;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", demo=" + demo +
'}';
}
}
在XML配置文件中通过<property>标签完成注入:
XML
<!--配置Demo Bean-->
<bean id="demo" class="com.xxx.service.Demo" />
<!--配置User Bean并注入属性-->
<bean id="user" class="com.xxx.service.User" >
<!--注入普通类型:name=属性名,value=属性值-->
<property name="age" value="18"></property>
<property name="name" value="张三"></property>
<!--注入引用类型:ref=依赖的Bean的id-->
<property name="demo" ref="demo"></property>
</bean>
测试代码:
java
@Test
public void run1(){
//创建Spring容器,加载配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//获取User对象
User user = ac.getBean("user", User.class);
//输出结果:User{age=18, name='张三', demo=com.qcby.service.Demo@xxx}
System.out.println(user.toString());
}
(2)注入数组、List、Map等集合类型
创建CollectionBean类,定义集合属性并提供setter方法:
java
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class CollectionBean {
private String [] strs;
private List<String> list;
private Map<String,String> map;
// 提供setter方法
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;
}
@Override
public String toString() {
return "CollectionBean{" +
"strs=" + Arrays.toString(strs) +
", list=" + list +
", map=" + map +
'}';
}
}
在XML配置文件中通过对应集合标签完成注入:
XML
<bean id="collectionBean" class="com.xxx.service.CollectionBean">
<!--注入数组:使用<array>标签-->
<property name="strs">
<array>
<value>美美</value>
<value>小凤</value>
</array>
</property>
<!--注入List:使用<list>标签-->
<property name="list">
<list>
<value>熊大</value>
<value>熊二</value>
</list>
</property>
<!--注入Map:使用<map>标签,entry对应键值对-->
<property name="map">
<map>
<entry key="aaa" value="老王"/>
<entry key="bbb" value="小王"/>
</map>
</property>
</bean>
2. 构造方法注入
构造方法注入通过Bean类的有参构造方法完成属性注入,无需提供setter方法。适用于属性必须初始化的场景(如创建对象时必须指定核心属性)。
创建Car类,定义有参构造方法:
java
public class Car {
private String cname;
private Double money;
// 有参构造方法(无参构造可省略,但若存在其他有参构造,建议显式定义)
public Car(String cname, Double money){
this.cname = cname;
this.money = money;
}
@Override
public String toString() {
return "Car{" +
"cname='" + cname + '\'' +
", money=" + money +
'}';
}
}
在XML配置文件中通过<constructor-arg>标签完成注入:
XML
<bean id="car" class="com.xxx.service.Car">
<!--name=构造方法参数名,value=参数值-->
<constructor-arg name="cname" value="奔驰"></constructor-arg>
<constructor-arg name="money" value="35"></constructor-arg>
</bean>
测试代码:
java
@Test
public void run(){
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
Car car = ac.getBean("car", Car.class);
//输出结果:Car{cname='奔驰', money=35.0}
System.out.println(car.toString());
}
同理,集合类型也可通过构造方法注入,只需在<constructor-arg>标签内部嵌套集合标签(<array>、<list>、<map>等)即可。
5.2 基于注解的Bean管理
基于注解的Bean管理是Spring后期推出的简化方案,通过在Java类、方法、属性上添加注解,替代XML配置文件的繁琐配置,大幅提升开发效率。
5.2.1 核心注解说明
Spring提供以下核心注解用于Bean管理:
1. 用于创建Bean对象的注解(替代<bean>标签)
-
@Component:通用注解,用于标识普通类为Spring管理的Bean。 -
@Controller:专门用于标识表现层(Controller)类,语义化注解,功能与@Component一致。 -
@Service:专门用于标识业务层(Service)类,语义化注解。 -
@Repository:专门用于标识持久层(Dao)类,语义化注解。
说明:以上四个注解功能完全一致,均可创建Bean实例。默认Bean的id为类名首字母小写(如UserServiceImpl对应的id为userServiceImpl),也可通过注解的value属性自定义id(如@Controller(value="us"))。
2. 用于注入属性的注解(替代<property>标签)
-
@Value:用于注入普通类型(String、int、double等),直接指定属性值。 -
@Autowired:用于注入引用类型,默认按"类型匹配"自动装配(即查找容器中与属性类型一致的Bean)。 -
@Qualifier:与@Autowired搭配使用,强制按"名称匹配"自动装配(需指定Bean的id),不能单独使用。 -
@Resource:Java原生注解(JSR-250规范),Spring支持该注解,默认按"名称匹配"自动装配(通过name属性指定Bean的id),无name属性时按类型匹配。
5.2.2 基于注解创建Bean对象
步骤1:编写接口与实现类,在实现类上添加创建Bean的注解。
java
// 接口
package com.xxx.testanno;
public interface UserService {
public void hello();
}
// 实现类,添加@Controller注解交由Spring管理
package com.xxx.testanno;
import org.springframework.stereotype.Controller;
// 自定义Bean的id为"us"
@Controller(value="us")
public class UserServiceImpl implements UserService {
public void hello() {
System.out.println("使用注解,方便吧!");
}
}
步骤2:编写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">
<!--开启注解扫描:扫描com.qcby包下所有类的注解-->
<context:component-scan base-package="com.qcby"/>
</beans>
步骤3:编写测试类。
java
package com.xxx.test;
import com.xxx.testanno.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo2 {
@Test
public void run1(){
//加载Spring配置文件,启动容器
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContextanno.xml");
//按id获取Bean对象
UserService us = (UserService) ac.getBean("us");
//调用方法,输出:使用注解,方便吧!
us.hello();
}
}
5.2.3 基于注解注入属性
以Car类和Person类为例,演示注解注入属性的用法:
java
// Person类
package com.xxx.testanno;
import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Value;
@Controller
public class Person {
// 注入普通类型:直接指定属性值
@Value("张三")
private String pname;
@Override
public String toString() {
return "Person{" +
"pname='" + pname + '\'' +
'}';
}
}
// Car类
package com.xxx.testanno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 自定义Bean的id为"c"
@Component(value = "c")
public class Car {
// 注入普通类型:value属性可省略(仅当注解只有value一个属性时)
@Value("大奔2")
private String cname;
@Value(value = "400000")
private Double money;
// 注入引用类型:按类型自动装配Person对象
@Autowired
// 若存在多个Person类型的Bean,可通过@Qualifier指定id:@Qualifier(value = "person")
// 也可使用@Resource(name = "person")按名称装配
private Person person;
@Override
public String toString() {
return "Car{" +
"cname='" + cname + '\'' +
", money=" + money +
", person=" + person +
'}';
}
}
测试代码:
java
@Test
public void run1(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取Car对象
Car car = (Car) ac.getBean("c");
//输出结果:Car{cname='大奔2', money=400000.0, person=Person{pname='张三'}}
System.out.println(car);
}
关键说明:使用注解注入属性时,无需为属性提供setter方法,Spring通过反射直接为属性赋值,简化了代码编写。
5.3 纯注解开发(无XML配置)
纯注解开发是Spring Boot的核心开发方式,完全摒弃XML配置文件,通过"配置类+注解"实现所有Bean管理功能。核心是使用@Configuration注解标识配置类,替代applicationContext.xml文件。
1. 核心注解
-
@Configuration:标识当前类为Spring的配置类,替代XML配置文件。 -
@ComponentScan:开启注解扫描,替代XML中的<context:component-scan>标签,通过value属性指定扫描的包路径。
2. 纯注解开发实战
步骤1:编写实体类Order。
java
package com.xxx.demo4;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Order {
@Value("北京")
private String address;
@Override
public String toString() {
return "Order{" +
"address='" + address + '\'' +
'}';
}
}
步骤2:编写配置类SpringConfig。
java
package com.xxx.demo4;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
// 标识为配置类
@Configuration
// 开启注解扫描,扫描com.qcby包下所有类
@ComponentScan(value = "com.qcby")
public class SpringConfig {
}
步骤3:编写测试类(使用AnnotationConfigApplicationContext加载配置类)。
java
package com.xxx.test;
import com.qcby.demo4.Order;
import com.qcby.demo4.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Demo4 {
@Test
public void run(){
// 加载配置类,启动Spring容器
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
// 获取Order对象
Order order = (Order) ac.getBean("order");
// 输出结果:Order{address='北京'}
System.out.println(order);
}
}
纯注解开发的优势:配置简洁、开发高效,是微服务架构的主流开发方式,也是Spring Boot和Spring Cloud的基础。