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架构详解
  • 请求映射和参数绑定
  • 响应处理和异常处理
  • 数据校验和转换
相关推荐
一只叫煤球的猫1 小时前
【🤣离谱整活】我写了一篇程序员掉进 Java 异世界的短篇小说
java·后端·程序员
你的人类朋友2 小时前
🫏光速入门cURL
前端·后端·程序员
aramae4 小时前
C++ -- STL -- vector
开发语言·c++·笔记·后端·visual studio
lifallen4 小时前
Paimon 原子提交实现
java·大数据·数据结构·数据库·后端·算法
舒一笑5 小时前
PandaCoder重大产品更新-引入Jenkinsfile文件支持
后端·程序员·intellij idea
PetterHillWater5 小时前
AI编程之CodeBuddy的小试
后端·aigc
codervibe6 小时前
如何用 Spring Security 构建无状态权限控制系统(含角色菜单控制)
java·后端
codervibe6 小时前
项目中如何用策略模式实现多角色登录解耦?(附实战代码)
java·后端
expect7g6 小时前
Flink-Checkpoint-2.OperatorChain
后端·flink
大葱白菜6 小时前
🧱 Java 抽象类详解:从基础到实战,掌握面向对象设计的核心基石
后端·程序员