AOP相关面试题
什么是AOP答AOP面向切面编程。核心思想将横切关注点从核心逻辑中分离出来形成一个一个切面横切关注点多个类或对象中的公共行为如日志记录、事务管理、接口限流、接口幂等性切面Aspect对横切关注点进行封装的类最核心的三个实际应用场景统一日志记录不需要在每个Controller里写log.info直接搞个切面拦截所有请求然后记录日志权限校验加个自定义注解切面识别到这个注解就自定查一下这个人有没有权限Spring事物Transactional: Transactional注解的底层就是一个AOP切面。AOP常见的通知类型有哪些通知切面在某个连接点要执行的操作。有五种类型Before目标方法执行前执行After目标方法执行后执行Around环绕通知可以拿到目标对象以及要执行的方法可以编写代码控制目标方法的执行过程在目标方法的前或后执行After Returning目标方法调用完之后在结果return之前触发After Throwing目标方法运行抛出异常后执行Spring AOP实现方法有哪些Spring AOP基于动态代理实现的。动态代理是在运行时动态生成代理对象从而实现在不修改源代码的情况下增强方法的功能。Spring AOP支持两种动态代理基于JDK的动态代理使用Proxy类和InvocationHandler接口实现。Spring框架背地里生成代理对象Proxy包含源代码逻辑和增强逻辑基于CGLIB的动态代理当代理类没有实现InvocationHandler接口时Spring框架会使用CGLIB库继承代理类生成一个子类在子类中重写添加增强逻辑Spring AOP属于运行时增强而AspectJ是编译时增强直接基于字节码进行操作。Spring AOP已经集成了AspectJ两者区别Spring AOP是在运行时动态生成代理类启动慢 AspectJ 在编译时就缝合好了运行是没有额外开销性能拉满代价是编译时间长AOP实现接口幂等性的逻辑什么是接口幂等性答不管前端提交几次后端只执行一次使用AOP 自定义注解 Redis实现接口幂等性前端的请求头中带一个用户唯一表示比如订单号、前端申请的唯一token请求传过来时通过redis的 SETNX命令设置对应的值如果为True说明第一次请求放行如果为False说明已经有一摸一样的请求了如果没有AOP在“创建订单”、“支付”、“扣减库存”等业务中都需要执行redis记录和判断的逻辑可以创建AOP切面来进行解耦和复用。还需要自定义注解来加到需要进行幂等性操作的业务方法上。比如自定义 Idempotent 注解AOP切面方法盯着这些注解使用Around 环绕通知执行Redis逻辑来判断是否要放行执行业务方法伪代码Around(annotation(你的自定义注解Idempotent)) public Object checkIdempotent(ProceedingJoinPoint joinPoint) { // 1. 提取当前请求的唯一凭证比如 Header 里的 Token 或 订单号 String token request.getHeader(Idempotent-Token); // 2. 去 Redis 里占坑利用 SETNX 特性并设置个过期时间比如 5秒 boolean success redisTemplate.opsForValue().setIfAbsent(token, 正在处理, 5, TimeUnit.SECONDS); // 3. 判断是否重复请求 if (!success) { // 占坑失败说明是重复点击直接把这颗子弹没收不让它进入 Controller throw new RuntimeException(手速太快啦请勿重复点击); } try { // 4. 占坑成功放行执行目标方法你真正的买皮肤、扣钱逻辑 return joinPoint.proceed(); } finally { // 5. 业务执行完后你可以选择把 Redis 里的坑挖掉或者等它自己过期 // redisTemplate.delete(token); } }Spring 的事务是如何实现的Spring事务的本质就是 数据库 对事物的支持。没有数据库事务的支持 spring是无法提供事务功能的 Spring提供事务管理的统一接口具体实现都是由各个数据库自己实现。Spring 支持 编程式事务管理 和 声明式事务管理1.编程式事务使用 TransactionTemplateAutowired private TransactionTemplate transactionTemplate; public void testTransaction() { transactionTemplate.execute(new TransactionCallbackWithoutResult() { Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { try { // .... 业务代码 } catch (Exception e){ //回滚 transactionStatus.setRollbackOnly(); } } }); }2. 声明式事务使用Transactional声明式事务建立在AOP之上的。其本质是通过AOP功能 对方法前后进行拦截将事务处理的额外功能 和 方法的核心功能功能编制在一起 。无法像编程式事务那样做到代码块级别的事务控制事务的传播机制是指当一个事务的方法被另一个事务方法调用时该事务方法如何进行。正常来说有三种解决方案1. 融入事务直接去掉serviceB中关于开启事务和提交事务的begin和commit融入到serviceA的事务中。问题B事务的错误会引起A事务的回滚。2. 挂起事务如果不想B事务的错误引起A事务的回滚可以开启两个连接一个执行A一个执行B互不影响执行到B的时候把A挂起新起连接去执行BB执行完了再唤醒A执行。两个事务的执行互不干扰B事务的回滚不影响A事务3.嵌套事务MySQL中可以通过给B事务加savepoint和rollback去模拟嵌套事务把B设置成伪事务。嵌套事务会保存回滚点7种事务传播行为TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行如果当前存在事务则抛出异常。默认传播行为requierd-加入到当前事务支持当前事务的requierd 有就加入没有就创建新事务常用于子方法为修改事务supports没有当前事务就以非事务执行常用于子方法为只读事务mandatory: 使用当前事务 没有当前事务就抛异常nested如果有当前事务则以嵌套事务执行。如果没有当前事务则创建新事务不支持当前事务的required_new: 新建一个事务当前事务挂起not_supported: 以非事务方式执行操作当前事务挂起never 以非事务方式执行如存在当前事务则抛出异常补充在 Spring 中一个事务方法A通过 this 调用同类中的非事务方法B时非事务方法会加入事务原理通过ThreadLocal实现的 B方法顺用了 A 在 ThreadLocal 里的连接Service public class MyService { Autowired private MyService selfProxy; // 注入自身代理 Transactional public void transactionalMethod() { selfProxy.nonTransactionalMethod(); // 通过代理调用非事务方法加入事务 } public void nonTransactionalMethod() { // 此时会加入事务 } }事务失效的情况1.事务方法非public修饰由于Spring的事务是基于AOP的方式结合动态代理来实现的。因此事务方法一定要是public的这样才能便于被Spring做事务的代理和增强。2. 非事务方法调用事务方法相当于通过this.调用的普通方法而不是生成代理方法非事务方法调用事务方法没有走代理事务启动不了3. 事务方法的异常被捕获了spring感受不到事务就不会回滚了4.事务异常类型不对Spring的事务管理默认感知的异常类型是RuntimeException当事务方法内部抛出了一个IOException时不会被Spring捕获5.事务传播行为不对如果一个事务调用另一个事务如果被调用的事务的事务传播行为是REQUIRED_NEW进入子事务时会创建一个新的事务为子事务而不会与调用者事务合并当调用者事务发生异常时被调用事务不会回滚6.没有被Spring管理比较低级的错误比如没有加 Service注解
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2424002.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!