spring 理解Spring AOP 一个简单的约定游戏
约定规则
package com.ssm.chapter11.game; public interface Interceptor { public void before(Object obj); public void after(Object obj); public void afterReturning(Object obj); public void afterThrowing(Object obj); }
这里是一个拦截接口,可以对它创建实现类。如果使用过Spring AOP,你就会发现笔者的定义和Spring AOP定义的消息是如此相近。
代码清单:ProxyBeanFactory的getBean方法
package com.ssm.chapter11.game; public class ProxyBeanFactory {
public static <T> T getBean(T obj, Interceptor interceptor) {
return (T) ProxyBeanUtil.getBean(obj, interceptor);
}
}
具体类ProxyBeanUtil的getBean方法的逻辑不需要去理会,因为这是笔者需要去完成的内容。但是作为读者,你要知道当使用了这个方法后,存在如下约定
当一个对象通过ProxyBeanFactory的getBean方法定义后,拥有这样的约定。
(1)Bean必须是一个实现了某一个接口的对象。
(2)最先会执行拦截器的before方法。
(3)其次执行Bean的方法(通过反射的形式)。
(4)执行Bean方法时,无论是否产生异常,都会执行after方法。
(5)执行Bean方法时,如果不产生异常,则执行afterReturning方法;如果产生异常,则执行afterThrowing方法。
这个约定实际已经十分接近Spring AOP对我们的约定,所以这个约定十分重要,其流程如图所示。
读者的代码
代码清单:RoleService接口
package com.ssm.chapter11.game.service; import com.ssm.chapter11.game.pojo.Role; public interface RoleService {
public void printRole(Role role);
}
代码清单:RoleServiceImpl
package com.ssm.chapter11.game.service.impl; import com.ssm.chapter11.game.pojo.Role;
import com.ssm.chapter11.game.service.RoleService; public class RoleServiceImpl implements RoleService { // @Override
public void printRole(Role role) {
System.out.println("{id =" + role.getId() + ", roleName=" + role.getRoleName() + ", note=" + role.getNote() + "}");
} }
代码清单:角色拦截器RoleInterceptor
package com.ssm.chapter11.game.interceptor; import com.ssm.chapter11.game.Interceptor; public class RoleInterceptor implements Interceptor { // @Override
public void before(Object obj) {
System.out.println("--before-准备打印角色信息");
} // @Override
public void after(Object obj) {
System.out.println("-after-已经完成角色信息的打印处理");
} // @Override
public void afterReturning(Object obj) {
System.out.println("-afterReturning-刚刚完成打印功能,一切正常。");
} // @Override
public void afterThrowing(Object obj) {
System.out.println("-afterThrowing-打印功能执行异常了,查看一下角色对象为空了吗?");
} }
它编写了图中描述流程的各个方法,这个时候你可以清楚地知道代码将按照流程图的流程执行。注意,你并不需要知道笔者如何实现,你只需要知道我们之间的约定即可
代码清单:测试约定流程
package com.ssm.chapter11.game.main; import com.ssm.chapter11.game.Interceptor;
import com.ssm.chapter11.game.ProxyBeanFactory;
import com.ssm.chapter11.game.interceptor.RoleInterceptor; import com.ssm.chapter11.game.pojo.Role;
import com.ssm.chapter11.game.service.RoleService;
import com.ssm.chapter11.game.service.impl.RoleServiceImpl; public class GameMain { public static void main(String[] args) {
RoleService roleService = new RoleServiceImpl();
Interceptor interceptor = new RoleInterceptor();
RoleService proxy = ProxyBeanFactory.getBean(roleService, interceptor);
Role role = new Role(1L, "role_name_1", "role_note_1");
proxy.printRole(role);
System.out.println("############## 测试 afterthrowing方法###############");
role = null;
proxy.printRole(role);
} }
笔者的代码
下面展示通过JDK动态代理实现上述流程的代码,如代码清单所示。
代码清单:使用动态代理实现流程
package com.ssm.chapter11.game; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; class ProxyBeanUtil implements InvocationHandler { //被代理对象
private Object obj;
// 拦截器
private Interceptor interceptor = null; /**
* 获取动态代理对象.
*
* @param obj 被代理对象
* @param interceptor 拦截器
* @param aroundFlag 是否启用around方法
* @return 动态代理对象
*/
public static Object getBean(Object obj, Interceptor interceptor) {
//使用当前类,作为代理方法,此时被代理对象执行方法的时候,会进入当前类的invoke方法里
ProxyBeanUtil _this = new ProxyBeanUtil();
//保存被代理对象
_this.obj = obj;
//保存拦截器
_this.interceptor = interceptor;
//生成代理对象,并绑定代理方法
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), _this);
} /**
* 代理方法
*
* @param proxy 代理对象
* @param method 当前调度方法
* @param args 参数
* @return 方法返回
* @throws Throwable 异常
*/
// @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object retObj = null;
//是否产生异常
boolean exceptionFlag = false;
//before方法
interceptor.before(obj);
try {
//反射原有方法
retObj = method.invoke(obj, args);
} catch (Exception ex) {
exceptionFlag = true;
} finally {
//after方法
interceptor.after(obj);
}
if (exceptionFlag) {
//afterThrowing方法
interceptor.afterThrowing(obj);
} else {
//afterReturning方法
interceptor.afterReturning(obj);
}
return retObj;
}
}
上面的代码使用了动态代理,由于这段代码的重要性,这里有必要讨论其实现过程。
首先,通过getBean方法保存了被代理对象、拦截器(inter-ceptor)和参数(args),为之后的调用奠定了基础。然后,生成了JDK动态代理对象(proxy),同时绑定了ProxyBeanUtil的一个实例作为其代理类,这样当代理对象调用方法的时候,就会进入到ProxyBeanUtil实例的invoke方法中,于是焦点又到了invoke方法上。
在invoke方法中,笔者将拦截器的方法按照流程图实现了一遍,其中设置了异常标志(exceptionFlag),通过这个标志就能判断反射原有对象方法的时候是否发生了异常,这就是读者的代码能够按照流程打印的原因。但是,由于动态代理和反射的代码会比较抽象,更多的时候大部分的框架只会告诉你流程图和具体的流程方法的配置,就像笔者之前只是给出约定而已,相信有心的读者已经明白这句话的意思了,这就是说Spring框架也是这样做的。
spring 理解Spring AOP 一个简单的约定游戏的更多相关文章
- spring boot: @Entity @Repository一个简单的数据读存储读取
spring boot: @Entity @Repository一个简单的数据读存储读取 创建了一个实体类. 如何持久化呢?1.使用@Entity进行实体类的持久化操作,当JPA检测到我们的实体类当中 ...
- 无聊的人用JS实现了一个简单的打地鼠游戏
直入正题,用JS实现一个简单的打地鼠游戏 因为功能比较简单就直接裸奔JS了,先看看效果图,或者 在线玩玩 吧 如果点击颜色比较深的那个(俗称坏老鼠),将扣分50:如果点击颜色比较浅的那个(俗称好老鼠) ...
- Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏
Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...
- 【模块化编程】理解requireJS-实现一个简单的模块加载器
在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题: ① 解决单文件变量命名冲突问题 ② 解决前端多人协作问题 ③ 解决文件依赖问题 ④ 按需加载(这个说法其实很假了) ⑤ ..... ...
- 理解与模拟一个简单web服务器
先简单说下几个概念,根据自己的理解,不正确请见谅. web服务器 首先要知道什么是web服务器,简单说web服务器就是可以使用HTTP传输协议与客户端进行通信的服务器.最初的web服务器只能用来处理静 ...
- 通过创建一个简单的骰子游戏来探究 Python
在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏.这次,我将展示如何使用 Python 模块 Pygame 来创建一个图形化游戏.它将需要几篇文章才 ...
- Spring IOC DI AOP 的简单理解及应用
Spring两大特性:IOC 和AOP.IOC 控制反转,AOP 面向切面编程 spring 核心容器的主要组件时Bean工厂(BeanFactory) ,Bean 工厂使用控制反转模式来降低程序代码 ...
- spring boot:创建一个简单的web(maven web project)
1.新建一个maven web project; 2.在pom.xml文件中添加相应的依赖包: 3.新建一个HelloController请求控制类: 4.编写index.jsp页面: 5.编写启动类 ...
- Spring学习笔记--声明一个简单的Bean
spring依赖的maven dependencyhttp://mvnrepository.com/artifact/org.springframework 在pom.xml中添加如下依赖: < ...
随机推荐
- LA 3704细胞自动机——循环矩阵&&矩阵快速幂
题目 一个细胞自动机包含 $n$ 个格子,每个格子的取值为 $0 \sim m-1$.给定距离 $d$,则每次操作是将每个格子的值变为到它的距离不超过 $d$ 的所有格子的在操作之前的值的和除以 $m ...
- Coins in a Line III
Description There are n coins in a line, and value of i-th coin is values[i]. Two players take turns ...
- Springboot如何优雅的解决ajax+自定义headers的跨域请求[转]
1.什么是跨域 由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.),凡是发 ...
- C# 异常 抛异常的时候 同时抛出 传入的参数
abp的审计日志都把这些功能实现了 可以借鉴 抛异常的时候 同时抛出 传入的参数 大致这样实现,aop,方法执行先,先把参数写入到栈中,抛异常时,栈中自然就有此时的参数了. 可用于重现该异常. 获取把 ...
- Nginx和php-fpm的启用和停用脚本
#!/bin/bash #停止php-fpm sudo php -v ps -ef | grep php-fpm | sed '$d' echo "..................... ...
- manjaro (arch) 安装搜狗输入法
本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/sogou_input_install_in_arch_manja ...
- AspNetCore3.0 和 JWT
添加NuGet引用 IdentityModel Microsoft.AspNetCore.Authorization.JwtBearer 在appsettings.json中添加JwtBearer配置 ...
- [树链剖分]BZOJ3589动态树
题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你求出几条树枝上 ...
- JDK提供的原子类原理与使用
原子更新基本类型 原子更新数组 原子更新抽象类型 原子更新字段 原子更新基本类型: package com.roocon.thread.t8; import java.util.concurrent. ...
- SyntaxError: Non-ASCII character 'æ' in file csdn.py on line 7, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
错误信息: SyntaxError: Non-ASCII character , but no encoding declared; see http://python.org/dev/peps/pe ...