spring手动回滚事务_手写 Spring 事务、IOC、DI 和 MVC
发布日期:2021-10-30 18:55:25 浏览次数:6 分类:技术文章

本文共 11963 字,大约阅读时间需要 39 分钟。

Spring AOP 原理

什么是 AOP?

AOP 即面向切面编程,利用 AOP 可以对业务进行解耦,提高重用性,提高开发效率

应用场景:日志记录,性能统计,安全控制,事务处理,异常处理

AOP 底层实现原理是采用代理实现的

Spring 事务

基本特性:

  • 原子性
  • 隔离性
  • 一致性
  • 持久性

事务控制分类:

编程式事务:手动控制事务操作

声明式事务:通过 AOP 控制事务

编程式事务实现

使用编程事务实现手动事务

@Component@Scope("prototype")public class TransactionUtils { // 获取事务源 @Autowired private DataSourceTransactionManager dataSourceTransactionManager; // 开启事务 public TransactionStatus begin() { TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute()); return transaction; } // 提交事务 public void commit(TransactionStatus transaction) { dataSourceTransactionManager.commit(transaction); } // 回滚事务 public void rollback(TransactionStatus transaction) { dataSourceTransactionManager.rollback(transaction); }}复制代码

AOP技术封装手动事务

@Component@Aspectpublic class TransactionAop { @Autowired private TransactionUtils transactionUtils; @Around("execution(* com.kernel.service.UserService.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) { try { // 调用方法之前执行 System.out.println("开启事务"); TransactionStatus transactionStatus = transactionUtils.begin(); proceedingJoinPoint.proceed(); System.out.println("提交事务"); transactionUtils.commit(transactionStatus); } catch (Throwable throwable) { System.out.println("回滚事务"); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }}复制代码

事务注意事项:

一定不要将代码通过 try 包裹起来,如果程序发生异常,事务接收不到异常,就会认为程序正常执行,就不会进行回滚,必须手动回滚

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

声明式事务

通过 AOP 实现,对方法进行拦截,在方法执行之前开启事务,结束后提交事务,发生异常回滚事务

自定义事务注解

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface ExtTransaction {}复制代码

事务实现

@Component@Aspectpublic class TransactionAop { @Autowired private TransactionUtils transactionUtils; private TransactionStatus transactionStatus = null; /** * AOP实现事务管理 * * @param proceedingJoinPoint 切面通知对象 */ @Around("execution(* com.kernel.service.*.* (..))") public void around(ProceedingJoinPoint proceedingJoinPoint) { try { // 获取注解对象 ExtTransaction extTransaction = getExtTransaction(proceedingJoinPoint); begin(extTransaction); // 执行目标方法 proceedingJoinPoint.proceed(); // 提交事务 commit(); } catch (Throwable throwable) { transactionUtils.rollback(); } } /** * 获取注解对象 * * @param proceedingJoinPoint 切面通知对象 * @return 注解对象 * @throws NoSuchMethodException */ public ExtTransaction getExtTransaction(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException { // 获取方法名称 String method = proceedingJoinPoint.getSignature().getName(); // 获取目标方法 Class> classTarget = proceedingJoinPoint.getTarget().getClass(); // 获取目标对象类型 Class[] parameterTypes = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes(); // 获取目标对象方法 Method objMethod = classTarget.getMethod(method, parameterTypes); // 获取注解 ExtTransaction declaredAnnotation = objMethod.getDeclaredAnnotation(ExtTransaction.class); return declaredAnnotation; } /** * 开启事务 * @param extTransaction 注解对象 * @return 事务对象 */ TransactionStatus begin(ExtTransaction extTransaction) { if (extTransaction != null) transactionStatus = transactionUtils.begin(); return transactionStatus; } /** * 提交事务 */ void commit() { if (transactionStatus != null) transactionUtils.commit(transactionStatus); } /** * 回滚事务 */ void rollback() { transactionUtils.rollback(); }}复制代码

Spring事物传播行为

  • PROPAGATION_REQUIRED:如果当前有事务,就用当前事务,如果当前没有事务,就新建一个事务
  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行
  • PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常
  • PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起
  • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常

什么是 Spring IOC?

Spring IOC 指的是控制反转,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖,交由Spring来管理这些,实现解耦

手写 Spring IOC

实现步骤:

扫包

将标注了注解的类,通过反射创建实例并添加的 bean 容器中

当用户向容器要 bean 时,通过 beanId 在 bean 容器中查找并返回实例

package com.kernel.ext;import com.kernel.ext.annotation.ExtAutoWired;import com.kernel.ext.annotation.ExtService;import com.kernel.utils.ClassUtil;import org.apache.commons.lang.StringUtils;import java.lang.reflect.Field;import java.util.List;import java.util.concurrent.ConcurrentHashMap;/** * IOC 注解版本 */public class ExtClassPathXmlApplicationContext { // 包名 private String packageName; // bean容器 private ConcurrentHashMap beans = null; /** * 构造函数 * * @param packageName 包名 * @throws InstantiationException * @throws IllegalAccessException */ public ExtClassPathXmlApplicationContext(String packageName) throws InstantiationException, IllegalAccessException { this.packageName = packageName; init(); } /** * 初始化对象 * * @throws IllegalAccessException * @throws InstantiationException */ private void init() throws IllegalAccessException, InstantiationException { // 遍历所有类 List> classes = ClassUtil.getClasses(packageName); // 将所有标注ExtService注解的类加入到容器中 findAnnotationByClasses(classes); } /** * 过滤标注ExtService注解的类 * * @param classes * @throws InstantiationException * @throws IllegalAccessException */ private void findAnnotationByClasses(List> classes) throws InstantiationException, IllegalAccessException { for (Class classInfo : classes) { ExtService extService = (ExtService) classInfo.getAnnotation(ExtService.class); if (extService != null) { Object newInstance = newInstance(classInfo); beans.put(toLowerCaseFirstOne(classInfo.getSimpleName()), newInstance); } } } /** * 通过反射构建对象 * * @param classInfo * @return * @throws InstantiationException * @throws IllegalAccessException */ private Object newInstance(Class classInfo) throws InstantiationException, IllegalAccessException { return classInfo.getClass().newInstance(); } /** * 通过beanId查找对应的实例 * * @param beanId * @return */ public Object getBean(String beanId) throws IllegalAccessException { Object object = null; if (StringUtils.isEmpty(beanId)) return null; for (String id : beans.keySet()) if (beanId.equals(id)) { object = beans.get(beanId); attrAssign(object); break; } return object; } /** * 依赖注入 */ void attrAssign(Object object) throws IllegalAccessException { Class> aClass = object.getClass(); Field[] declaredFields = aClass.getDeclaredFields(); for (Field field : declaredFields) { ExtAutoWired extAutoWired = field.getAnnotation(ExtAutoWired.class); if (extAutoWired != null) { field.setAccessible(true); Object bean = getBean(field.getName()); field.set(field.getName(), object); } } } /** * 首字母变小写 * * @param s * @return */ public static String toLowerCaseFirstOne(String s) { if (Character.isLowerCase(s.charAt(0))) return s; else { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(Character.toLowerCase(s.charAt(0))); stringBuffer.append(s.substring(1)); return stringBuffer.toString(); } }}复制代码

Spring MVC 原理

bba1a7d41af17d4d05f899632323d249.png

执行流程:

  1. 用户请求 url 至前端控制器 DispatcherServlet
  2. DispatcherServlet 调用处理器映射器 HandlerMapping
  3. HandlerMapping 根据 url 找到具体的处理器生成处理器执行链,并将执行链返回给 DispatcherServlet
  4. DispatcherServlet 根据处理器 Handler 获取处理器适配器 HandlerAdapter 执行
  5. 执行 Handler
  6. 返回 ModelAndView 返回给 DispatcherServlet
  7. DispatcherServlet 将 ModelAnd view 传递给视图解析器 ViewResolver
  8. ViewResolver 解析成具体 View
  9. 渲染视图
  10. 响应页面给用户

Servlet 生命周期

init:在 Servlet 生命周期中,该方法仅执行一次,它是在将服务器装入 Servlet 时执行的,负责初始化 Servlet 对象,Servlet 是单例多线程的

service:负责响应请求,每当一个客户请求一个 HttpServlet 对象,该对象的 Service 方法就要被调用,传递一个 ServletRequest 和 ServletResponse 对象

destroy:在服务器停止卸载 Servlet 时调用

手写 Spring MVC

实现步骤:

创建一个 ExtDispatcherServlet 继承 HttpServlet

扫包

将标注了 @ExtController 注解的类,通过反射创建对象添加到容器中,将 beanId 和控制器关联

将标注了 @ExtRequestMapping 注解的类,将请求url 和控制器对象关联,将 url 和 方法关联

当用户请求 url 时,查找和 url 对应的对象,然后查找和 url 对应的方法,执行方法,解析并渲染

package com.kernel.ext.servlet;import com.kernel.controller.ExtIndexController;import com.kernel.ext.annotation.ExtController;import com.kernel.ext.annotation.ExtRequestMapping;import com.kernel.utils.ClassUtil;import org.apache.commons.lang.StringUtils;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.List;import java.util.concurrent.ConcurrentHashMap;/** * 手写SpringMVC */public class ExtDispatcherServlet extends HttpServlet { // 关联beanId和Object private ConcurrentHashMap mvcBeans = new ConcurrentHashMap<>(); // 关联url和控制器对象 private ConcurrentHashMap mvcBeanUrl = new ConcurrentHashMap<>(); // 关联url和methodName private ConcurrentHashMap mvcMethodUrl = new ConcurrentHashMap<>(); /** * 初始化Servlet */ public void init() { try { List> classes = ClassUtil.getClasses("com.kernel.controller"); findClassMVCBeans(classes); handlerMapping(mvcBeans); } catch (Exception e) { e.printStackTrace(); } } /** * 关联url和控制器对象、url和methoName * @param mvcBeans */ private void handlerMapping(ConcurrentHashMap mvcBeans) { for (Object classInfo : mvcBeans.values()) { ExtRequestMapping extCla***equestMapping = classInfo.getClass().getDeclaredAnnotation(ExtRequestMapping.class); String requestBaseUrl = null; if (extCla***equestMapping != null) { requestBaseUrl = extCla***equestMapping.value(); } Method[] methods = classInfo.getClass().getDeclaredMethods(); for (Method method : methods) { ExtRequestMapping extMthodRequestMapping = method.getDeclaredAnnotation(ExtRequestMapping.class); if (extCla***equestMapping != null){ String httpRequestUrl = extMthodRequestMapping.value(); mvcBeanUrl.put(requestBaseUrl + httpRequestUrl, classInfo); mvcMethodUrl.put(requestBaseUrl + httpRequestUrl, method.getName()); } } } } /** * 将所有控制器添加到mvcBeans中 * @param classes 包内所有类 * @throws InstantiationException * @throws IllegalAccessException * @throws ClassNotFoundException */ private void findClassMVCBeans(List> classes) throws InstantiationException, IllegalAccessException, ClassNotFoundException { for (Class classInfo : classes) { ExtController extController = (ExtController) classInfo.getDeclaredAnnotation(ExtController.class); if (extController != null){ mvcBeans.put(classInfo.getName(), ClassUtil.newInstance(classInfo)); } } } /** * get请求 * @param req * @param resp * @throws IOException * @throws ServletException */ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { try { doPost(req, resp); } catch (Exception e) { e.printStackTrace(); } } /** * post请求 * @param req * @param resp */ protected void doPost(HttpServletRequest req, HttpServletResponse resp) { try { doDispatch(req, resp); } catch (Exception e) { e.printStackTrace(); } } /** * 路由分发 * @param req * @param resp * @throws Exception */ private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception { String requestUrl = req.getServletPath(); Object object = mvcBeanUrl.get(requestUrl); if (object == null) object = ExtIndexController.class.newInstance(); String methodName = mvcMethodUrl.get(requestUrl); if (StringUtils.isEmpty(methodName)) methodName = "error"; Class> classInfo = object.getClass(); String resultPage = (String) methodInvoke(classInfo, object, methodName); viewDisplay(resultPage, req, resp); } /** * 视图渲染 * @param resultPage * @param req * @param resp * @throws ServletException * @throws IOException */ private void viewDisplay(String resultPage, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String suffix = ".jsp"; String prefix = "/"; req.getRequestDispatcher(prefix + resultPage + suffix).forward(req, resp); } /** * 反射执行方法 * @param classInfo 控制器 * @param object 控制器对象 * @param methodName 方法名称 * @return * @throws InvocationTargetException * @throws IllegalAccessException * @throws NoSuchMethodException */ private Object methodInvoke(Class> classInfo, Object object, String methodName) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { Method method = null; try { method = classInfo.getDeclaredMethod(methodName); } catch (NoSuchMethodException e) { e.printStackTrace(); } finally { return method.invoke(object); } }}复制代码

对文章感兴趣的朋友可以关注小编,以后会有更多的技术文章输出

对Java技术感兴趣的同学可以关注小编并私信“Java”

可以免费获取一套小编自己收集的学习资料。主要包含了分布式,微服务,源码解析,高并发以及性能优化等等相关内容。

把握当下才能走出更好的明天!

转载地址:https://blog.csdn.net/weixin_39849239/article/details/111347430 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:搜索不包含关键词_百度关键词推广有什么匹配方式
下一篇:华为摄像头搜索软件_涨知识!原来华为手机摄像头还有这些高级玩法,学会轻松提高工作效率...

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月13日 02时23分07秒