引言:为什么选择Spring框架?
Spring框架是Java企业级应用开发的事实标准,它解决了企业级开发中的诸多难题。作为一款轻量级的开源框架,Spring的核心优势在于其控制反转(IoC)和面向切面编程(AOP)的设计理念。这些设计不仅降低了代码的耦合度,还提高了代码的可测试性和可维护性。在现代企业级开发中,Spring不仅仅是一个框架,更是一套完整的生态体系,涵盖了数据访问、Web开发、安全控制、微服务架构等多个领域。对于Java开发者而言,掌握Spring意味着掌握了构建现代化、高性能、可扩展企业级应用的关键技术。
第一部分:Spring框架基础入门
1.1 Spring框架概述
Spring框架是一个分层架构,它允许开发者选择性地使用其各个模块。核心模块是整个框架的基础,提供了IoC容器和依赖注入功能。除此之外,Spring还提供了Spring MVC用于Web开发,Spring Data用于数据访问,Spring Security用于安全控制等。Spring框架的设计哲学是“非侵入式”,这意味着开发者可以在不修改现有代码的情况下引入Spring功能。
1.2 环境搭建与第一个Spring应用
在开始Spring开发之前,我们需要配置开发环境。推荐使用IntelliJ IDEA作为开发工具,Maven或Gradle作为构建工具。以下是使用Maven创建Spring项目的步骤:
- 在pom.xml中添加Spring核心依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
</dependencies>
- 创建一个简单的Java类:
public class HelloWorld {
private String message;
public void setMessage(String message) {
this.message = message;
}
public void getMessage() {
System.out.println("Message: " + message);
}
}
- 创建Spring配置文件(beans.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="helloWorld" class="com.example.HelloWorld">
<property name="message" value="Hello Spring!" />
</bean>
</beans>
- 编写主程序测试:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
helloWorld.getMessage();
}
}
1.3 依赖注入(DI)详解
依赖注入是Spring框架的核心功能之一,它实现了对象之间的解耦。Spring提供了两种主要的依赖注入方式:构造器注入和Setter方法注入。
构造器注入示例:
public class OrderService {
private final UserService userService;
// 构造器注入
public OrderService(UserService userService) {
this.userService = userService;
}
}
Setter方法注入示例:
public class OrderService {
private UserService userService;
// Setter方法注入
public void setUserService(UserService userService) {
this.userService = userService;
}
}
在XML配置中,我们可以这样定义:
<!-- 构造器注入 -->
<bean id="orderService" class="com.example.OrderService">
<constructor-arg ref="userService" />
</bean>
<!-- Setter方法注入 -->
<bean id="orderService" class="com.example.OrderService">
<property name="userService" ref="userService" />
</bean>
1.4 Spring IoC容器详解
Spring IoC容器是Spring框架的核心,它负责创建、配置和管理Bean的生命周期。Spring提供了两种主要的IoC容器:BeanFactory和ApplicationContext。ApplicationContext是BeanFactory的子接口,提供了更多企业级功能,如事件发布、国际化支持等。
BeanFactory示例:
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
HelloWorld hello = (HelloWorld) factory.getBean("helloWorld");
ApplicationContext示例:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
HelloWorld hello = context.getBean(HelloWorld.class);
第二部分:Spring核心原理深入解析
2.1 面向切面编程(AOP)原理与应用
AOP是Spring框架的另一个核心特性,它允许开发者在不修改源代码的情况下为程序添加额外功能。Spring AOP基于代理模式实现,主要概念包括切面(Aspect)、连接点(Join Point)、通知(Advice)和切入点(Pointcut)。
AOP术语解释:
- 切面(Aspect):横切关注点的模块化,如日志、事务管理等
- 连接点(Join Point):程序执行过程中的某个特定点,如方法调用
- 通知(Advice):切面在连接点执行的具体操作
- 切入点(Pointcut):匹配连接点的规则
使用注解方式实现AOP:
- 添加AOP依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
- 定义切面类:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
@Component
public class LoggingAspect {
// 前置通知:在目标方法执行前执行
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("方法执行前:记录日志");
}
// 后置通知:在目标方法执行后执行
@After("execution(* com.example.service.*.*(..))")
public void logAfter() {
System.out.println("方法执行后:记录日志");
}
// 环绕通知:包围目标方法
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知:方法执行前");
Object result = joinPoint.proceed(); // 执行目标方法
System.out.println("环绕通知:方法执行后");
return result;
}
}
- 启用AOP注解支持:
@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
2.2 Bean的生命周期管理
Spring管理的Bean具有完整的生命周期,从实例化、初始化到销毁。理解Bean的生命周期对于开发复杂应用至关重要。
Bean生命周期的完整流程:
- 实例化Bean对象
- 设置Bean属性
- 调用BeanNameAware.setBeanName()
- 调用BeanFactoryAware.setBeanFactory()
- 调用ApplicationContextAware.setApplicationContext()
- 调用BeanPostProcessor.postProcessBeforeInitialization()
- 调用InitializingBean.afterPropertiesSet()
- 调用自定义的init方法
- 调用BeanPostProcessor.postProcessAfterInitialization()
- Bean就绪,可以使用
- 调用DisposableBean.destroy()
- 调用自定义的destroy方法
实现Bean生命周期管理的示例:
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class LifeCycleBean implements BeanNameAware, InitializingBean, DisposableBean, ApplicationContextAware {
private String name;
private ApplicationContext context;
public LifeCycleBean() {
System.out.println("1. 构造函数被调用");
}
@Override
public void setBeanName(String name) {
this.name = name;
System.out.println("2. setBeanName被调用,Bean名称:" + name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.context = applicationContext;
System.out.println("3. setApplicationContext被调用");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5. afterPropertiesSet被调用");
}
public void customInit() {
System.out.println("6. 自定义init方法被调用");
}
@Override
public void destroy() throws Exception {
System.out.println("7. destroy被调用");
}
public void customDestroy() {
System.out.println("8. 自定义destroy方法被调用");
}
}
XML配置:
<bean id="lifeCycleBean" class="com.example.LifeCycleBean"
init-method="customInit" destroy-method="customDestroy" />
2.3 Spring事件驱动模型
Spring提供了强大的事件驱动模型,允许组件之间通过事件进行通信。Spring事件基于观察者模式实现。
自定义事件类:
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
事件监听器:
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("收到事件:" + event.getMessage());
}
}
事件发布者:
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class CustomEventPublisher {
private final ApplicationEventPublisher publisher;
public CustomEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void publishEvent(String message) {
publisher.publishEvent(new CustomEvent(this, message));
}
}
第三部分:Spring Data访问技术
3.1 Spring JDBC模板
Spring JDBC抽象层消除了传统JDBC编程的样板代码,提供了更简洁的数据库访问方式。
配置数据源:
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
使用JdbcTemplate进行CRUD操作:
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@Component
public class UserRepository {
private final JdbcTemplate jdbcTemplate;
public UserRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// 查询单个对象
public User findById(Long id) {
String sql = "SELECT * FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);
}
// 查询列表
public List<User> findAll() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql, new UserRowMapper());
}
// 插入数据
public void insert(User user) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
jdbcTemplate.update(sql, user.getName(), user.getEmail());
}
// 更新数据
public void update(User user) {
String sql = "UPDATE users SET name = ?, email = ? WHERE id = ?";
jdbcTemplate.update(sql, user.getName(), user.getEmail(), user.getId());
}
// 删除数据
public void delete(Long id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
// RowMapper用于映射结果集到对象
private static class UserRowMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
user.setEmail(rs.getString("email"));
return user;
}
}
}
3.2 Spring Data JPA
Spring Data JPA是Spring Data项目的一部分,它基于JPA规范,进一步简化了数据访问层的开发。
配置Spring Data JPA:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class JpaConfig {
@Bean
public DataSource dataSource() {
// 数据源配置...
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.example.entity");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
定义实体类:
import javax.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String name;
@Column(nullable = false, unique = true, length = 150)
private String email;
// 构造函数、getter和setter...
}
定义Repository接口:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名查询:自动实现
List<User> findByName(String name);
// 使用JPQL查询
@Query("SELECT u FROM User u WHERE u.email = :email")
User findByEmail(@Param("email") String email);
// 复杂查询
@Query("SELECT u FROM User u WHERE u.name LIKE %:keyword% OR u.email LIKE %:keyword%")
List<User> searchUsers(@Param("keyword") String keyword);
}
使用Repository:
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(User user) {
return userRepository.save(user);
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public Optional<User> getUserById(Long id) {
return userRepository.findById(id);
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
3.3 声明式事务管理
Spring提供了声明式事务管理,通过AOP实现,无需在代码中手动管理事务。
使用@Transactional注解:
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
@Service
public class BankService {
private final AccountRepository accountRepository;
public BankService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
@Transactional
public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) {
Account fromAccount = accountRepository.findById(fromAccountId)
.orElseThrow(() -> new RuntimeException("账户不存在"));
Account toAccount = accountRepository.findById(toAccountId)
.orElseThrow(() -> new RuntimeException("账户不存在"));
if (fromAccount.getBalance().compareTo(amount) < 0) {
throw new RuntimeException("余额不足");
}
fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
toAccount.setBalance(toAccount.getBalance().add(amount));
accountRepository.save(fromAccount);
accountRepository.save(toAccount);
}
}
配置事务管理器:
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
第四部分:Spring Web开发
4.1 Spring MVC框架
Spring MVC是Spring框架的Web模块,遵循MVC设计模式,提供了灵活的Web开发能力。
配置DispatcherServlet:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Web配置类:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class WebConfig implements WebMvcConfigurer {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
}
控制器示例:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.ui.Model;
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping
public String listUsers(Model model) {
// 获取用户列表并添加到model
model.addAttribute("users", userService.getAllUsers());
return "users/list"; // 返回视图名称
}
@GetMapping("/{id}")
public String getUser(@PathVariable Long id, Model model) {
User user = userService.getUserById(id);
model.addAttribute("user", user);
return "users/detail";
}
@PostMapping
public String createUser(@ModelAttribute User user) {
userService.createUser(user);
return "redirect:/users";
}
@PutMapping("/{id}")
public String updateUser(@PathVariable Long id, @ModelAttribute User user) {
user.setId(id);
userService.updateUser(user);
return "redirect:/users";
}
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return "redirect:/users";
}
}
RESTful API控制器:
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
@RestController
@RequestMapping("/api/users")
public class UserApiController {
private final UserService userService;
public UserApiController(UserService userService) {
this.userService = userService;
}
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return userService.getUserById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
try {
user.setId(id);
User updatedUser = userService.updateUser(user);
return ResponseEntity.ok(updatedUser);
} catch (Exception e) {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
Spring Boot是Spring框架的扩展,它简化了Spring应用的配置和部署。Spring Boot遵循“约定优于配置”的原则,提供了自动配置功能,大大减少了开发者的配置工作量。
### 5.1 Spring Boot快速入门
**创建Spring Boot项目:**
可以使用Spring Initializr(https://start.spring.io)快速生成项目,或者使用Spring Boot CLI。
**使用Spring Initializr创建项目:**
1. 访问https://start.spring.io
2. 选择项目配置:
- Project: Maven Project
- Language: Java
- Spring Boot: 2.7.x
- Group: com.example
- Artifact: demo
- Dependencies: Spring Web, Spring Data JPA, H2 Database
3. 点击Generate下载项目
**Spring Boot主类:**
```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
5.2 Spring Boot自动配置原理
Spring Boot的自动配置基于条件化配置,通过@Conditional注解实现。
自动配置示例:
@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
自定义自动配置:
@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(name = "myapp.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyAppProperties.class)
public class MyAppAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyAppProperties properties) {
return new MyService(properties.getMessage());
}
}
5.3 Spring Boot配置文件
application.properties示例:
# 服务器配置
server.port=8080
server.servlet.context-path=/api
# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
# 日志配置
logging.level.com.example=DEBUG
logging.level.org.springframework.web=INFO
application.yml示例:
server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
logging:
level:
com.example: DEBUG
org.springframework.web: INFO
多环境配置:
# application-dev.yml
spring:
profiles: dev
datasource:
url: jdbc:mysql://localhost:3306/test_dev
# application-prod.yml
spring:
profiles: prod
datasource:
url: jdbc:mysql://prod-server:3306/test_prod
5.4 Spring Boot Starter原理
Spring Boot Starter是一组依赖描述符的集合,它简化了依赖管理。
自定义Starter步骤:
- 创建自动配置类:
@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(name = "myapp.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyAppProperties.class)
public class MyAppAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyAppProperties properties) {
return new MyService(properties.getMessage());
}
}
- 创建属性类:
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private boolean enabled = true;
private String message = "Hello Starter";
// getter和setter...
}
- 创建spring.factories文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAppAutoConfiguration
- 打包为jar并发布
第六部分:Spring Security安全框架
6.1 Spring Security基础
Spring Security是Spring生态中的安全框架,提供了认证和授权功能。
基本配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("{noop}password")
.roles("USER")
.and()
.withUser("admin")
.password("{noop}admin")
.roles("USER", "ADMIN");
}
}
6.2 自定义用户认证
基于数据库的认证:
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRoles().toArray(new String[0]))
.build();
}
}
配置自定义UserDetailsService:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomUserDetailsService userDetailsService;
public SecurityConfig(CustomUserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
6.3 JWT认证
JWT工具类:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class JwtTokenUtil {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION_TIME = 86400000; // 24小时
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
}
JWT认证过滤器:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JwtRequestFilter extends OncePerRequestFilter {
private final UserDetailsService userDetailsService;
private final JwtTokenUtil jwtTokenUtil;
public JwtRequestFilter(UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil) {
this.userDetailsService = userDetailsService;
this.jwtTokenUtil = jwtTokenUtil;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtTokenUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
chain.doFilter(request, response);
}
}
配置JWT安全:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomUserDetailsService userDetailsService;
private final JwtTokenUtil jwtTokenUtil;
public SecurityConfig(CustomUserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil) {
this.userDetailsService = userDetailsService;
this.jwtTokenUtil = jwtTokenUtil;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public JwtRequestFilter jwtRequestFilter() {
return new JwtRequestFilter(userDetailsService, jwtTokenUtil);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
第七部分:Spring微服务架构
7.1 Spring Cloud基础
Spring Cloud是基于Spring Boot的微服务框架,提供了分布式系统开发的常见模式。
服务注册与发现(Eureka):
- Eureka Server:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Eureka Server配置:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka/
- Eureka Client:
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
Eureka Client配置:
server:
port: 8081
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
7.2 服务调用(Feign)
Feign客户端:
@FeignClient(name = "user-service")
public interface UserServiceClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
@PostMapping("/users")
User createUser(@RequestBody User user);
}
启用Feign:
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
7.3 熔断器(Hystrix)
Feign集成Hystrix:
@FeignClient(name = "user-service", fallback = UserServiceFallback.class)
public interface UserServiceClient {
// ...
}
@Component
public class UserServiceFallback implements UserServiceClient {
@Override
public User getUserById(Long id) {
// 返回降级数据
User fallbackUser = new User();
fallbackUser.setId(id);
fallbackUser.setName("默认用户");
return fallbackUser;
}
@Override
public User createUser(User user) {
return null;
}
}
配置Hystrix:
feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
7.4 配置中心(Config)
Config Server:
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
Config Server配置:
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-repo/config-repo
search-paths: config
username: your-username
password: your-password
Config Client配置:
spring:
application:
name: user-service
cloud:
config:
uri: http://localhost:8888
profile: dev
第八部分:Spring高级特性与最佳实践
8.1 Spring测试框架
单元测试示例:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
public void testCreateUser() {
User user = new User();
user.setName("John");
user.setEmail("john@example.com");
when(userRepository.save(any(User.class))).thenReturn(user);
User savedUser = userService.createUser(user);
assertNotNull(savedUser);
assertEquals("John", savedUser.getName());
verify(userRepository, times(1)).save(user);
}
}
集成测试示例:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testGetUser() {
String url = "http://localhost:" + port + "/api/users/1";
ResponseEntity<User> response = restTemplate.getForEntity(url, User.class);
assertEquals(200, response.getStatusCodeValue());
assertNotNull(response.getBody());
}
}
8.2 Spring AOP高级应用
自定义注解实现日志:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
}
切面实现:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Around("@annotation(logExecution)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecution logExecution) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return result;
}
}
使用自定义注解:
@Service
public class SomeService {
@LogExecution
public void someMethod() {
// 业务逻辑
}
}
8.3 Spring性能优化
连接池优化(HikariCP):
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
leak-detection-threshold: 60000
缓存配置:
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
RedisCacheManager cacheManager = RedisCacheManager.create(redisConnectionFactory());
return cacheManager;
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new JedisConnectionFactory();
}
}
使用缓存:
@Service
public class UserService {
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
// 数据库查询
return userRepository.findById(id).orElse(null);
}
@CacheEvict(value = "users", key = "#user.id")
public void updateUser(User user) {
userRepository.save(user);
}
}
8.4 Spring最佳实践
1. 分层架构设计:
controller → service → repository → database
2. 异常处理:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "系统内部错误");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
3. DTO模式:
// DTO类
public class UserDTO {
private String name;
private String email;
// getter和setter...
}
// 转换器
public class UserConverter {
public static UserDTO toDTO(User user) {
UserDTO dto = new UserDTO();
dto.setName(user.getName());
dto.setEmail(user.getEmail());
return dto;
}
public static User toEntity(UserDTO dto) {
User user = new User();
user.setName(dto.getName());
user.setEmail(dto.getEmail());
return user;
}
}
4. 配置管理:
- 使用环境变量管理敏感信息
- 使用Spring Cloud Config集中管理配置
- 使用Profile区分不同环境配置
5. 日志规范:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
public void processOrder(Order order) {
logger.info("开始处理订单: {}", order.getId());
try {
// 业务逻辑
logger.debug("订单详情: {}", order);
} catch (Exception e) {
logger.error("处理订单失败: {}", order.getId(), e);
throw new OrderProcessingException("订单处理失败", e);
}
}
}
第九部分:Spring生态与未来趋势
9.1 Spring Boot Actuator
启用Actuator:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置Actuator端点:
management:
endpoints:
web:
exposure:
include: health,info,metrics,env
endpoint:
health:
show-details: always
自定义健康检查:
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// 检查数据库连接
boolean isConnected = checkDatabaseConnection();
if (isConnected) {
return Health.up()
.withDetail("database", "MySQL")
.withDetail("status", "connected")
.build();
} else {
return Health.down()
.withDetail("database", "MySQL")
.withDetail("status", "disconnected")
.build();
}
}
private boolean checkDatabaseConnection() {
// 实际的数据库连接检查逻辑
return true;
}
}
9.2 Spring WebFlux响应式编程
WebFlux控制器:
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/reactive")
public class ReactiveUserController {
private final ReactiveUserRepository userRepository;
public ReactiveUserController(ReactiveUserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/users")
public Flux<User> getAllUsers() {
return userRepository.findAll();
}
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable Long id) {
return userRepository.findById(id)
.switchIfEmpty(Mono.error(new UserNotFoundException(id)));
}
@PostMapping("/users")
public Mono<User> createUser(@RequestBody User user) {
return userRepository.save(user);
}
}
WebFlux配置:
@Configuration
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer {
@Bean
public RouterFunction<ServerResponse> routerFunction() {
return RouterFunctions.route()
.GET("/api/reactive/users", request ->
ServerResponse.ok().body(userRepository.findAll(), User.class))
.build();
}
}
9.3 Spring Native与GraalVM
Spring Native简介: Spring Native是Spring Boot的实验性特性,可以将Spring应用编译为原生镜像,显著提升启动速度和内存使用效率。
使用Spring Native:
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.11.4</version>
</dependency>
构建原生镜像:
# 使用Pack构建
pack build myapp --builder paketobuildpacks/builder:base --env BP_NATIVE_IMAGE=true
# 使用GraalVM native-image
native-image -H:+ReportExceptionStackTraces -H:+StaticExecutableWithDynamicLibC \
-H:Name=myapp -H:Class=com.example.MyApplication
9.4 Spring与云原生
Spring Cloud Kubernetes:
@SpringBootApplication
@EnableDiscoveryClient
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Kubernetes配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:1.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: SPRING_CLOUD_KUBERNETES_CONFIG_ENABLED
value: "true"
第十部分:企业级Spring应用实战案例
10.1 电商系统架构设计
整体架构:
API Gateway → Service Registry → Microservices
↓
Config Center → 各个微服务
↓
Monitoring → 各个微服务
用户服务实现:
// 实体类
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
private String password;
private String email;
private String phone;
@Enumerated(EnumType.STRING)
private UserRole role;
// 构造函数、getter和setter...
}
// Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}
// Service
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final JwtTokenUtil jwtTokenUtil;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, JwtTokenUtil jwtTokenUtil) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.jwtTokenUtil = jwtTokenUtil;
}
public String register(UserRegistrationDTO dto) {
if (userRepository.findByUsername(dto.getUsername()).isPresent()) {
throw new RuntimeException("用户名已存在");
}
User user = new User();
user.setUsername(dto.getUsername());
user.setPassword(passwordEncoder.encode(dto.getPassword()));
user.setEmail(dto.getEmail());
user.setPhone(dto.getPhone());
user.setRole(UserRole.CUSTOMER);
userRepository.save(user);
return "注册成功";
}
public String login(UserLoginDTO dto) {
User user = userRepository.findByUsername(dto.getUsername())
.orElseThrow(() -> new RuntimeException("用户不存在"));
if (!passwordEncoder.matches(dto.getPassword(), user.getPassword())) {
throw new RuntimeException("密码错误");
}
return jwtTokenUtil.generateToken(
org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRole().name())
.build()
);
}
}
// Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("/register")
public ResponseEntity<String> register(@RequestBody UserRegistrationDTO dto) {
return ResponseEntity.ok(userService.register(dto));
}
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody UserLoginDTO dto) {
return ResponseEntity.ok(userService.login(dto));
}
}
商品服务实现:
// 实体类
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
private BigDecimal price;
private Integer stock;
@Enumerated(EnumType.STRING)
private ProductStatus status;
// 构造函数、getter和setter...
}
// Service
@Service
public class ProductService {
private final ProductRepository productRepository;
private final RedisTemplate<String, Object> redisTemplate;
public ProductService(ProductRepository productRepository, RedisTemplate<String, Object> redisTemplate) {
this.productRepository = productRepository;
this.redisTemplate = redisTemplate;
}
@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
return productRepository.findById(id)
.orElseThrow(() -> new RuntimeException("商品不存在"));
}
@CacheEvict(value = "products", key = "#product.id")
public void updateProduct(Product product) {
productRepository.save(product);
}
// 扣减库存
@Transactional
public boolean decreaseStock(Long productId, Integer quantity) {
String lockKey = "product_stock_" + productId;
try {
// 获取分布式锁
Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (Boolean.FALSE.equals(locked)) {
return false;
}
Product product = productRepository.findById(productId)
.orElseThrow(() -> new RuntimeException("商品不存在"));
if (product.getStock() < quantity) {
return false;
}
product.setStock(product.getStock() - quantity);
productRepository.save(product);
return true;
} finally {
redisTemplate.delete(lockKey);
}
}
}
订单服务实现:
// 实体类
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
private BigDecimal totalAmount;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> items;
// 构造函数、getter和setter...
}
@Entity
@Table(name = "order_items")
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "order_id")
private Order order;
private Long productId;
private String productName;
private Integer quantity;
private BigDecimal price;
// 构造函数、getter和setter...
}
// Service
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final ProductFeignClient productFeignClient;
private final PaymentFeignClient paymentFeignClient;
public OrderService(OrderRepository orderRepository, ProductFeignClient productFeignClient, PaymentFeignClient paymentFeignClient) {
this.orderRepository = orderRepository;
this.productFeignClient = productFeignClient;
this.paymentFeignClient = paymentFeignClient;
}
@Transactional
public Order createOrder(OrderDTO orderDTO) {
// 1. 验证商品
BigDecimal totalAmount = BigDecimal.ZERO;
List<OrderItem> items = new ArrayList<>();
for (OrderItemDTO itemDTO : orderDTO.getItems()) {
Product product = productFeignClient.getProductById(itemDTO.getProductId());
if (product == null) {
throw new RuntimeException("商品不存在: " + itemDTO.getProductId());
}
// 2. 扣减库存
boolean success = productFeignClient.decreaseStock(itemDTO.getProductId(), itemDTO.getQuantity());
if (!success) {
throw new RuntimeException("库存不足: " + product.getName());
}
// 3. 计算金额
BigDecimal itemAmount = product.getPrice().multiply(new BigDecimal(itemDTO.getQuantity()));
totalAmount = totalAmount.add(itemAmount);
OrderItem item = new OrderItem();
item.setProductId(product.getId());
item.setProductName(product.getName());
item.setQuantity(itemDTO.getQuantity());
item.setPrice(product.getPrice());
items.add(item);
}
// 4. 创建订单
Order order = new Order();
order.setUserId(orderDTO.getUserId());
order.setTotalAmount(totalAmount);
order.setStatus(OrderStatus.PENDING);
order.setItems(items);
items.forEach(item -> item.setOrder(order));
orderRepository.save(order);
// 5. 发送订单创建事件
// eventPublisher.publishEvent(new OrderCreatedEvent(this, order));
return order;
}
@Transactional
public void processPayment(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
if (order.getStatus() != OrderStatus.PENDING) {
throw new RuntimeException("订单状态不正确");
}
// 调用支付服务
boolean paymentSuccess = paymentFeignClient.processPayment(orderId, order.getTotalAmount());
if (paymentSuccess) {
order.setStatus(OrderStatus.PAID);
orderRepository.save(order);
} else {
// 支付失败,恢复库存
for (OrderItem item : order.getItems()) {
productFeignClient.increaseStock(item.getProductId(), item.getQuantity());
}
throw new RuntimeException("支付失败");
}
}
}
10.2 微服务通信模式
同步通信(Feign):
@FeignClient(name = "inventory-service")
public interface InventoryFeignClient {
@GetMapping("/api/inventory/{productId}")
Inventory getInventory(@PathVariable("productId") Long productId);
@PostMapping("/api/inventory/decrease")
boolean decreaseStock(@RequestParam("productId") Long productId, @RequestParam("quantity") Integer quantity);
}
异步通信(消息队列):
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
@Service
public class OrderEventService {
private final KafkaTemplate<String, Object> kafkaTemplate;
public OrderEventService(KafkaTemplate<String, Object> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public void publishOrderCreatedEvent(Order order) {
kafkaTemplate.send("order-created", order);
}
@KafkaListener(topics = "order-created", groupId = "inventory-group")
public void handleOrderCreated(Order order) {
// 处理订单创建事件,如更新库存、发送通知等
System.out.println("收到订单创建事件: " + order.getId());
}
}
10.3 分布式事务处理
Saga模式实现:
// Saga协调器
@Service
public class OrderSagaCoordinator {
private final OrderService orderService;
private final InventoryService inventoryService;
private final PaymentService paymentService;
public void createOrderSaga(OrderDTO orderDTO) {
try {
// 1. 创建订单(临时状态)
Order order = orderService.createOrder(orderDTO);
// 2. 扣减库存
boolean inventorySuccess = inventoryService.decreaseStock(orderDTO);
if (!inventorySuccess) {
// 补偿:取消订单
orderService.cancelOrder(order.getId());
throw new RuntimeException("库存扣减失败");
}
// 3. 处理支付
boolean paymentSuccess = paymentService.processPayment(order.getId(), order.getTotalAmount());
if (!paymentSuccess) {
// 补偿:恢复库存,取消订单
inventoryService.increaseStock(orderDTO);
orderService.cancelOrder(order.getId());
throw new RuntimeException("支付失败");
}
// 4. 确认订单
orderService.confirmOrder(order.getId());
} catch (Exception e) {
// 记录Saga失败
log.error("Saga执行失败: {}", e.getMessage());
throw e;
}
}
}
10.4 监控与日志
Micrometer集成:
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Counter;
import org.springframework.stereotype.Component;
@Component
public class MetricsCollector {
private final Counter orderCounter;
public MetricsCollector(MeterRegistry registry) {
this.orderCounter = Counter.builder("orders.total")
.description("Total number of orders")
.register(registry);
}
public void incrementOrderCount() {
orderCounter.increment();
}
}
分布式追踪(Sleuth + Zipkin):
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0
第十一部分:Spring面试题与高级知识点
11.1 核心原理面试题
1. Spring Bean的作用域有哪些?
- singleton:默认作用域,每个容器中一个Bean实例
- prototype:每次请求都创建新实例
- request:每个HTTP请求一个实例(Web环境)
- session:每个HTTP会话一个实例(Web环境)
- global-session:全局HTTP会话(Portlet环境)
2. Spring如何解决循环依赖? Spring通过三级缓存解决循环依赖:
// 一级缓存:存放完全初始化好的Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:存放早期暴露的Bean(未完全初始化)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存:存放Bean工厂,用于创建Bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
3. Spring AOP代理方式选择
- JDK动态代理:目标类实现了接口
- CGLIB代理:目标类没有实现接口
// 强制使用CGLIB
@EnableAspectJAutoProxy(proxyTargetClass = true)
11.2 性能调优面试题
1. 如何优化Spring Boot启动速度?
- 延迟初始化:
spring.main.lazy-initialization=true - 减少类路径扫描:
@ComponentScan指定具体包 - 使用Spring Boot 2.3+的分层JAR
- 使用GraalVM编译为原生镜像
2. 如何优化数据库连接池?
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
leak-detection-threshold: 60000
11.3 架构设计面试题
1. 如何设计一个高并发的Spring系统?
- 使用缓存(Redis)减少数据库压力
- 使用消息队列(Kafka/RabbitMQ)削峰填谷
- 数据库读写分离
- 使用分布式锁
- 服务降级和熔断
2. Spring Cloud与Dubbo对比
- Spring Cloud:基于HTTP/REST,生态完善,配置简单
- Dubbo:基于RPC,性能更好,服务治理功能强大
第十二部分:Spring学习路线与资源推荐
12.1 学习路线图
阶段一:基础入门(1-2周)
- 掌握IoC和DI
- 理解Bean生命周期
- 学习AOP基础
- 完成第一个Spring应用
阶段二:核心进阶(2-3周)
- 深入理解AOP原理
- 掌握Spring Data访问
- 学习Spring MVC
- 理解事务管理
阶段三:Spring Boot(2周)
- 自动配置原理
- Starter机制
- 配置文件管理
- Actuator监控
阶段四:Spring Security(1-2周)
- 认证与授权
- JWT实现
- OAuth2.0
- 方法级安全
阶段五:微服务架构(3-4周)
- Spring Cloud基础
- 服务注册与发现
- 配置中心
- 熔断器
- 网关
阶段六:高级特性与实战(持续学习)
- 响应式编程
- 性能优化
- 分布式事务
- 容器化部署
12.2 推荐学习资源
官方文档:
- Spring Framework官方文档:https://spring.io/projects/spring-framework
- Spring Boot官方文档:https://spring.io/projects/spring-boot
- Spring Cloud官方文档:https://spring.io/projects/spring-cloud
书籍推荐:
- 《Spring实战》(Craig Walls著)
- 《Spring Boot编程思想》(小马哥著)
- 《Spring Cloud微服务实战》(翟永超著)
- 《Spring 5核心原理》(Tom著)
在线课程:
- Spring官方教程:https://spring.io/guides
- Baeldung Spring教程:https://www.baeldung.com/spring-tutorial
- 廖雪峰Spring教程
社区与论坛:
- Spring官方社区:https://spring.io/community
- Stack Overflow Spring标签
- GitHub Spring项目
- 国内Spring技术社区
12.3 实战项目建议
初级项目:
- 个人博客系统
- 简单的电商后台
- 任务管理系统
中级项目:
- 微服务架构的电商系统
- 在线教育平台
- 社交媒体应用
高级项目:
- 高并发秒杀系统
- 大数据处理平台
- 金融交易系统
总结
Spring框架作为Java企业级开发的基石,其重要性不言而喻。从基础的IoC容器到复杂的微服务架构,Spring提供了一套完整的解决方案。掌握Spring不仅需要理解其核心原理,更需要在实际项目中不断实践和总结。
学习Spring的关键在于:
- 理解核心概念:IoC、AOP、DI是Spring的基石,必须深入理解
- 实践驱动:通过实际项目来巩固知识,不要只停留在理论层面
- 循序渐进:按照学习路线逐步深入,不要急于求成
- 关注生态:Spring不仅仅是一个框架,而是一个完整的生态体系
- 持续学习:技术在不断发展,保持学习的热情和习惯
希望这份指南能够帮助你从Spring入门到精通,在企业级开发的道路上越走越远。记住,最好的学习方式就是动手实践,遇到问题时多查阅官方文档,多参与社区讨论,相信你一定能成为Spring技术专家!
