Java学习第8天 - Spring框架入门与依赖注入

学习时间: 4-5小时
学习目标: 初步了解Spring框架,掌握依赖注入(DI)和控制反转(IoC)核心概念


📋 详细学习清单

✅ 第一部分:Spring框架概念理解(90分钟)

1. Spring框架与前端框架对比

Vue.js (你熟悉的前端框架)

javascript 复制代码
// Vue.js 组件化开发
// main.js - 应用入口
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

const app = createApp(App)
app.use(store)  // 使用状态管理
app.use(router) // 使用路由
app.mount('#app')

// 组件依赖注入
// UserService.js
export class UserService {
    async getUsers() {
        return await fetch('/api/users').then(res => res.json())
    }
}

// UserComponent.vue
import { UserService } from '@/services/UserService'
export default {
    data() {
        return {
            users: [],
            userService: new UserService() // 手动创建依赖
        }
    },
    async mounted() {
        this.users = await this.userService.getUsers()
    }
}

Spring框架 (今天学习的后端框架)

java 复制代码
// Spring应用程序入口
// Application.java
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 服务层 - Spring自动管理
@Service  // 标记为Spring管理的组件
public class UserService {
    
    @Autowired  // 自动注入依赖
    private UserRepository userRepository;
    
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
}

// 控制器层 - Spring自动注入
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired  // Spring自动注入UserService
    private UserService userService;
    
    @GetMapping
    public List<User> getUsers() {
        return userService.getAllUsers();  // 不需要手动创建service实例
    }
    
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
}

2. 核心概念详解

IoC(控制反转)概念

java 复制代码
// 传统方式 - 手动控制依赖
public class UserController {
    private UserService userService;
    
    public UserController() {
        // 自己创建依赖 - 紧耦合
        this.userService = new UserService();
    }
}

// Spring IoC方式 - 框架控制依赖
@RestController
public class UserController {
    
    @Autowired  // 交给Spring容器管理
    private UserService userService;
    
    // Spring会自动注入userService实例
    // 我们不需要知道如何创建,只需要使用
}

DI(依赖注入)三种方式

java 复制代码
// 1. 构造函数注入(推荐)
@RestController
public class UserController {
    private final UserService userService;
    
    // 构造函数注入 - 保证依赖不为null
    public UserController(UserService userService) {
        this.userService = userService;
    }
}

// 2. Setter方法注入
@RestController
public class UserController {
    private UserService userService;
    
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

// 3. 字段注入(简单但不推荐)
@RestController
public class UserController {
    @Autowired
    private UserService userService;
}

✅ 第二部分:Spring Bean管理(80分钟)

1. Bean的概念和生命周期

什么是Bean?

java 复制代码
// Bean就是由Spring容器管理的对象
// 类似于Vue中由Vue实例管理的组件

// 1. 使用注解标记Bean
@Component  // 通用组件
public class EmailService {
    public void sendEmail(String to, String message) {
        System.out.println("发送邮件给: " + to);
    }
}

@Service    // 业务逻辑层
public class UserService {
    // ...
}

@Repository // 数据访问层
public class UserRepository {
    // ...
}

@Controller // 控制器层
public class UserController {
    // ...
}

// 2. 使用@Configuration和@Bean
@Configuration
public class AppConfig {
    
    @Bean
    public EmailService emailService() {
        return new EmailService();
    }
    
    @Bean
    public UserService userService() {
        return new UserService();
    }
}

2. Bean的作用域

java 复制代码
// 单例模式(默认)- 类似于Vue的全局状态
@Service
@Scope("singleton")  // 整个应用只有一个实例
public class UserService {
    private int counter = 0;
    
    public void incrementCounter() {
        counter++;
        System.out.println("计数器: " + counter);
    }
}

// 原型模式 - 每次注入都创建新实例
@Service
@Scope("prototype")  // 每次请求都创建新实例
public class TaskService {
    private String taskId = UUID.randomUUID().toString();
    
    public String getTaskId() {
        return taskId;
    }
}

// Web相关作用域
@Service
@Scope("request")    // 每个HTTP请求一个实例
public class RequestService {
    // ...
}

@Service
@Scope("session")    // 每个用户会话一个实例
public class SessionService {
    // ...
}

✅ 第三部分:Spring配置方式(70分钟)

1. 基于注解的配置(推荐)

java 复制代码
// 1. 应用程序主配置
@SpringBootApplication  // 包含@Configuration + @EnableAutoConfiguration + @ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 2. 组件扫描
@ComponentScan(basePackages = {"com.example.service", "com.example.controller"})
@Configuration
public class AppConfig {
    // Spring会自动扫描指定包下的@Component, @Service, @Repository, @Controller
}

// 3. 条件化配置
@Configuration
public class DatabaseConfig {
    
    @Bean
    @ConditionalOnProperty(name = "database.type", havingValue = "mysql")
    public DataSource mysqlDataSource() {
        return new MysqlDataSource();
    }
    
