Spring框架1
- [Spring 框架的概述](#Spring 框架的概述)
- [Spring 的 IOC 核心技术](#Spring 的 IOC 核心技术)
-
- [Bean 管理的配置文件方式](#Bean 管理的配置文件方式)
- [实例化 Bean 的三种方式](#实例化 Bean 的三种方式)
- [DI 依赖注入](#DI 依赖注入)
- 多配置文件方式
Spring 框架的概述
Spring 是一个开源的企业级 Java 应用开发框架,由 Rod Johnson 于 2003 年基于其著作《Expert One-On-One J2EE Development and Design》中阐述的设计理念与原型开发而成。该框架的核心设计目标是解决企业级应用开发的复杂性,尤其聚焦于消除业务逻辑层与数据访问层、表现层等其他层级之间的紧耦合问题 ------ 而这一目标的实现,核心在于将面向接口编程的思想贯穿于整个应用的设计与实现过程。
从架构特性来看,Spring 具备三个关键属性:其一,轻量级,即无需依赖重量级的 J2EE 容器即可运行,且核心组件体积小、资源消耗低;其二,分层架构,框架按功能划分为核心容器、AOP 模块、数据访问 / 集成模块等独立组件,使用者可根据需求选择性引入,而非强制依赖全量组件,避免功能冗余;其三,一站式,Spring 并非对现有技术的替代,而是通过整合与封装,为开发者提供一站式解决方案,覆盖了从 JavaSE 基础开发到 JavaEE 企业级应用开发的全流程需求,提供了从依赖注入到事务管理、从 Web 开发到数据持久化的完整解决方案支持。
Spring 框架的核心支柱是控制反转(IoC,Inversion of Control) 与面向切面编程(AOP,Aspect-Oriented Programming):
- IoC 通过将对象的创建、依赖关系管理等职责从业务逻辑代码中剥离,交由容器统一管控,实现了组件间的解耦,提升了代码的可维护性与可测试性;
- AOP 则通过将日志记录、事务管理、权限控制等横切关注点模块化,实现了业务逻辑与非业务逻辑的分离,增强了系统的扩展性。
Spring 框架的核心优势:
- 方便解耦,简化依赖管理:基于 IoC 容器实现对象的生命周期与依赖关系的自动化管理,消除了手动创建对象与维护依赖的代码,降低了组件间的耦合度。
- 支持 AOP 编程:提供完善的 AOP 实现,可通过声明式方式将横切关注点植入业务逻辑,避免代码侵入,提升系统模块化程度。
- 声明式事务管理:基于 AOP 实现事务管理,开发者无需通过硬编码控制事务,仅需通过配置即可完成事务的定义、传播行为与隔离级别设置,简化了事务操作。
- 增强可测试性:原生支持与 JUnit、TestNG 等测试框架的集成,通过注解可便捷地实现依赖注入,降低测试环境搭建的复杂度。
- 兼容主流框架:设计上保持开放性,内部提供对 MyBatis、Hibernate 等 ORM 框架,以及 Quartz、Redis 等工具的集成支持,避免技术栈锁定。
- 简化 JavaEE API 使用:对 JDBC、JavaMail、远程调用等复杂 JavaEE API 进行封装(如JdbcTemplate),屏蔽底层细节,降低 API 使用门槛。
Spring 的 IOC 核心技术
Spring 的 IOC(Inversion of Control,控制反转)是面向对象编程的重要设计原则,其核心思想是将对象的创建、依赖关系的管理等控制权从应用程序代码本身转移到 Spring 的 IOC 容器,实现了控制权的反转。这种机制的核心价值在于解耦,有效降低代码之间的直接耦合,从而提升系统的可维护性、可扩展性和可测试性。
Spring 的 IOC 容器是实现控制反转思想的核心载体,IoC 容器负责:
- Bean 的创建与实例化:容器根据配置信息,自动创建应用程序所需的对象,开发者无需手动通过 new 关键字创建对象,而是由容器根据规则完成实例化;
- 通过依赖注入配置依赖项:容器会自动分析并处理 Bean 之间的依赖关系;
- 管理 Bean 的整个生命周期:从对象创建、初始化、使用、到最终的销毁,以及开发者无需关心对象的销毁时机和资源释放;
- 读取配置元数据:容器会加载并解析所有配置源(XML、注解、Java 配置类等),将 Bean 的定义信息(如类名、作用域、依赖关系等)进行统一管理,作为创建和管理 Bean 的依据。
下面我们一起来编写 IOC 的入门程序
首先是需要创建 maven Java 工程,导入坐标依赖
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>
编写接口和实现类,编写具体的实现方法
java
package com.qcby.service;
public interface UserService {
public void hello();
}
java
package com.qcby.service.impl;
import com.qcby.service.UserService;
public class UserServiceImpl implements UserService {
public void hello() {
System.out.println("hello Ioc !!!");
}
}
Spring 负责管理对象的创建过程,因此需要处理可实例化的类。由于 UserService 接口本身无法被实例化,交由 Spring 管理没有实际意义,因此 Spring 实际管理的是该接口的具体实现类 UserServiceImpl。
Bean 管理的配置文件方式
编写 Spring 核心配置文件,在 src 的 resources 目录下创建 applicationContext.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">
<!--IOC 管理 bean-->
<bean id="userService" class="com.qcby.service.impl.UserServiceImpl" />
</beans>
容器管理的对象称为 bean
- id 属性即为 bean 起个名字,在约束中采用 ID 的约束,唯一,必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号
- class 属性即为 bean 对象的全路径
- scope 属性代表 Bean 的作用范围:
singleton 单例
prototype 多例
request 应用在 Web 项目中,每次 HTTP 请求都会创建一个新的 Bean
session 应用在 Web 项目中,同一个 HTTP Session 共享一个 Bean - Bean 对象的创建和销毁的两个属性配置
Spring 初始化 bean 或销毁 bean 时,有时需要作一些处理工作,因此 spring 可以在创建和拆卸 bean 的时候调用 bean 的两个生命周期方法
init-method,当 bean 被载入到容器的时候调用 init-method 属性指定的方法
destroy-method,当 bean 从容器中删除的时候调用 destroy-method 属性指定的方法
把 log4j.properties 的配置文件拷贝到 resources 目录下,做为 log4j 的日志配置文件

配置当 bean 被载入到容器的时候调用 init-method 属性指定的方法
xml
<bean id="userService" class="com.qcby.service.impl.UserServiceImpl" init-method="init"/>
java
public class UserServiceImpl implements UserService {
public void hello() {
System.out.println("hello Ioc !!!");
}
public void init(){
System.out.println("对象创建完成,进行初始化操作...");
}
}
Spring 提供了两种类型的容器:
- BeanFactory 容器
是提供依赖注入支持的基本容器,在这种情况下只有在显式请求时才会实例化 bean,重量轻适用于资源受限的环境 - ApplicationContext 容器
是建立在 BeanFactory 之上的高级容器,它包括 BeanFactory 的所有功能,并添加了额外的功能,在这种情况下 Bean 是在启动时创建和配置的
ApplicationContext 是 Spring 的核心工厂接口,,主要用于获取容器中的 Bean 实例。该接口下有两个具体的实现类:
ClassPathXmlApplicationContext,加载类路径下的 Spring 配置文件
FileSystemXmlApplicationContext,加载本地磁盘下的 Spring 配置文件
java
package com.qcby;
import com.qcby.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo1 {
@Test
public void run1(){
// 使用 Spring 的工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类
UserService userService = (UserService) applicationContext.getBean("userService");
userService.hello();
}
}
需要注意的是 Spring 容器中 bean 的默认作用域是 singleton(单例),当一个 bean 被定义为单例时,Spring 容器在整个应用生命周期内只会创建该 bean 的一个实例,所有获取该 bean 的请求(getBean())都会返回同一个实例

Spring 的单例作用域是容器级别的,每个 applicationContext 容器会独立维护自己的单例 bean 实例,不同容器之间的 bean 是相互独立的

bean 的作用域 scope 定义为 prototype(原型),当每次调用 getBean() 时,都会创建一个新的实例
注解配置方式为:@Scope("prototype")
,XML 配置方式为:
xml
<bean id="userService" class="com.qcby.service.impl.UserServiceImpl" scope="prototype" init-method="init"/>

实例化 Bean 的三种方式
- 默认是无参数的构造方法
xml
<bean id="us" class="com.qcby.service.impl.UserServiceImpl"/>
在 XML 配置中,通过 factory-method 指定方法创建实例
- 静态工厂实例化方式
java
package com.qcby.factory;
import com.qcby.service.UserService;
import com.qcby.service.impl.UserServiceImpl;
public class StaticFactory {
// 静态工厂方式
public static UserService createUs(){
System.out.println("通过静态工厂的方式创建 UserServiceImpl 对象...");
return new UserServiceImpl();
}
}
xml
<!--静态工厂实例化-->
<bean id="us" class="com.qcby.factory.StaticFactory" factory-method="createUs" />
工厂类中的创建方法是静态方法,不需要创建工厂类的实例,Spring 容器会调用 UserFactory.createUser() 来生成 user 实例
- 动态工厂实例化方式
java
package com.qcby.factory;
import com.qcby.service.UserService;
import com.qcby.service.impl.UserServiceImpl;
public class DynamicFactoty {
public UserService createUs(){
System.out.println("动态工厂实例化方式...");
return new UserServiceImpl();
}
}
xml
<!--动态工厂实例化-->
<bean id="dynamicFactoty" class="com.qcby.factory.DynamicFactoty" />
<bean id="us1" factory-bean="dynamicFactoty" factory-method="createUs" />
工厂类中的创建方法是非静态方法,必须先实例化工厂类,再通过工厂实例调用方法
DI 依赖注入
DI(Dependency Injection,依赖注入)是实现 IOC(控制反转)思想的技术,在 Spring 框架负责创建 Bean 对象时,动态的将依赖对象 / 属性 注入到 Bean 组件中
- 属性的 set 方法注入值
编写属性提供该属性对应的 set 方法,编写配置文件完成属性值的注入
java
package com.qcby.dao.impl;
import com.qcby.dao.OrderDao;
public class OrderDaoImpl implements OrderDao {
public void saveOrder() {
System.out.println("持久层:保存订单...");
}
}
java
package com.qcby.service.impl;
import com.qcby.dao.OrderDao;
import com.qcby.service.OrderService;
public class OrderServiceImpl implements OrderService {
// 编写成员属性
private OrderDao orderDao;
// 一定需要提供该属性的 set 方法,IOC 容器底层就通过属性的 set 方法方式注入值
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
private String msg;
private int age;
public void setMsg(String msg) {
this.msg = msg;
}
public void setAge(int age) {
this.age = age;
}
public void saveOrder() {
System.out.println("业务层:保存订单..."+msg+" - "+age);
// 调用
orderDao.saveOrder();
}
}
xml
<!-- DI 依赖注入,通过属性的 set 方法注入值-->
<bean id="os" class="com.qcby.service.impl.OrderServiceImpl">
<property name="orderDao" ref="od" />
<property name="msg" value="你好" />
<property name="age" value="30" />
</bean>
<bean id="od" class="com.qcby.dao.impl.OrderDaoImpl"></bean>
- 属性构造方法方式注入值
对于类成员变量,有参构造函数注入
java
package com.qcby.model;
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
<!-- DI 依赖注入,通过有参构造器注入值-->
<bean id="car" class="com.qcby.model.Car">
<constructor-arg name="cname" value="奔驰" />
<constructor-arg name="money" value="400000" />
</bean>
数组,集合(List,Set,Map),Properties等的注入方式
java
package com.qcby.model;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class CollectionBean {
private String [] strs;
public void setStrs(String[] strs) {
this.strs = strs;
}
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
private Map<String,String> map;
public void setMap(Map<String, String> map) {
this.map = map;
}
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollectionBean{" +
"strs=" + Arrays.toString(strs) +
", list=" + list +
", map=" + map +
", properties=" + properties +
'}';
}
}
xml
<!--给集合属性注入值-->
<bean id="collectionBean"
class="com.qcby.model.CollectionBean">
<property name="strs">
<array>
<value>美美</value>
<value>小凤</value>
</array>
</property>
<property name="list">
<list>
<value>熊大</value>
<value>熊二</value>
</list>
</property>
<property name="map">
<map>
<entry key="aaa" value="老王"/>
<entry key="bbb" value="小王"/>
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
多配置文件方式
在 src 的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种
主配置文件中包含其他的配置文件
xml
<import resource="applicationContext2.xml"/>
工厂创建的时候直接加载多个配置文件
java
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");