手写 Spring 事务、IOC、DI 和 MVC
Spring AOP 原理
什么是 AOP?
AOP 即面向切面编程,利用 AOP 可以对业务进行解耦,提高重用性,提高开发效率
应用场景:日志记录,性能统计,安全控制,事务处理,异常处理
AOP 底层实现原理是采用代理实现的
Spring 事务
基本特性:
- 原子性
- 隔离性
- 一致性
- 持久性
事务控制分类:
编程式事务:手动控制事务操作
声明式事务:通过 AOP 控制事务
编程式事务实现
使用编程事务实现手动事务
@Component
@Scope("prototype")
public class TransactionUtils {// 获取事务源@Autowiredprivate 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
@Aspect
public class TransactionAop {@Autowiredprivate 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
@Aspect
public class TransactionAop {@Autowiredprivate 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<String, Object> 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<Class<?>> classes = ClassUtil.getClasses(packageName);// 将所有标注ExtService注解的类加入到容器中findAnnotationByClasses(classes);}/*** 过滤标注ExtService注解的类** @param classes* @throws InstantiationException* @throws IllegalAccessException*/private void findAnnotationByClasses(List<Class<?>> 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 原理
执行流程:
用户请求 url 至前端控制器 DispatcherServlet
DispatcherServlet 调用处理器映射器 HandlerMapping
HandlerMapping 根据 url 找到具体的处理器生成处理器执行链,并将执行链返回给 DispatcherServlet
DispatcherServlet 根据处理器 Handler 获取处理器适配器 HandlerAdapter 执行
执行 Handler
返回 ModelAndView 返回给 DispatcherServlet
DispatcherServlet 将 ModelAnd view 传递给视图解析器 ViewResolver
ViewResolver 解析成具体 View
渲染视图
- 响应页面给用户
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和Objectprivate ConcurrentHashMap<String, Object> mvcBeans = new ConcurrentHashMap<>();// 关联url和控制器对象private ConcurrentHashMap<String, Object> mvcBeanUrl = new ConcurrentHashMap<>();// 关联url和methodNameprivate ConcurrentHashMap<String, String> mvcMethodUrl = new ConcurrentHashMap<>();/*** 初始化Servlet*/public void init() {try {List<Class<?>> classes = ClassUtil.getClasses("com.kernel.controller");findClassMVCBeans(classes);handlerMapping(mvcBeans);} catch (Exception e) {e.printStackTrace();}}/*** 关联url和控制器对象、url和methoName* @param mvcBeans*/private void handlerMapping(ConcurrentHashMap<String, Object> 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<Class<?>> 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);}}
}
转载于:https://blog.51cto.com/13559120/2388239
手写 Spring 事务、IOC、DI 和 MVC相关推荐
- JAVA项目代码手写吗_一个老程序员是如何手写Spring MVC的
见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十多 ...
- 记录一次阿里架构师全程手写Spring MVC
人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...
- 手写 Spring MVC
学习自<Spring 5核心原理与30个类手写实战>作者 Tom 老师 手写 Spring MVC 不多说,简历装 X 必备.不过练好还是需要求一定的思维能力. 一.整体思路 思路要熟练背 ...
- 手写Spring DI依赖注入,嘿,你的益达!
手写DI 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBean ...
- 十年java架构师分享:我是这样手写Spring的
人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...
- 05. 手写Spring核心框架
目录 05 手写Spring核心框架 Pt1 手写IoC/DI Pt1.1 流程设计 Pt1.2 基础配置 application.properties pom.xml web.xml Pt1.3 注 ...
- 从头开始实现一个小型spring框架——手写Spring之集成Tomcat服务器
手写Spring之集成Tomcat与Servlet 写在前面 一.Web服务模型及servlet 1.1 Web服务器 1.2 请求流程 二.实现 三.小结 写在前面 最近学习了一下spring的相关 ...
- 从0开始,手写MySQL事务
说在前面:从0开始,手写MySQL的学习价值 尼恩曾经指导过的一个7年经验小伙,凭借精通Mysql, 搞定月薪40K. 从0开始,手写一个MySQL的学习价值在于: 可以深入地理解MySQL的内部机制 ...
- 手把手教你手写Spring框架
手写spring准备工作: 新建一个maven工程: 架构 新建类: package com.spring;public class keweiqinApplicationContext {priva ...
最新文章
- UFLDL深度学习笔记 (三)无监督特征学习
- 使用netsh.exe命令配置TCP/IP
- 软件技术专业-就业提示(二、测试工程师)
- cassandra_Apache Cassandra和低延迟应用程序
- 现代程序设计 作业4
- html动态跟随鼠标效果,使用JS实现气泡跟随鼠标移动的动画效果
- 数据结构:列表(双向链表)的了解与示例
- The content of element type “resultMap“ must match “(constructor?,id*,result*,association*,collectio
- win10易升_白嫖性能!Win10系统开启硬件加速GPU调度计划提升显卡性能的方法
- 书店管理系统课程设计( sql server+python)
- 家里计算机网络布局图,图解八种家庭网络常规布局优缺点
- 24个希腊字母(符号) 附字母表
- layui的layer弹出层和form表单
- 按键精灵连接远程mysql_按键精灵手机版 如何连接远程网络数据库 进行读写操作...
- 已解决-MacBook pro/MacBook air上安装Windows10双系统教程
- 超实用的Mac风扇控制系统:Macs Fan Control Pro mac中文版
- android dfu升级
- 局域网访问电脑中VMware虚拟机
- 还在手动部署 Kubernetes 集群吗,是时候使用 Kubespray 完成自动化部署了!
- 零点起飞学Visual Basic pdf
热门文章
- 《资本说》如何帮助企业从“0”到“1”,看王波玩转投资攻略
- C程序演示产生僵死进程的过程
- 前后台使用ajax传list的时候,用value[] 获取值
- 【USACO】namenum
- LotusScript类的继承
- Linux下如何实现用户的集中管理(NIS服务器的高级配置)
- VS2005中删除最近打开的项目和文件的记录
- fegin调用为什么要序列化_全方位解析Java的序列化
- linux吃鸡游戏下载,沙雕糖豆人吃鸡战场
- 禅道设置bug模板_JPress v3.0 beta.2 发布,修复 bug 和完善产品细节