Spring框架核心(上)——IoC控制反转与DI依赖注入详解

前言

Spring框架自2003年兴起以来,已成为Java企业级开发的事实标准。它由Rod Johnson在其著作《Expert One-On-One J2EE Development and Design》中阐述的理念衍生而来,解决了企业应用开发的复杂性。本系列分为上下两篇,上篇聚焦于Spring最核心的控制反转(IoC)依赖注入(DI),涵盖XML配置、注解开发以及纯注解方式,并配有大量实战代码。


一、Spring框架概述

1.1 什么是Spring?

Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,将面向接口的编程思想贯穿整个系统。Spring是一个轻量级一站式(JavaSE/EE full-stack)的开源框架。

1.2 Spring的核心架构

Spring的核心是 IoC(控制反转)AOP(面向切面编程),构建了一个分层架构,允许开发者按需选择组件。

复制代码
┌─────────────────────────────────────────┐
│           表现层(Web层)                  │
├─────────────────────────────────────────┤
│           业务层(Service层)              │
├─────────────────────────────────────────┤
│           持久层(DAO层)                  │
├─────────────────────────────────────────┤
│         Spring核心容器(IoC/AOP)          │
└─────────────────────────────────────────┘

下图展示了Spring框架的经典分层架构,IoC和AOP作为底层基石,向上支撑着数据访问、Web层和业务逻辑层。

1.3 Spring的主要优点

  1. 解耦简化开发:Spring作为大工厂,管理对象创建和依赖关系。

  2. AOP编程支持:方便实现权限拦截、运行监控等。

  3. 声明式事务:通过配置管理事务,无需手动编码。

  4. 方便测试:与JUnit整合,轻松测试。

  5. 集成优秀框架:支持Struts2、Hibernate、MyBatis等。

  6. 降低API难度:对JDBC、JavaMail等提供封装。


二、IoC控制反转核心技术

2.1 什么是IoC?

IoC(Inversion of Control)即控制反转,将对象的创建权力反转给Spring框架。它是一种设计原则,用于降低代码之间的耦合度。

  • 传统方式UserService service = new UserServiceImpl();(主动创建)

  • IoC方式:由Spring工厂创建对象,我们被动获取。

复制代码

2.2 IoC快速入门

步骤1:创建Maven工程,导入依赖
XML 复制代码
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>
步骤2:编写接口与实现类
java 复制代码
java

// UserService.java
package com.example.service;
public interface UserService {
    void hello();
}

// UserServiceImpl.java
package com.example.service;
public class UserServiceImpl implements UserService {
    @Override
    public void hello() {
        System.out.println("Hello IOC!!");
    }
}
步骤3:编写Spring配置文件(applicationContext.xml)
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 id="userService" class="com.example.service.UserServiceImpl"/>
</beans>
步骤4:测试
java 复制代码
java

@Test
public void testIoC() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService service = (UserService) context.getBean("userService");
    service.hello();  // 输出 Hello IOC!!
}

IoC容器获取Bean的流程如下图所示:

2.3 ApplicationContext工厂接口

  • ClassPathXmlApplicationContext:加载类路径下的配置文件。

  • FileSystemXmlApplicationContext:加载磁盘路径下的配置文件。

2.4 Bean管理的XML配置

属性 说明
id Bean的唯一标识(命名规范)
class 类的全路径
scope 作用范围:singleton(默认单例)、prototype(多例)、request、session
init-method / destroy-method 生命周期回调方法

示例:

XML 复制代码
xml

<bean id="userService" class="com.example.service.UserServiceImpl" scope="singleton" init-method="init" destroy-method="destroy"/>

2.5 实例化Bean的三种方式

2.5.1 默认无参构造(最常用)
XML 复制代码
xml

<bean id="us" class="com.example.service.UserServiceImpl"/>
2.5.2 静态工厂方法
XML 复制代码
java

public class StaticFactory {
    public static UserService createUs() {
        return new UserServiceImpl();
    }
}
xml

<bean id="us" class="com.example.StaticFactory" factory-method="createUs"/>
2.5.3 实例工厂方法
XML 复制代码
java

public class DFactory {
    public UserService createUs() {
        return new UserServiceImpl();
    }
}
xml

<bean id="dfactory" class="com.example.DFactory"/>
<bean id="us" factory-bean="dfactory" factory-method="createUs"/>

三、DI依赖注入

3.1 什么是DI?

DI(Dependency Injection)即依赖注入 ,在Spring创建Bean时,动态地将依赖对象注入到Bean中。IoC是思想,DI是实现方式

3.2 Setter方法注入

XML 复制代码
java

public class OrderServiceImpl implements OrderService {
    private OrderDao orderDao;
    private String msg;
    private int age;
    // 必须提供setter方法
    public void setOrderDao(OrderDao orderDao) { this.orderDao = orderDao; }
    public void setMsg(String msg) { this.msg = msg; }
    public void setAge(int age) { this.age = age; }
    // 业务方法...
}
xml

<bean id="orderService" class="com.example.OrderServiceImpl">
    <property name="orderDao" ref="orderDao"/>
    <property name="msg" value="测试消息"/>
    <property name="age" value="18"/>
</bean>

3.3 构造方法注入

XML 复制代码
java

public class Car {
    private String cname;
    private Double money;
    public Car(String cname, Double money) {
        this.cname = cname;
        this.money = money;
    }
}
xml

<bean id="car" class="com.example.Car">
    <constructor-arg name="cname" value="奔驰"/>
    <constructor-arg name="money" value="400000"/>
</bean>

3.4 集合类型注入

