当前位置: 首页 > web >正文

Spring介绍以及IOC和AOP的实现

Spring

spring是由interface21框架为基础经过重新设计,并不断丰富其内涵在2004年3月24日发布了1.0版本。

spring的创作理念就在于使现有的技术更加容易使用

优点
  • Spring是一个开源的免费框架(容器)

  • Spring是一个轻量级非入侵式的框架

  • Spring的核心技术控制反转(IOC)和面向切面编程(AOP)

  • 支持事务的处理,支持框架的整合。

总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架

Spring的组成

  1. Core Container(核心容器)

    • 功能:IoC(控制反转)和 DI(依赖注入)实现,管理 Bean 的生命周期。

    • 核心类ApplicationContextBeanFactory

  2. AOP(面向切面编程)

    • 功能:通过动态代理实现日志、事务等横切逻辑。

    • 注解@Aspect@Transactional

  3. Data Access(数据访问)

    • 功能:简化 JDBC(JdbcTemplate)、集成 ORM(Hibernate/JPA)。

    • 事务管理:声明式事务(@Transactional

  4. Web MVC

    • 功能:基于 Servlet 的 MVC 框架,支持 REST。

    • 核心类DispatcherServlet@Controller

  5. Context(上下文)

    • 功能:扩展 ApplicationContext,提供国际化、事件机制等。

  6. WebFlux(响应式 Web)

    • 功能:非阻塞响应式编程(基于 Reactor),替代传统 Web MVC。

  7. Testing(测试)

    • 功能:集成 JUnit,支持 Mock 测试(@SpringBootTest)。

IOC和AOP

Spring Ioc:控制反转的意思,它指的是一种思想,早些时候我们需要通过new关键字来创造对象,这就存在了一个弊端,当用户需要其它功能的时候,就会出现问题,我们就需要实时的根据需求进行修改,当我们通过IOC容器来帮我们进行实例化对象的时候,就大大的降低了对象之间的耦合度。依赖注入DI就是实现这个技术的一种方式。

AOP(面向切面编程) 的核心思想是:将与业务无关的通用功能(如日志、事务、权限)从业务代码中剥离,以切面(Aspect)的形式统一管理,避免代码重复和耦合。Spring AOP 的代理实现分为 JDK 动态代理CGLIB 代理,具体选择取决于目标对象是否实现接口。

当我们使用Spring AOP的时候:

1.先添加依赖:

<!-- Maven 依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.定义切面类

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
​
@Aspect
@Component
public class LogAspect {
​// 定义切入点:拦截 service 包下所有方法@Pointcut("execution(* com.example.service.*.*(..))")public void serviceMethods() {}
​// 前置通知:方法执行前调用@Before("serviceMethods()")public void beforeAdvice() {System.out.println("【前置通知】准备执行方法...");}
​// 后置通知:方法正常返回后调用@AfterReturning(pointcut = "serviceMethods()", returning = "result")public void afterReturningAdvice(Object result) {System.out.println("【后置通知】方法执行成功,返回值:" + result);}
​// 异常通知:方法抛出异常时调用@AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")public void afterThrowingAdvice(Exception ex) {System.out.println("【异常通知】方法执行异常:" + ex.getMessage());}
​// 环绕通知:控制方法整个执行流程@Around("serviceMethods()")public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {System.out.println("【环绕通知】方法开始执行...");Object result = pjp.proceed(); // 执行目标方法System.out.println("【环绕通知】方法执行结束");return result;}
}

3.切入点表达式

Spring AOP使用AspectJ切入点表达式语言定义切入点:

  • execution([修饰符] 返回类型 [类名].方法名(参数) [异常])

    • * 代表任意

    • .. 代表任意参数或包路径

    • 示例:

      • execution(public * *(..)) - 所有public方法

      • execution(* set*(..)) - 所有以set开头的方法

      • execution(* com.xyz.service.*.*(..)) - service包下所有类的所有方法

      • execution(* com.xyz.service..*.*(..)) - service包及其子包下所有类的所有方法

4.通知执行顺序

  1. 环绕通知的前半部分(@Around)

  2. 前置通知(@Before)

  3. 目标方法执行

  4. 后置通知(@AfterReturning)或异常通知(@AfterThrowing)

  5. 最终通知(@After)

  6. 环绕通知的后半部分(@Around)

可以通过@Order注解指定切面执行顺序:

@Aspect
@Component
@Order(1)  // 数字越小优先级越高
public class LoggingAspect {// ...
}

Spring AOP的高级特性

1.获取方法的信息

在通知方法中可以通过JoinPointProceedingJoinPoint获取方法信息:

@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {// 获取方法签名MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();// 获取方法参数名和值String[] paramNames = signature.getParameterNames();Object[] paramValues = joinPoint.getArgs();// 获取目标类Object target = joinPoint.getTarget();Class<?> targetClass = target.getClass();
}

2.处理通知中的异常

在环绕通知当中可以捕获并处理异常

@Around("serviceLayer()")
public Object handleException(ProceedingJoinPoint joinPoint) {try {return joinPoint.proceed();} catch (BusinessException ex) {// 处理业务异常return fallbackResult();} catch (Throwable ex) {// 处理其他异常throw new RuntimeException("系统异常", ex);}
}

Spring AOP 的代理实现分为 JDK 动态代理CGLIB 代理,具体选择取决于目标对象是否实现接口。

JDK动态代理

需要目标至少实现一个接口,实现原理:JDK动态代理通过反射在运行时动态生成实现指定接口的代理类,将方法调用转发到InvocationHandler处理,在调用真实方法前后可插入自定义逻辑。

我们进行示例:

1.定义业务接口和实现

public interface OrderService {void createOrder(String orderId);void cancelOrder(String orderId);
}
public class OrderServiceImpl implements OrderService {@Overridepublic void createOrder(String orderId) {System.out.println("创建订单: " + orderId);}@Overridepublic void cancelOrder(String orderId) {System.out.println("取消订单: " + orderId);}
}

2.实现InvocationHandler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
​
public class OrderServiceHandler implements InvocationHandler {private final Object target;  // 目标对象public OrderServiceHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置处理System.out.println("[日志] 开始执行 " + method.getName() + " 方法");System.out.println("[参数] " + (args != null ? Arrays.toString(args) : "无"));// 调用目标方法Object result = method.invoke(target, args);// 后置处理System.out.println("[日志] " + method.getName() + " 方法执行完成");return result;}
}

3.创建并使用

import java.lang.reflect.Proxy;
​
public class JdkProxyDemo {public static void main(String[] args) {// 1. 创建目标对象OrderService target = new OrderServiceImpl();// 2. 创建调用处理器OrderServiceHandler handler = new OrderServiceHandler(target);// 3. 创建代理对象OrderService proxy = (OrderService) Proxy.newProxyInstance(OrderService.class.getClassLoader(),  // 类加载器new Class[]{OrderService.class},     // 代理接口数组handler                             // 调用处理器);// 4. 使用代理对象proxy.createOrder("ORD123456");System.out.println("----------------");proxy.cancelOrder("ORD123456");}
}

执行结果

[日志] 开始执行 createOrder 方法
[参数] [ORD123456]
创建订单: ORD123456
[日志] createOrder 方法执行完成
----------------
[日志] 开始执行 cancelOrder 方法
[参数] [ORD123456]
取消订单: ORD123456
[日志] cancelOrder 方法执行完成

CGLIB动态代理

CGLIB动态代理通过继承目标类生成子类,重写方法实现代理,无需接口即可拦截方法调用(无法代理final类/方法)。

示例:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
​
public class CglibDemo {// 目标类(无需接口)static class UserService {public void saveUser(String name) {System.out.println("保存用户: " + name);}}
​public static void main(String[] args) {// 1. 创建 EnhancerEnhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class); // 设置父类(目标类)// 2. 设置回调(拦截逻辑)enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {System.out.println("[CGLIB] 方法调用前: " + method.getName());Object result = proxy.invokeSuper(obj, args); // 调用父类方法System.out.println("[CGLIB] 方法调用后");return result;});
​// 3. 生成代理对象UserService proxy = (UserService) enhancer.create();// 4. 调用代理方法proxy.saveUser("张三");}
}

Spring AOP 是高层抽象,底层默认通过 JDK动态代理(基于接口)或 CGLIB(基于子类)实现动态代理

http://www.xdnf.cn/news/15777.html

相关文章:

  • SpringBoot项目创建,三层架构,分成结构,IOC,DI相关,@Resource与@Autowired的区别
  • Camera相机人脸识别系列专题分析之十七:人脸特征检测FFD算法之libhci_face_camera_api.so 296点位人脸识别检测流程详解
  • Flutter——Android原生View是如何通过Flutter进行加载
  • 关于Mysql开启慢查询日志报错:13 - Permission denied的解决方案
  • logback日志控制服务器日志输出
  • 对Yii2中开启`authenticator`后出现的跨域问题-修复
  • 图机器学习(11)——链接预测
  • 现代R语言【Tidyverse、Tidymodel】的机器学习方法
  • Typecho博客集成阿里云CDN+OSS实现全站加速方案
  • 关于字符编辑器vi、vim版本的安装过程及其常用命令:
  • 第七章 愿景09 海波龙的坑
  • 数字化转型:概念性名词浅谈(第三十讲)
  • Kotlin集合过滤
  • 文档处理控件TX Text Control系列教程:使用 C# .NET 将二维码添加到 PDF 文档
  • 从拆分到导出图片,这款工具如何简化PDF处理流程
  • 基于R语言piecewiseSEM结构方程模型在生态环境领域实践技术应用
  • 无标记点动捕:如何突破传统娱乐边界,打造沉浸式交互体验
  • RuoYi-Cloud框架功能分析与请求处理流程解析
  • docker,防火墙关闭后,未重启docker,导致端口映射失败
  • 【3D并排条状图】:附Origin详细画图教程
  • CertiK创始人顾荣辉出席上海Conflux大会,聚焦Web3全球化中的安全与合规路径
  • 区块链加密技术全景解析
  • (nice!!!)(LeetCode 每日一题) 2163. 删除元素后和的最小差值 (贪心+优先队列)
  • Java学习第五十三部分——后端常用函数
  • 从抓包GitHub Copilot认证请求,认识OAuth 2.0技术
  • 性能远超Spring Cloud Gateway!Apache ShenYu如何重新定义API网关!
  • 集成开发环境:在IntelliJ IDEA中高效运行与调试Spring Boot
  • LangChain 源码剖析(三):连接提示词与大语言模型的核心纽带——LLMChain
  • Mock 单元测试
  • AI驱动数据质量优化:破局数据治理难题