JavaEE Spring框架的概述与对比无框架下的优势
Spring 是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的 松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。
我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是:核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。
1.Spring的特征与特性
1.1 Spring 官网(Spring | Home)列出的 Spring 的 6 个特征:
- 核心技术 :依赖注入(DI),AOP,事件(events),资源,i18n,验证,数据绑定,类型转换,SpEL。
- 测试 :模拟对象,TestContext框架,Spring MVC 测试,WebTestClient。
- 数据访问 :事务,DAO支持,JDBC,ORM,编组XML。
- Web支持 : Spring MVC和Spring WebFlux Web框架。
- 集成 :远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。
- 语言 :Kotlin,Groovy,动态语言。
1.2 Spring的核心特性 对比无框架的优势
1.2.1 IoC(控制反转)与 DI(依赖注入):通过 IoC 容器管理对象的创建和依赖关系,减少代码耦合。
new
。new
关键字创建对象,对象的生命周期由开发者手动控制(创建、销毁)。@Autowired private UserService userService
即可获取依赖,无需在代码中new UserService()
。UserService userService = new UserServiceImpl();
若UserService
的实现类变更,所有引用处都需修改,耦合度极高。无框架实现:
// 1. 定义接口public interface UserService { void createUser(String username);}// 2. 实现类public class UserServiceImpl implements UserService { private UserDao userDao; // 依赖UserDao public UserServiceImpl() { // 硬编码创建依赖对象 this.userDao = new UserDaoImpl(); } @Override public void createUser(String username) { // 业务逻辑 + 依赖调用 System.out.println(\"Creating user: \" + username); userDao.save(username); }}// 3. 客户端调用public class Client { public static void main(String[] args) { // 手动创建对象及依赖链 UserService service = new UserServiceImpl(); service.createUser(\"test\"); }}
问题:
UserServiceImpl
与UserDaoImpl
强绑定,若需替换UserDao
实现(如改为测试用的MockUserDao
),必须修改UserServiceImpl
代码。
Spring 框架实现(依赖注入):
// 1. 定义接口public interface UserService { void createUser(String username);}// 2. 实现类(通过@Service自动注册为Bean)@Servicepublic class UserServiceImpl implements UserService { private final UserDao userDao; // 依赖UserDao // 构造器注入(@Autowired可省略) public UserServiceImpl(UserDao userDao) { this.userDao = userDao; } @Override public void createUser(String username) { System.out.println(\"Creating user: \" + username); userDao.save(username); }}// 3. 配置类(或通过@ComponentScan自动扫描)@Configuration@ComponentScan(basePackages = \"com.example.service\")public class AppConfig { @Bean public UserDao userDao() { return new UserDaoImpl(); // 配置依赖实现 }}// 4. 客户端调用public class Client { public static void main(String[] args) { // 通过Spring容器获取Bean,无需手动创建 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService service = context.getBean(UserService.class); service.createUser(\"test\"); }}
优势:
UserServiceImpl
不负责创建UserDao
,依赖关系由 Spring 容器管理,可通过配置动态替换实现(如测试时注入MockUserDao
)。- 对象创建逻辑集中在配置类,客户端只需从容器获取 Bean,降低耦合。
1.2.2 AOP(面向切面编程):允许分离横切关注点(如日志、事务管理),提高代码模块化。
@Aspect
定义切面,通过@Before
/@After
指定拦截规则,无需侵入业务代码。无框架下的问题代码:
public class UserServiceImpl implements UserService { @Override public void createUser(String username) { // 1. 重复的前置日志(横切逻辑) System.out.println(\"[INFO] Start creating user: \" + username); long startTime = System.currentTimeMillis(); // 2. 核心业务逻辑 try { System.out.println(\"Creating user in database...\"); Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } // 3. 重复的后置日志(横切逻辑) long endTime = System.currentTimeMillis(); System.out.println(\"[INFO] User created. Time elapsed: \" + (endTime - startTime) + \"ms\"); }}
问题:横切逻辑与业务逻辑耦合,导致代码冗余、难以维护
Spring 框架实现(AOP 切面)
// 1. 定义业务逻辑(纯净,无日志代码)@Servicepublic class UserServiceImpl implements UserService { @Override public void createUser(String username) { System.out.println(\"Creating user in database...\"); // 模拟数据库操作 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } }}// 2. 定义切面(集中处理日志)@Aspect@Componentpublic class LoggingAspect { // 定义切点:拦截UserService接口的所有方法 @Pointcut(\"execution(* com.example.service.UserService.*(..))\") public void serviceMethods() {} // 前置通知 @Before(\"serviceMethods()\") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println(\"[INFO] Start method: \" + methodName + \", args: \" + Arrays.toString(args)); } // 后置通知 @AfterReturning(\"serviceMethods()\") public void afterMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println(\"[INFO] Method completed: \" + methodName); } // 环绕通知(计算方法执行时间) @Around(\"serviceMethods()\") public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); Object result = pjp.proceed(); // 执行目标方法 long endTime = System.currentTimeMillis(); System.out.println(\"[INFO] Time elapsed: \" + (endTime - startTime) + \"ms\"); return result; }}// 3. 启用AOP(通过@EnableAspectJAutoProxy)@Configuration@ComponentScan(basePackages = \"com.example\")@EnableAspectJAutoProxypublic class AppConfig { // 配置略}
优势:
- 业务代码与日志逻辑完全分离,
UserServiceImpl
仅关注核心功能。 - 日志逻辑集中在切面类,修改日志格式只需调整一处。
- 可动态控制是否启用切面(如生产环境开启,测试环境关闭)。
1.2.3 事务管理:提供声明式事务管理,简化数据库事务处理。
@Transactional
注解或 XML 配置即可控制事务(自动处理begin
、commit
,异常时rollback
),无需手动编写事务控制代码。代码冗余且易出错(如忘记回滚、异常处理不完整)。
REQUIRED
、REQUIRES_NEW
)可通过配置控制,确保复杂业务(多方法调用)的事务一致性。无框架实现(JDBC 手动管理事务)
public class UserServiceImpl implements UserService { private DataSource dataSource; // 数据库连接池 public UserServiceImpl(DataSource dataSource) { this.dataSource = dataSource; } @Override public void transferMoney(String fromUser, String toUser, double amount) { Connection conn = null; try { // 1. 获取连接并开启事务 conn = dataSource.getConnection(); conn.setAutoCommit(false); // 开启事务 // 2. 业务操作1:扣款 updateBalance(conn, fromUser, -amount); // 3. 模拟异常(测试回滚) if (amount > 1000) { throw new RuntimeException(\"金额超过限制\"); } // 4. 业务操作2:收款 updateBalance(conn, toUser, amount); // 5. 提交事务 conn.commit(); } catch (Exception e) { // 6. 异常时回滚 if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } throw new RuntimeException(\"转账失败\", e); } finally { // 7. 关闭连接 if (conn != null) { try { conn.setAutoCommit(true); // 恢复默认提交模式 conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } private void updateBalance(Connection conn, String username, double amount) throws SQLException { // JDBC操作略 }}
问题:
- 事务控制代码(获取连接、开启 / 提交 / 回滚事务)与业务逻辑混杂,代码冗长。
- 异常处理复杂,易遗漏回滚操作导致数据不一致。
- 若业务逻辑变更(如新增操作),需手动调整事务边界。
Spring 框架实现(声明式事务)
// 1. 配置数据源和事务管理器@Configuration@EnableTransactionManagement // 启用事务管理public class AppConfig { @Bean public DataSource dataSource() { // 配置数据源(如HikariCP) return DataSourceBuilder.create() .url(\"jdbc:mysql://localhost:3306/test\") .username(\"root\") .password(\"password\") .build(); } @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }}// 2. 业务服务(使用@Transactional声明事务)@Servicepublic class UserServiceImpl implements UserService { private JdbcTemplate jdbcTemplate; public UserServiceImpl(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override @Transactional(rollbackFor = Exception.class) // 声明式事务 public void transferMoney(String fromUser, String toUser, double amount) { // 1. 扣款 updateBalance(fromUser, -amount); // 2. 模拟异常 if (amount > 1000) { throw new RuntimeException(\"金额超过限制\"); } // 3. 收款 updateBalance(toUser, amount); } private void updateBalance(String username, double amount) { // 使用JdbcTemplate执行SQL(无需手动管理连接) jdbcTemplate.update(\"UPDATE users SET balance = balance + ? WHERE username = ?\", amount, username); }}
优势:
- 事务控制通过
@Transactional
注解声明,业务代码中无需手动处理连接、提交 / 回滚事务。 - 异常时自动回滚(默认回滚
RuntimeException
及其子类),可通过rollbackFor
自定义回滚条件。 - 支持事务传播行为(如
REQUIRED
、REQUIRES_NEW
),适用于复杂业务场景。
1.2.4 MVC 架构:Spring MVC 框架支持构建灵活的 Web 应用,处理请求映射、视图解析等。
DispatcherServlet
统一接收请求,通过@RequestMapping
映射到具体控制器(Controller),职责清晰(前端控制器模式)。@Valid
)、异常统一处理(@ExceptionHandler
)等,减少重复代码。request.getParameter()
)、手动校验数据、手动处理异常,代码冗余且易出错。无框架实现:
// 1. 手动编写Servlet处理用户注册请求@WebServlet(\"/register\")public class UserRegisterServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. 获取请求参数(手动解析) String username = req.getParameter(\"username\"); String password = req.getParameter(\"password\"); // 2. 数据校验(手动实现) if (username == null || username.isEmpty()) { resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); resp.getWriter().write(\"Username is required\"); return; } // 3. 调用业务逻辑 UserService userService = new UserServiceImpl(); // 手动创建Service try { userService.registerUser(username, password); resp.setStatus(HttpServletResponse.SC_OK); resp.getWriter().write(\"Registration successful\"); } catch (Exception e) { resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); resp.getWriter().write(\"Error: \" + e.getMessage()); } }}// 2. 部署Servlet(需在web.xml中配置或使用@WebServlet注解)
问题:
- Servlet 职责混乱(同时处理参数解析、校验、业务逻辑、异常处理、视图渲染)。
- 参数解析和校验逻辑重复(每个 Servlet 都需编写类似代码)。
- 异常处理分散,难以统一管理。
- 视图渲染与业务逻辑耦合(如直接在 Servlet 中输出 HTML)。
Spring 框架实现(Spring MVC)
// 1. 定义Controller处理请求@RestController@RequestMapping(\"/api/users\")public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } // 处理注册请求 @PostMapping(\"/register\") public ResponseEntity registerUser(@RequestBody @Valid UserRegistrationRequest request) { // 1. 参数自动绑定到UserRegistrationRequest对象 // 3. 调用业务逻辑 userService.registerUser(request.getUsername(), request.getPassword()); // 4. 返回响应(自动序列化为JSON) return ResponseEntity.ok(\"Registration successful\"); } // 5. 统一异常处理 @ExceptionHandler(UserAlreadyExistsException.class) public ResponseEntity handleUserAlreadyExists(UserAlreadyExistsException ex) { return ResponseEntity.status(HttpStatus.CONFLICT).body(ex.getMessage()); }}// 2. 数据模型(含校验注解)@Data // Lombok注解public class UserRegistrationRequest { @NotBlank(message = \"Username is required\") private String username; @NotBlank(message = \"Password is required\") @Size(min = 6, message = \"Password must be at least 6 characters\") private String password;}// 3. 启用Spring MVC(通过@SpringBootApplication)@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
优势:
- 职责分离:Controller 仅负责请求路由和参数校验,业务逻辑由 Service 处理,视图渲染由视图解析器处理。
- 参数自动绑定:通过
@RequestBody
和@RequestParam
自动将 HTTP 请求数据映射到 Java 对象。 - 数据校验:通过 JSR-303 注解(如
@NotBlank
、@Size
)实现声明式校验,无需手动编写校验逻辑。 - 统一异常处理:通过
@ExceptionHandler
集中处理特定异常,返回标准化错误响应。
1.2.5 集成支持:无缝集成各种技术(如 JDBC、ORM 框架、缓存、安全等)。
通过 starter(如
spring-boot-starter-data-redis
)简化配置,无需手动处理技术细节。需解决技术间的兼容性(如版本冲突),开发效率低。
application.properties
、@Configuration
),集中管理各技术的配置(如数据库连接、缓存过期时间)。db.properties
、Redis 的redis.conf
)中,需手动加载和维护,易出现配置不一致。总结
通过上述示例可见:
- Spring 框架通过注解(如
@Autowired
、@Transactional
)和容器(如ApplicationContext
)简化对象管理和依赖注入,用 AOP 分离横切逻辑,用声明式事务管理数据库操作,用 MVC 架构统一处理 Web 请求,大幅减少重复代码,提升开发效率。 - 无框架开发需手动处理对象创建、依赖关系、事务边界、Web 请求解析等底层细节,导致代码耦合度高、可维护性差。
选择 Spring 框架的核心价值在于 “聚焦业务,而非基础设施”,让开发者将更多精力投入到业务逻辑实现中。