Spring AOP 理论
一、AOP
AOP 产生的背景
“存在即合理”,任何一种理论或技术的产生,必然有它的原因。了解它产生的背景、为了解决的问题有助于我们更好地把握AOP的概念。
软件开发一直在寻求一种高效开发、护展、维护的方式。从面向过程的开发实践中,前人将关注点抽象出来,对行为和属性进行聚合,形成了面向对象的开发思想,其在一定程度上影响了软件开发的过程。鉴于此,我们在开发的过程中会对软件开发进行抽象、分割成各个模块或对象。例如,我们会对API进行抽象成四个模块:Controller,Service,Gateway,Command.这很好地解决了业务级别的开发,但对于系统级别的开发我们很难聚焦。比如、对于每一个模块需要进行打日志、代码监控、异常处理。以打日志为例,我只能将日志代码嵌套在各个对象上,而无法关注日志本身,而这种现象又偏离了OOP思想。
至于AOP的确切的概念,我不希望给出抽象复杂的表述,只需要了解其作用即可。
二、AOP的技术实现Proxy
AOP仅仅是一种思想,那为了让这种思想发光,必然脱离语言本身的技术支持,Java在实现该技术时就是采用的代理Proxy,那我们就去了解一下,如何通过代理实现面向切面
1.静态代理
就像我们去买二手房要经过中介一样,房主将房源委托给中介,中介将房源推荐给买方。中间的任何手续的承办都由中介来处理,不需要我们和房主直接打交道。无论对买方还是卖房都都省了很多事情,但同时也要付出代价,对于买房当然是中介费,对于代码的话就是性能。下面我们来介绍实现AOP的三种代理方式。
下面我就以买房的过程中需要打日志为例介绍三种代理方式
静态和动态是由代理产生的时间段来决定的。静态代理产生于代码编译阶段,即一旦代码运行就不可变了。下面我们来看一个例子
public interface IPerson {
public void doSomething();
}
public class Person implements IPerson {
public void doSomething(){
System.out.println("I want wo sell this house");
}
}
public class PersonProxy {
private IPerson iPerson;
private final static Logger logger = LoggerFactory.getLogger(PersonProxy.class);
public PersonProxy(IPerson iPerson) {
this.iPerson = iPerson;
}
public void doSomething() {
logger.info("Before Proxy");
iPerson.doSomething();
logger.info("After Proxy");
}
public static void main(String[] args) {
PersonProxy personProxy = new PersonProxy(new Person());
personProxy.doSomething();
}
}
通过代理类我们实现了将日志代码集成到了目标类,但从上面我们可以看出它具有很大的局限性:需要固定的类编写接口(或许还可以接受,毕竟有提倡面向接口编程),需要实现接口的每一个函数(不可接受),同样会造成代码的大量重复,将会使代码更加混乱。
2.动态代理
那能否通过实现一次代码即可将logger织入到所有函数中呢,答案当然是可以的,此时就要用到java中的反射机制
public class PersonProxy implements InvocationHandler{
private Object delegate;
private final Logger logger = LoggerFactory.getLogger(this.getClass();
public Object bind(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
logger.info("Before Proxy");
result = method.invoke(delegate, args);
logger.info("After Proxy");
} catch (Exception e) {
throw e;
}
return result;
}
public static void main(String[] args) {
PersonProxy personProxy = new PersonProxy();
IPerson iperson = (IPerson) personProxy.bind(new Person());
iperson.doSomething();
}
}
它的好处理时可以为我们生成任何一个接口的代理类,并将需要增强的方法织入到任意目标函数。但它仍然具有一个局限性,就是只有实现了接口的类,才能为其实现代理。
3.CGLIB
CGLIB解决了动态代理的难题,它通过生成目标类子类的方式来实现来实现代理,而不是接口,规避了接口的局限性。
CGLIB是一个强大的高性能代码生成包(生成原理还没研究过),其在运行时期(非编译时期)生成被 代理对象的子类,并重写了被代理对象的所有方法,从而作为代理对象。
public class PersonProxy implements MethodInterceptor {
private Object delegate;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
logger.info("Before Proxy");
Object result = methodProxy.invokeSuper(method, args);
logger.info("After Proxy");
return result;
}
public static Person getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Person.class);
enhancer.setCallback(new PersonProxy());
return (Person) enhancer.create();
}
}
当然CGLIB也具有局限性,对于无法生成子类的类(final类),肯定是没有办法生成代理子类的。
以上就是三种代理的实现方式,但千成别被迷惑了,在Spring AOP中这些东西已经被封装了,不需要我们自己实现。要不然得累死,但了解AOP的实现原理(即基于代理)还是很有必要的。
五、最佳实践
那什么时候来使用AOP呢?我就私自定义一下:当一个功能和对象本身没有必段关系,重复出现在多个模块时,就应该用AOP来解耦。
有人总结了一下使用情景(参考, 是否认同自己决定):
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务
5.1 日志
看了很多资料都是用日志做AOP的例子,其实这个并不太好,因为AOP很难完全实现log的行为,但对于某一类型的日志处理还是有用的。
例如:对Command的异常进行统一处理,对Controller层的请求进行打日志
请参考日志:https://github.com/ameizi/DevArticles/issues/152
5.2 代码性能测试
利用PerformanceMonitorInterceptor来协助应用性能优化, spring自带的
http://www.cnblogs.com/f1194361820/p/6626077.html
当然还有这个JamonPerformanceMonitorInterceptor
作者:oneWeekOneTopic
链接:https://www.jianshu.com/p/7fa3e6ebf0c1
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
Spring AOP 理论的更多相关文章
- [转]彻底征服 Spring AOP 之 理论篇
基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹的是, 这些概念经过了中文翻译后, 变得面目全非, 相同的一个术语, 在不同的翻译下, ...
- 彻底征服 Spring AOP 之 理论篇
基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹的是, 这些概念经过了中文翻译后, 变得面目全非, 相同的一个术语, 在不同的翻译下, ...
- Spring AOP详解
一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...
- [转]彻底征服 Spring AOP 之 实战篇
Spring AOP 实战 看了上面这么多的理论知识, 不知道大家有没有觉得枯燥哈. 不过不要急, 俗话说理论是实践的基础, 对 Spring AOP 有了基本的理论认识后, 我们来看一下下面几个具体 ...
- 161110、彻底征服 Spring AOP 之 实战篇
Spring AOP 实战 看了上面这么多的理论知识, 不知道大家有没有觉得枯燥哈. 不过不要急, 俗话说理论是实践的基础, 对 Spring AOP 有了基本的理论认识后, 我们来看一下下面几个具体 ...
- 彻底征服 Spring AOP 之 实战篇
Spring AOP 实战 看了上面这么多的理论知识, 不知道大家有没有觉得枯燥哈. 不过不要急, 俗话说理论是实践的基础, 对 Spring AOP 有了基本的理论认识后, 我们来看一下下面几个 ...
- 关于 Spring AOP (AspectJ) 该知晓的一切
关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...
- springmvc 运行原理 Spring ioc的实现原理 Mybatis工作流程 spring AOP实现原理
SpringMVC的工作原理图: SpringMVC流程 . 用户发送请求至前端控制器DispatcherServlet. . DispatcherServlet收到请求调用HandlerMappin ...
- 【转】Java Spring AOP详解
一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...
随机推荐
- tp5 中使用自定义扩展类和函数
如果是要引用其它控制器里定义的方法参考:https://www.cnblogs.com/efyefy/p/8796014.html 如果在extend定义的类和函数默认是在全局命名空间下的 new \ ...
- Eclipse自动生成方法注释 快捷键
自动生成方法的注释格式,例如 /*** @param str* @return* @throws ParseException*/ 快捷键是 ALT + SHIFT + J,将光标放在方法名上,按快捷 ...
- Python3 tkinter基础 Listbox delete 删除单个、所有元素
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- 【MVC】Spring MVC常用配置
一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 <!--conf ...
- CF776B Sherlock and his girlfriend
题目地址 题目链接 题解 这题很有意思啊qwq.本来是写算出每个数的质约数的,然后写到一半发现,质约数互相不影响,有质约数的数肯定是合数. 所以合数染一种色,质数染一种色就好 #include < ...
- p4168 [Violet]蒲公英(分块)
区间众数的重题 和数列分块入门9双倍经验还是挺好的 然后开O2水过 好像有不带log的写法啊 之后在补就是咕咕咕 // luogu-judger-enable-o2 #include <cstd ...
- jquery及jquery常用选择器使用
本文为博主原创,未经允许不得转载: 1.jquery强大之处: 容易上手,强大的选择器,解决浏览器的兼容 完善的时间机制,出色的ajax封装,丰富的ui 2.jquery是一个javas ...
- Wijmo 2017路线图
2016年是Wijmo团队发展和增长的另一个富有成效的一年.回顾我们2016年的路线图,您可以看到我们交付了我们承诺的一切.让我们回顾一下2016年的亮点: 我们第一个全面支持Angular 2 互操 ...
- C语言调用Python 混合编程
导语 Python有很多库,Qt用来编写界面,自然产生C++调用Python的需求.一路摸索,充满艰辛 添加头文件搜索路径,导入静态库 我的python头文件搜索路径:C:\Python27amd64 ...
- 小文笔记 - phantomjs
小文笔记 - phantomjs 视频推荐: http://www.intalesson.com/compedium/phantom 2017-05-13 第一节:安装 Windows安装: 下载解压 ...