支持数组、List、Set、Map、Properties等。

XML 复制代码
xml

<bean id="collectionBean" class="com.example.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="老王"/></map>
    </property>
    <property name="properties">
        <props><prop key="username">root</prop></props>
    </property>
</bean>

三种注入方式关系图


四、多配置文件加载

方式一:在主配置文件中导入

xml

复制代码
<import resource="applicationContext2.xml"/>

方式二:工厂同时加载多个

java

复制代码
ApplicationContext ac = new ClassPathXmlApplicationContext("app1.xml", "app2.xml");

五、Spring整合JDBC实战(IoC+DI综合案例)

5.1 数据库准备

sql 复制代码
sql

CREATE DATABASE spring_db;
USE spring_db;
CREATE TABLE account (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(40),
    money DOUBLE
);
INSERT INTO account VALUES (NULL,'aaa',1000),(NULL,'bbb',1000);

5.2 依赖(添加Druid和MySQL驱动)

XML 复制代码
xml

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
</dependency>

5.3 实体类、DAO、Service代码(省略getter/setter)

Account.java

java 复制代码
java

public class Account {
    private Integer id;
    private String name;
    private Double money;
    // 构造、getter、setter、toString
}

AccountDao接口与实现

java 复制代码
java

public interface AccountDao {
    List<Account> findAll();
}
public class AccountDaoImpl implements AccountDao {
    private DataSource dataSource;
    public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; }
    @Override
    public List<Account> findAll() {
        // 使用dataSource获取连接,执行查询,封装返回
        // 代码略(详见PDF)
    }
}

AccountService接口与实现

java 复制代码
java

public interface AccountService {
    List<Account> findAll();
}
public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; }
    @Override
    public List<Account> findAll() {
        return accountDao.findAll();
    }
}

5.4 配置文件(整合所有)

XML 复制代码
xml

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql:///spring_db"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>
<bean id="accountDao" class="com.example.dao.AccountDaoImpl">
    <property name="dataSource" ref="dataSource"/>
</bean>
<bean id="accountService" class="com.example.service.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
</bean>

5.5 测试

java 复制代码
java

@Test
public void testFindAll() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    AccountService service = ac.getBean(AccountService.class);
    List<Account> list = service.findAll();
    list.forEach(System.out::println);
}

六、IOC注解方式

6.1 快速入门

在类上添加@Component(或@Service@Repository@Controller),并在配置文件中开启注解扫描。

java 复制代码
java

@Component("us")
public class UserServiceImpl implements UserService {
    public void hello() { System.out.println("Hello IOC注解..."); }
}
xml

<context:component-scan base-package="com.example"/>

测试时直接通过id获取。

6.2 常用注解详解

注解 作用
@Component 普通类标记为Bean
@Controller 表现层
@Service 业务层
@Repository 持久层
@Value 注入基本类型值
@Autowired 按类型自动装配
@Qualifier 与@Autowired配合,按名称注入
@Resource JSR-250,按名称注入
@Scope 作用范围
@PostConstruct 初始化方法
@PreDestroy 销毁方法

示例:

java 复制代码
java

@Service
@Scope("singleton")
public class Car {
    @Value("大奔")
    private String cname;
    @Autowired
    private Person person;
    @PostConstruct
    public void init() { System.out.println("初始化"); }
}

6.3 纯注解方式(无XML)

配置类

java 复制代码
java

@Configuration
@ComponentScan("com.example")
@Import(OtherConfig.class)
public class SpringConfig {
    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql:///spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

测试

java 复制代码
java

ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
Order order = ac.getBean(Order.class);

七、Spring整合JUnit单元测试

7.1 配置文件方式

java 复制代码
java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestDemo {
    @Autowired
    private UserService userService;
    @Test
    public void test() { userService.hello(); }
}

7.2 纯注解方式

java 复制代码
java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class TestDemo {
    @Autowired
    private UserService userService;
    @Test
    public void test() { userService.hello(); }
}

总结

本篇详细介绍了Spring框架的IoC控制反转DI依赖注入 ,从XML配置到注解再到纯注解,并通过整合JDBC的实战案例加深理解。掌握了这些内容,您就打下了Spring的坚实基础。下篇我们将深入AOP面向切面编程事务管理JDBC模板等高级特性,敬请期待。

相关推荐
橙子家1 天前
使用方法 ToDictionary() 来优化查询时间复杂度:O(N*M) -> O(1*M)【C# 基础】
后端
matlabgoodboy1 天前
计算机毕设代做|Java Python Matlab APP 全套开发设计
java·python·课程设计
IT_陈寒1 天前
我又被JavaScript的隐式类型转换坑了
前端·人工智能·后端
用户8356290780511 天前
Python Word 转 PDF 和 PDF 转 Word 指南
后端·python
用户8356290780511 天前
如何使用 Python 加密和保护 Word 文档
后端·python
他们叫我秃子1 天前
前端开发转 Go 全栈(五):终于遇到熟人了,Go 的闭包和高阶函数原来这么像 JavaScript
前端·后端·go
SomeB1oody1 天前
【RustyML入门】2.6. 线性判别分析
开发语言·后端·机器学习·rust·教程
妙码生花1 天前
从 PHP 到 AI + Golang,程序员自救转型手记(五十七):AI时代对组件封装的新理解、agInput 统一入口,动态表单预备
前端·后端·go
Yao8061 天前
SpringAI + Ollama + DeepSeek + RAG 搭建 AI 航线规划系统
后端
大勇前进1 天前
SQL Server 分页查询多种写法对比:哪种性能最高?
后端