    @Bean
    @ConditionalOnProperty(name = "database.type", havingValue = "postgresql")
    public DataSource postgresqlDataSource() {
        return new PostgresqlDataSource();
    }
}

2. 配置文件管理

application.properties

properties 复制代码
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# 应用配置
app.name=MyApplication
app.version=1.0.0
app.email.enabled=true
app.email.host=smtp.gmail.com

application.yml (推荐)

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

app:
  name: MyApplication
  version: 1.0.0
  email:
    enabled: true
    host: smtp.gmail.com

使用配置属性

java 复制代码
// 1. 单个属性注入
@Service
public class EmailService {
    
    @Value("${app.email.host}")
    private String emailHost;
    
    @Value("${app.email.enabled:false}")  // 默认值
    private boolean emailEnabled;
    
    public void sendEmail(String message) {
        if (emailEnabled) {
            System.out.println("通过 " + emailHost + " 发送邮件: " + message);
        }
    }
}

// 2. 配置类绑定
@ConfigurationProperties(prefix = "app")
@Component
public class AppProperties {
    private String name;
    private String version;
    private Email email;
    
    // getter和setter方法
    public static class Email {
        private boolean enabled;
        private String host;
        // getter和setter
    }
}

// 使用配置类
@Service
public class ApplicationService {
    
    @Autowired
    private AppProperties appProperties;
    
    public void printAppInfo() {
        System.out.println("应用名称: " + appProperties.getName());
        System.out.println("版本: " + appProperties.getVersion());
        System.out.println("邮件启用: " + appProperties.getEmail().isEnabled());
    }
}

✅ 第四部分:实战练习 - 简单的用户管理系统(90分钟)

1. 项目结构

bash 复制代码
src/main/java/com/example/usermgmt/
├── Application.java                 # 应用入口
├── controller/
│   └── UserController.java         # 控制器层
├── service/
│   ├── UserService.java           # 业务逻辑层接口
│   └── UserServiceImpl.java       # 业务逻辑实现
├── repository/
│   └── UserRepository.java        # 数据访问层
├── model/
│   └── User.java                   # 用户实体
└── config/
    └── AppConfig.java              # 应用配置

2. 完整代码实现

用户实体

java 复制代码
// User.java
public class User {
    private Long id;
    private String username;
    private String email;
    private int age;
    
    // 构造函数
    public User() {}
    
    public User(String username, String email, int age) {
        this.username = username;
        this.email = email;
        this.age = age;
    }
    
    // getter和setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    
    @Override
    public String toString() {
        return "User{id=" + id + ", username='" + username + 
               "', email='" + email + "', age=" + age + "}";
    }
}

数据访问层

java 复制代码
// UserRepository.java
@Repository
public class UserRepository {
    
    // 模拟数据库存储
    private Map<Long, User> users = new ConcurrentHashMap<>();
    private AtomicLong idGenerator = new AtomicLong(1);
    
    public List<User> findAll() {
        return new ArrayList<>(users.values());
    }
    
    public User findById(Long id) {
        return users.get(id);
    }
    
    public User save(User user) {
        if (user.getId() == null) {
            user.setId(idGenerator.getAndIncrement());
        }
        users.put(user.getId(), user);
        return user;
    }
    
    public void deleteById(Long id) {
        users.remove(id);
    }
    
    public User findByUsername(String username) {
        return users.values().stream()
                .filter(user -> user.getUsername().equals(username))
                .findFirst()
                .orElse(null);
    }
}

业务逻辑层

java 复制代码
// UserService.java (接口)
public interface UserService {
    List<User> getAllUsers();
    User getUserById(Long id);
    User createUser(User user);
    User updateUser(Long id, User user);
    void deleteUser(Long id);
    User getUserByUsername(String username);
}

// UserServiceImpl.java (实现)
@Service
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    
    // 构造函数注入(推荐方式)
    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Override
    public List<User> getAllUsers() {
        List<User> users = userRepository.findAll();
        System.out.println("获取所有用户,总数: " + users.size());
        return users;
    }
    
    @Override
    public User getUserById(Long id) {
        User user = userRepository.findById(id);
        if (user == null) {
            throw new RuntimeException("用户不存在: " + id);
        }
        return user;
    }
    
    @Override
    public User createUser(User user) {
        // 业务验证
        if (user.getUsername() == null || user.getUsername().trim().isEmpty()) {
            throw new RuntimeException("用户名不能为空");
        }
        
        // 检查用户名是否已存在
        if (userRepository.findByUsername(user.getUsername()) != null) {
            throw new RuntimeException("用户名已存在: " + user.getUsername());
        }
        
        User savedUser = userRepository.save(user);
        System.out.println("创建用户成功: " + savedUser);
        return savedUser;
    }
    
    @Override
    public User updateUser(Long id, User user) {
        User existingUser = getUserById(id);
        
        existingUser.setUsername(user.getUsername());
        existingUser.setEmail(user.getEmail());
        existingUser.setAge(user.getAge());
        
        User updatedUser = userRepository.save(existingUser);
        System.out.println("更新用户成功: " + updatedUser);
        return updatedUser;
    }
    
