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 原理

执行流程:

  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和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相关推荐

  1. JAVA项目代码手写吗_一个老程序员是如何手写Spring MVC的

    见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十多 ...

  2. 记录一次阿里架构师全程手写Spring MVC

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  3. 手写 Spring MVC

    学习自<Spring 5核心原理与30个类手写实战>作者 Tom 老师 手写 Spring MVC 不多说,简历装 X 必备.不过练好还是需要求一定的思维能力. 一.整体思路 思路要熟练背 ...

  4. 手写Spring DI依赖注入,嘿,你的益达!

    手写DI 提前实例化单例Bean DI分析 DI的实现 构造参数依赖 一:定义分析 二:定义一个类BeanReference 三:BeanDefinition接口及其实现类 四:DefaultBean ...

  5. 十年java架构师分享:我是这样手写Spring的

    人见人爱的 Spring 已然不仅仅只是一个框架了.如今,Spring 已然成为了一个生态.但深入了解 Spring 的却寥寥无几.这里,我带大家一起来看看,我是如何手写 Spring 的.我将结合对 ...

  6. 05. 手写Spring核心框架

    目录 05 手写Spring核心框架 Pt1 手写IoC/DI Pt1.1 流程设计 Pt1.2 基础配置 application.properties pom.xml web.xml Pt1.3 注 ...

  7. 从头开始实现一个小型spring框架——手写Spring之集成Tomcat服务器

    手写Spring之集成Tomcat与Servlet 写在前面 一.Web服务模型及servlet 1.1 Web服务器 1.2 请求流程 二.实现 三.小结 写在前面 最近学习了一下spring的相关 ...

  8. 从0开始,手写MySQL事务

    说在前面:从0开始,手写MySQL的学习价值 尼恩曾经指导过的一个7年经验小伙,凭借精通Mysql, 搞定月薪40K. 从0开始,手写一个MySQL的学习价值在于: 可以深入地理解MySQL的内部机制 ...

  9. 手把手教你手写Spring框架

    手写spring准备工作: 新建一个maven工程: 架构 新建类: package com.spring;public class keweiqinApplicationContext {priva ...

最新文章

  1. UFLDL深度学习笔记 (三)无监督特征学习
  2. 使用netsh.exe命令配置TCP/IP
  3. 软件技术专业-就业提示(二、测试工程师)
  4. cassandra_Apache Cassandra和低延迟应用程序
  5. 现代程序设计 作业4
  6. html动态跟随鼠标效果,使用JS实现气泡跟随鼠标移动的动画效果
  7. 数据结构:列表(双向链表)的了解与示例
  8. The content of element type “resultMap“ must match “(constructor?,id*,result*,association*,collectio
  9. win10易升_白嫖性能!Win10系统开启硬件加速GPU调度计划提升显卡性能的方法
  10. 书店管理系统课程设计( sql server+python)
  11. 家里计算机网络布局图,图解八种家庭网络常规布局优缺点
  12. 24个希腊字母(符号) 附字母表
  13. layui的layer弹出层和form表单
  14. 按键精灵连接远程mysql_按键精灵手机版 如何连接远程网络数据库 进行读写操作...
  15. 已解决-MacBook pro/MacBook air上安装Windows10双系统教程
  16. 超实用的Mac风扇控制系统:Macs Fan Control Pro mac中文版
  17. android dfu升级
  18. 局域网访问电脑中VMware虚拟机
  19. 还在手动部署 Kubernetes 集群吗,是时候使用 Kubespray 完成自动化部署了!
  20. 零点起飞学Visual Basic pdf

热门文章

  1. 《资本说》如何帮助企业从“0”到“1”,看王波玩转投资攻略
  2. C程序演示产生僵死进程的过程
  3. 前后台使用ajax传list的时候,用value[] 获取值
  4. 【USACO】namenum
  5. LotusScript类的继承
  6. Linux下如何实现用户的集中管理(NIS服务器的高级配置)
  7. VS2005中删除最近打开的项目和文件的记录
  8. fegin调用为什么要序列化_全方位解析Java的序列化
  9. linux吃鸡游戏下载,沙雕糖豆人吃鸡战场
  10. 禅道设置bug模板_JPress v3.0 beta.2 发布,修复 bug 和完善产品细节