Spring 是一个开源的轻量级 Java 开发框架,旨在简化企业级应用开发。它通过控制反转(IoC)和面向切面编程(AOP)实现组件解耦和横切逻辑分离,提升系统的可维护性与扩展性。Spring 提供统一的事务管理、灵活的 Web 开发框架(Spring MVC),并支持与多种第三方技术集成。其生态系统包括 Spring Boot(快速构建应用)、Spring Cloud(微服务架构支持)等,已成为现代 Java 开发的核心技术之一
Spring框架采用由内至外的同心圆分层架构:核心层由Spring Core(提供依赖注入与IoC容器)和Spring Context(管理Bean生命周期及上下文配置)构成;中间功能层向外扩展,包含Spring AOP(基于核心实现切面编程)、Spring JDBC(简化数据库操作抽象层)和Spring ORM(集成Hibernate等ORM框架);外层为Spring Web模块,支撑Web应用开发。如下图所示:
IoC(控制反转)是Spring框架的基础机制之一,他的核心思想是将对象的创建和依赖关系的管理从开发者手中剥离,转而交由Spring容器统一进行控制。只需通过XML配置、Java注解或Java配置类的方式声明组件及其依赖关系,Spring容器就会在运行时根据配置动态创建对象,并自动完成依赖注入。
AOP(面向切面编程)则聚焦于系统中横切关注点的解耦与复用。通过将日志记录、权限校验、事务管理等非功能性需求抽象为独立的切面,AOP能够在编译期、类加载期或运行期通过织入(Weaving)机制将这些逻辑动态注入到目标方法中。这种横向抽取的设计避免了业务代码的重复编写,提升了代码的可维护性。
IoC与AOP相辅相成:前者负责纵向的对象生命周期管理,后者则横向增强系统功能,二者共同构成了Spring框架高效、模块化的核心支撑体系。
关键字:IOC名词解释,作用是解耦,使用IOC容器管理项目组件之间的耦合关系。
IOC(Inversion of Control,中文释义:控制反转),是Spring框架的核心思想之一,主要用于解耦。IOC是指将创建对象的控制权转移给Spring框架进行管理,由Spring框架根据配置文件或注解等方式,创建bean对象并管理各个bean对象之间的依赖关系。使对象之间形成松耦合的关系,实现解耦。
ioc的思想最核心的地方在于,资源不由使用资源者管理,而由不使用资源的第三方管理,这可以带来很多好处,比如在实际项目中一个 Service 类可能依赖了很多其他的类,假如我们需要实例化这个 Service,可能要每次都要搞清这个 Service 所有底层类的构造函数,这就变得复杂了。而如果使用 IoC 的话,只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
xml配置
顾名思义,就是将bean的信息配置.xml文件里,通过Spring加载文件来创建bean。这种方式出现很多早前的SSM项目中,将第三方类库或者一些配置工具类都以这种方式进行配置,主要原因是由于第三方类不支持Spring注解。
举例:
<?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">
<!-- services -->
<bean id="userService" class="com.seven.springframework.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
java配置
将类的创建交给我们配置的JavcConfig类来完成,Spring只负责维护和管理,采用纯Java创建方式。其本质上就是把在XML上的配置声明转移到Java配置类中
举例:
@Configuration
public class BeansConfig {
@Bean("userDao")
public UserDaoImpl userDao() {
return new UserDaoImpl();
}
@Bean("userService")
public UserServiceImpl userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao());
return userService;
}
}
注解配置
通过在类上加注解的方式,来声明一个类交给Spring管理,Spring会自动扫描带有@Component,@Controller,@Service,@Repository这四个注解的类,然后帮我们创建并管理,前提是需要先配置Spring的注解扫描器。
举例:
@Service
public class UserServiceImpl {
@Autowired
private UserDaoImpl userDao;
public List<User> findUserList() {
return userDao.findUserList();
}
}
总结:
方式 | 适用场景 | 灵活性 | 可维护性 | 学习成本 |
---|---|---|---|---|
XML配置 | 遗留系统/第三方库 | ★★★★☆ | ★★☆☆☆ | ★★☆☆☆ |
Java配置 | 复杂业务逻辑/条件化Bean | ★★★★★ | ★★★★☆ | ★★★☆☆ |
注解配置 | 新项目/领域模型 | ★★★☆☆ | ★★★★☆ | ★★☆☆☆ |
术语解析:
简单理解:Spring会创建一个"代理"对象,这个代理对象包含原对象的所有功能,同时可以在方法调用前后添加额外的逻辑。
Spring AOP是AspectJ的简化版,两者有以下区别:
特性 | Spring AOP | AspectJ |
---|---|---|
功能 | 基本的AOP功能 | 完整的AOP功能 |
织入时机 | 运行时 | 编译时、加载时 |
性能 | 相对较低 | 更高 |
学习曲线 | 较低 | 较高 |
使用场景 | 简单应用 | 复杂应用 |
在大多数应用场景中,Spring AOP所提供的功能已能充分满足业务需求,无需额外引入AspectJ框架。Spring AOP基于动态代理的实现方式在性能与复杂度之间取得了良好平衡,其轻量级特性更适合常规开发需求。
定义切面类:
使用@Aspect
注解标记一个类为切面类,示例代码如下:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义一个切点,匹配 com.example.service 包下所有类的所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 可以定义更多的切点,例如匹配特定注解的方法
@Pointcut("@annotation(com.example.annotation.Loggable)")
public void loggableMethods() {}
}
使用@Before
注解标记一个方法为前置通知,在目标方法执行前执行,示例代码如下:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义切点...
// 在 serviceMethods 切点处执行的前置通知
@Before("serviceMethods()")
public void logBeforeMethodExecution(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("Before executing method: " + className + "." + methodName);
}
// 在 loggableMethods 切点处执行的前置通知
@Before("loggableMethods()")
public void logBeforeLoggableMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("Before executing loggable method: " + className + "." + methodName);
}
}
使用@After
注解标记一个方法为后置通知,在目标方法执行后执行,无论目标方法是否抛出异常,示例代码如下:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义切点...
@Before("serviceMethods()")
public void logBeforeMethodExecution(JoinPoint joinPoint) {
// 前置通知逻辑...
}
@After("serviceMethods()")
public void logAfterMethodExecution(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("After executing method: " + className + "." + methodName);
}
}
使用@AfterReturning
注解标记一个方法为返回通知,在目标方法正常返回后执行,示例代码如下:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义切点...
@Before("serviceMethods()")
public void logBeforeMethodExecution(JoinPoint joinPoint) {
// 前置通知逻辑...
}
@After("serviceMethods()")
public void logAfterMethodExecution(JoinPoint joinPoint) {
// 后置通知逻辑...
}
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("Method " + className + "." + methodName + " returned with value: " + result);
}
}
使用@AfterThrowing
注解标记一个方法为异常通知,在目标方法抛出异常后执行,示例代码如下:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义切点...
@Before("serviceMethods()")
public void logBeforeMethodExecution(JoinPoint joinPoint) {
// 前置通知逻辑...
}
@After("serviceMethods()")
public void logAfterMethodExecution(JoinPoint joinPoint) {
// 后置通知逻辑...
}
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
// 返回通知逻辑...
}
@AfterThrowing(pointcut = "serviceMethods()", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("Method " + className + "." + methodName + " threw exception: " + exception.getMessage());
}
}
使用 @Around
注解标记一个方法为环绕通知,环绕通知可以在目标方法执行前后都进行增强,并且可以控制目标方法的执行,示例代码如下:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// 定义切点...
@Around("serviceMethods()")
public Object logAroundMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("Before executing method: " + className + "." + methodName);
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("After executing method: " + className + "." + methodName);
System.out.println("Method execution time: " + (endTime - startTime) + " ms");
return result;
}
}
OP 注意事项
在使用 AOP 时,需要注意以下几点:
总结
pring AOP通过@Aspect注解定义切面类,结合@Pointcut可灵活配置多种切点表达式(如包路径匹配或注解匹配),再通过@Before、@After、@AfterReturning、@AfterThrowing和@Around等通知注解实现不同增强逻辑。前置通知在目标方法执行前触发,后置通知无论是否异常都会执行,返回通知仅在正常返回时触发,异常通知捕获方法抛出的异常,环绕通知则能完全控制目标方法的执行流程并测量执行时间。但是使用时要注意能影响、切点表达式准确性、循环依赖风险、异常处理规范以及不同AOP实现方式的兼容性等问题。
完成之后点击创建等待创建成功
创建完成后的项目结构如下
源代码写在src目录下
test目录主要是测试
插入取消访问 Maven 仓库査找 Spring 依赖:https://mvnrepository.com/
点击第一个
选择6.1.14后点击
选择Maven后将下面内容复制
复制后在pom.xml文件中粘贴
点击更新maven
在examp目录下创建java类
在创建的类中添加
选中前三个方法后点击鼠标右键生成
点击Getter 和 Setter
选中全部后点击确定
在main下创建一个目录
创建resources文件
在这个目录下创建spring配置文件
导入spring文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframeworkframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframeworkframework.org/schema/beans http://www.springframeworkframework.org/schema/beans/spring-beans.xsd">
</beans>
将User对象存储到Spring容器
调用实例打印user中的方法
成功打印出你好!spring
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有