    @Override
    public void deleteUser(Long id) {
        User user = getUserById(id);
        userRepository.deleteById(id);
        System.out.println("删除用户成功: " + user);
    }
    
    @Override
    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }
}

控制器层

java 复制代码
// UserController.java
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    private final UserService userService;
    
    // 构造函数注入
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
    
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
    
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }
    
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
    
    @GetMapping("/search")
    public User getUserByUsername(@RequestParam String username) {
        return userService.getUserByUsername(username);
    }
}

应用入口

java 复制代码
// Application.java
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    // 可选:添加一些初始数据
    @Bean
    public CommandLineRunner initData(UserService userService) {
        return args -> {
            userService.createUser(new User("张三", "zhangsan@example.com", 25));
            userService.createUser(new User("李四", "lisi@example.com", 30));
            userService.createUser(new User("王五", "wangwu@example.com", 28));
            
            System.out.println("初始化数据完成!");
        };
    }
}

✅ 第五部分:测试和验证(30分钟)

1. 创建测试类

java 复制代码
// UserServiceTest.java
@SpringBootTest
public class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void testCreateUser() {
        User user = new User("测试用户", "test@example.com", 22);
        User savedUser = userService.createUser(user);
        
        assertNotNull(savedUser.getId());
        assertEquals("测试用户", savedUser.getUsername());
        assertEquals("test@example.com", savedUser.getEmail());
        assertEquals(22, savedUser.getAge());
    }
    
    @Test
    public void testGetAllUsers() {
        List<User> users = userService.getAllUsers();
        assertTrue(users.size() >= 3); // 至少有初始化的3个用户
    }
    
    @Test
    public void testUpdateUser() {
        // 先创建用户
        User user = new User("原始用户", "original@example.com", 20);
        User savedUser = userService.createUser(user);
        
        // 更新用户
        User updateData = new User("更新用户", "updated@example.com", 25);
        User updatedUser = userService.updateUser(savedUser.getId(), updateData);
        
        assertEquals("更新用户", updatedUser.getUsername());
        assertEquals("updated@example.com", updatedUser.getEmail());
        assertEquals(25, updatedUser.getAge());
    }
}

2. 使用Postman或curl测试API

bash 复制代码
# 1. 获取所有用户
curl -X GET http://localhost:8080/api/users

# 2. 创建新用户
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{"username":"新用户","email":"newuser@example.com","age":26}'

# 3. 获取特定用户
curl -X GET http://localhost:8080/api/users/1

# 4. 更新用户
curl -X PUT http://localhost:8080/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"username":"更新的用户","email":"updated@example.com","age":27}'

# 5. 删除用户
curl -X DELETE http://localhost:8080/api/users/1

# 6. 按用户名搜索
curl -X GET "http://localhost:8080/api/users/search?username=张三"

📝 今日学习总结

✅ 学习成果检查清单

  • 理解Spring框架的核心概念(IoC、DI)
  • 掌握三种依赖注入方式
  • 了解Bean的生命周期和作用域
  • 熟悉基于注解的配置方式
  • 能够使用配置文件管理应用属性
  • 完成用户管理系统实战项目
  • 编写单元测试验证功能

🎯 重点掌握概念

  1. IoC容器:Spring管理所有Bean的生命周期
  2. 依赖注入:通过构造函数、setter或字段注入依赖
  3. 注解驱动:使用@Service、@Repository、@Controller等注解
  4. 配置外部化:使用application.yml管理配置
  5. 分层架构:Controller → Service → Repository的清晰分层

🚀 明天预告

第9天学习内容:Spring Boot Web开发

  • RESTful API设计原则
  • Spring MVC架构详解
  • 请求映射和参数绑定
  • 响应处理和异常处理
  • 数据校验和转换
相关推荐
做运维的阿瑞11 分钟前
Python零基础入门:30分钟掌握核心语法与实战应用
开发语言·后端·python·算法·系统架构
猿究院-陆昱泽1 小时前
Redis 五大核心数据结构知识点梳理
redis·后端·中间件
yuriy.wang2 小时前
Spring IOC源码篇五 核心方法obtainFreshBeanFactory.doLoadBeanDefinitions
java·后端·spring
咖啡教室4 小时前
程序员应该掌握的网络命令telnet、ping和curl
运维·后端
你的人类朋友4 小时前
Let‘s Encrypt 免费获取 SSL、TLS 证书的原理
后端
老葱头蒸鸡4 小时前
(14)ASP.NET Core2.2 中的日志记录
后端·asp.net
李昊哲小课5 小时前
Spring Boot 基础教程
java·大数据·spring boot·后端
码事漫谈5 小时前
C++内存越界的幽灵:为什么代码运行正常,free时却崩溃了?
后端
Swift社区5 小时前
Spring Boot 3.x + Security + OpenFeign:如何避免内部服务调用被重复拦截?
java·spring boot·后端
90后的晨仔5 小时前
Mac 上配置多个 Gitee 账号的完整教程
前端·后端