集装箱学习(两):动手模拟AOP
简单的说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
上文已经介绍模拟IoC实现,这篇文章来动手模拟AOP。
AOP简述
面向对象强调"一切皆是对象",是对真实世界的模拟。然而面向对象也并不是完美无缺的,它更注重于对象层次结构方面的东西。对于怎样更好的管理对象行为内部结构,还存在着些许不足。那么我们怎样使这个问题的得到更完美的解决呢?答案就是AOP。
AOP:Aspect-Oriented Programming。AOP是OOP的补充。是GOF的延续。
我们知道设计模式是对于面向对象设计中经验的总结。它孜孜不断追求的就是调用者与被调用者之间的解耦。
有了设计模式我们能够更有效的利用面向对象的特性,使得整个软件设计更加灵活、优雅。可是设计模式是基于面向对象的思想而形成的。很多其它的时候关注的是对象层次的东西,在解决对象行为内部问题方面却有些不足。
AOP的出现恰恰就是对面向对象思想做出了完美的补充。
说到AOP,我们就不得不来提一下软件的纵向和横向问题。从纵向结构来看就是我们软件系统的各个模块。它主要负责处理我们的核心业务(比如商品订购、购物车查看);而从横向结构来看,我们差点儿每一个系统又包括一些公共模块(比如权限、日志模块等)。
这些公共模块分布于我们各个核心业务之中(比如订购和查看商品明细的过程都须要检查用户权限、记录系统日志等)。这样一来不仅在开发过程中要处处关注公共模块的处理并且开发后维护起来也是十分麻烦。而有了AOP之后将应用程序中的商业逻辑同对其提供支持的通用服务进行分离,使得开发者能够很多其它的关注核心业务开发。
利用动态代理实现AOP
以下我们就以一个简单的样例来看一下AOP吧!
点击下载源代码:下载
比方说,我们如今要开发的一个应用里面有非常多的业务方法,可是,我们如今要对这种方法的运行做全面监控,或部分监控.或许我们就会在要一些方法运行前进行日志记录,我们写个样例看看我们最简单的解决方式
我们先写一个接口UserManager.java代码例如以下:
- publicinterface UserManager {
- publicvoid add(String userId, String userName);
- }
add方法里面仅仅是将简单的字符串作为參数,而不是实体。勿怪,解说的重点不是这里。我们去写个类实现UserManager接口
- publicclass UserManagerImp implements UserManager {
- @Override
- publicvoid add(String userId, String userName) {
- System.out.println("成功运行:UserManagerImpl.add()userId-->>" + userId);
- }
- }
如今我们要为这个业务方法加上日志记录的业务,我们在不改变原代码的情况下,我们会去怎么做呢?或许,你会去写一个类去实现UserManager接口,并依赖UserManagerImp这个类.代码例如以下:
- public class UserManagerProxyimplements UserManager{
- private UserManager userManager;
- public UserManagerProxy(UserManager userManager){
- this.userManager= userManager;
- }
- publicvoid addUser(String userId, String userName) {
- System.out.println("start-->>addUser()userId-->>" + userId);
- try{
- userManager.add(userId,userName);
- System.out.println("success-->>addUser()");
- }catch(Exceptione) {
- e.printStackTrace();
- System.out.println("error-->>addUser()");
- thrownew RuntimeException();
- }
- }
- }
从上面的代码我们能够看出,UserManager
对象是被UserManagerProxy这个所谓的代理所创建的.这样,假设我们以后要把日志记录的功能去掉.那我们仅仅要把得到userManager对象的的详细实现改为UserManager的就能够。
上面的代码 就是对AOP的最简单的实现,可是我们接下来想,假设我们要在非常多业务逻辑之前加日志的话。那么,我们是不是要去写非常多个UserManagerProxy这种类呢.事实上也是一种非常麻烦的事.在jdk1.3以后.jdk跟我们提供了一个API java.lang.reflect.InvocationHandler的类. 这个类能够让我们在JVM调用某个类的方法时动态的为些方法做些什么事.让我们把以上的代码改一下来看看效果.
我们一样的去写一个代理类.仅仅只是.让这个类去实现java.lang.reflect.InvocationHandler接口,代码例如以下:
- packagecom.java.drp.pattern;
- importjava.lang.reflect.InvocationHandler;
- importjava.lang.reflect.Method;
- importjava.lang.reflect.Proxy;
- publicclass LogHandler implements InvocationHandler {
- /**
- * 要处理的对象(也就是我们要在方法前后加上业务逻辑的对象)
- */
- privateObject targetObject;
- /**
- * 动态生成方法被处理过后的对象 (写法固定)
- * @param targetObject
- * @return
- */
- publicObject newProxyInstance(Object targetObject){
- this.targetObject= targetObject;
- returnProxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(), this);
- }
- /**
- *要处理的对象中的每一个方法会被此方法送去JVM调用,也就是说,要处理的对象的方法仅仅能通过此方法调用
- * 此方法是动态的,不是手动调用的
- */
- @Override
- publicObject invoke(Object proxy, Method method, Object[] args)
- throwsThrowable {
- System.out.println("将要运行的方法:"+ method.getName());
- System.out.print("将要运行的方法中的參数:");
- for(int i = 0; i < args.length; i++) {
- System.out.print(args[i]+ " ");
- }
- System.out.println();
- Objectresult = null;
- try{
- //运行原来的方法之前记录日志
- System.out.println(method.getName()+ "Method Start!");
- //JVM通过这条语句运行原来的方法(反射机制)
- result= method.invoke(targetObject, args);
- //运行原来的方法之后记录日志
- System.out.println(method.getName()+ "Method End!");
- }catch (Exception e) {
- e.printStackTrace();
- throwe;
- }
- //返回方法返回值给调用者
- returnresult;
- }
- }
该段代码的运行流程
执行结果:
将要运行的方法:add
将要运行的方法中的參数:001tch
addMethod Start!
加入用户成功
addMethod End!
从上面的样例我们看出,你的不论什么对象的方法运行之前要加上记录日志的操作都是能够的.LogHandler自己主动去代理运行被代理对象UserManagerImp中的每个方法,通过java.lang.reflect.InvocationHandler接口就把我们的代理对象和被代理对象解藕。
总结
上面简单的介绍了怎样用动态代理的方式实现AOP。主要是帮助大家理解动态代理AOP的大致思路。以便更好的使用AOP工具,而且把AOP应用到实际的面向对象开发。
版权声明:本文博主原创文章。博客,未经同意不得转载。
集装箱学习(两):动手模拟AOP的更多相关文章
- [原]容器学习(二):动手模拟AOP
简单来说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架.上文已经介绍模拟IoC实现,这篇文章来动手模拟AOP. AOP简述 面向对象强调"一切皆是对象" ...
- [原]容器学习(一):动手模拟spring的IoC
介绍 学习经典框架的实现原理以及设计模式在其实际中的运用,是非常有必要的,可以让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能,明白原理后,可以更好的使用它,进而为进行面向对象提供一 ...
- 容器学习(一):动手模拟spring的IoC
介绍 学习经典框架的实现原理以及设计模式在事实上际中的运用,是很有必要的,能够让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能.明确原理后,能够更好的使用它,进而为进行面向对象提供一 ...
- 动态代理学习(一)自己动手模拟JDK动态代理
最近一直在学习Spring的源码,Spring底层大量使用了动态代理.所以花一些时间对动态代理的知识做一下总结. 我们自己动手模拟一个动态代理 对JDK动态代理的源码进行分析 文章目录 场景: 思路: ...
- Spring 源码学习笔记10——Spring AOP
Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...
- Spring两种实现AOP的方式
有两种实现AOP的方式:xml配置文件的方式和注解的形式 我们知道通知Advice是指对拦截到的方法做什么事,可以细分为 前置通知:方法执行之前执行的行为. 后置通知:方法执行之后执行的行为. 异常通 ...
- python学习两月总结_汇总大牛们的思想_值得收藏
下面是我汇总的我学习两个月python(version:3.3.2)的所有笔记 你可以访问:http://www.python.org获取更多信息 你也可以访问:http://www.cnblogs. ...
- Java动态代理(三)——模拟AOP实现
以下案例模拟AOP实现 目录结构 接口PersonService package com.ljq.service; public interface PersonService { public vo ...
- 为U盘装备Ubuntu工作学习两不误
题记: 在上一篇文章中,我介绍了让Ubuntu 10.04完美支持Thinkpad小红点Trackpoint.看上去,显得有些不痛不痒,实际上有些同学会因为小红点中键不能正常使用,而放弃在Th ...
随机推荐
- 【剑指offer】Q40:数组中出现一次的数
书里面关于分类的推断有些麻烦,通过某一位为0为1来对数组元素进行分类.假如第3位为1.那么也就是元素x & 8 等于或不等于0,所以不是必需非的用第几位去推断. def once(array) ...
- CSS布局方案之圣杯布局
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- 【高精度练习+卡特兰数】【Uva1133】Buy the Ticket
Buy the Ticket Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) T ...
- 【枚举+数学】【HDU1271】整数对 难度:五颗星
整数对 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submis ...
- NET基础课--JIT编译器如何工作1
1..Net运行时调用JIT编译器,用来把由C#编译器生成的IL指令编译成机器代码.这一任务在应用程序的运行期间是分步进行的.JIT并不是在程序一开始就编译整个应用程序,取而代之的是,CLR是一个函数 ...
- MySQL整数类型说明 int(11) vs int(20)
整数类型后面跟的是显示的宽度.M指示最大显示宽度.最大有效显示宽度是255.显示宽度与存储大小或类型包含的值的范围无关. 实践出真知: mysql> create table test2 ( a ...
- 随学随记之java的数据类型
Java中的变量只有两种数据类型:基本数据类型(8种).引用数据类型 定义变量时内存中的状态变化:定义数据类型,开辟空间,存放数据. 8种基本数据类型的变量各占多大的内存空间,变量的取值范围 byte ...
- Respond.js让IE6-8支持CSS3 Media Query
原文地址:http://caibaojian.com/respondjs.html 使用方式 官方demo地址:http://scottjehl.github.com/Respond/test ...
- AjaxHelper的get和post请求的封装类
最近在学习ajax的时候发现不断的调用get和post请求时,代码重复很多,有的公司会用自带的封装的方法,这个可以直接调用ajax的方法,但是在运用的时候我们也应该学习它是怎么封装的和一些原理性的东西 ...
- [转]如何正确清理C盘
转自微软的Answers网站. 以下是推荐使用的方法,安全且不会误删有用的系统文件 1.尽量不要在C盘安装应用软件,在软件安装时,一般可以手动指定安装路径,您可以将软件指定安装到其他盘符. 在使用它们 ...