OOP的完美点缀—AOP之SpringAOP实现原理

前言

OOP与AOP

OOP(Object Oriented Programming,面向对象编程),通过封装、继承将程序抽象为各个层次的对象,进而组合为模块或者程序,达到了软件工程中的重用性、灵活性、扩展性。程序的运行笼统地可以看为各层次对象之间的相互调用。
AOP(Aspect Oriented Programming,面向切面编程),将程序运行过程分解为一个个的切面,对特定的切面(某个步骤或者阶段)进行提取,达到解耦各种不同逻辑代码。
OOP是在程序分块层面上进行考虑,而AOP则是在程序运行的切面上进行考虑。

可以将AOP理解为一种无损伤型的”切面”激光手术刀。OOP使属性和行为被封装为了一个严实、密不透风的对象。想要改变由对象保护着的方法,就可以通过该激光手术刀,既不损伤对象(即是,不破坏对象的封装),又不添加任何冗余的代码,实现对原对象的方法的增强处理。

不得不说,AOP实在是一种巧妙的编程思想!!!弥补了OOP中一些难以解决的问题。例如,
1. 类应该是纯净的,不应含有与本身无关的逻辑。如日志跟踪的逻辑代码。这样的类就可以更好地重用,更有效地被AOP的切入更多的业务逻辑, 举例代码如下:


  1. /*

  2. * 假如需要记录某只柯基狗的日常,

  3. * 我们总不能让它自己来记录吧??

  4. * 如 下面的注释了的方法

  5. * 看起来是不是非常怪异,一只狗狗自己给自己写日记

  6. */

  7. class dog{

  8. void run(){

  9. /*note.write("散步了");*/

  10. }



  11. void sleep(){

  12. /*note.write("又睡懒觉了");*/

  13. }

  14. }

2. OOP为不同类别的对象引入公共方法时,往往力不从心,造成大量的分散的重复代码,重用性真的很差,每次都要改动真的很麻烦。


  1. class dog{

  2. private Note note = new Note();



  3. void run(){

  4. note.write("散步了");

  5. }

  6. void sleep(){

  7. note.write("又睡懒觉了");

  8. }

  9. }

本文中”特定处理”指的日志记录、事务管理、异常处理等等之类的各种通用的业务逻辑

AOP实现原理

主要分为两大类:
是采用动态代理,对被代理对象和特定处理进行修饰和封装,得到代理对象,从使得被代理对象中不需切入任何的代码,如图:
简单的代理:实现不入侵原始对象而切入各种通用的业务逻辑(eg: 参数验证、日志记录方法等)


  1. interface Interface{

  2. void doSomething();

  3. }



  4. /*原始对象*/

  5. class RealObject implements Interface{

  6. @Override

  7. public void doSomething() {

  8. System.out.println("原始对象的行为");

  9. }

  10. }



  11. /*代理*/

  12. class SimplProxy implements Interface {

  13. private Interface proxied;



  14. public SimplProxy(Interface proxied){

  15. this.proxied = proxied;

  16. }



  17. public void doSomething(){

  18. System.out.println("处理一些通用的业务逻辑, 如参数校验等等");

  19. proxied.doSomething();

  20. }

  21. }



  22. /*调用者*/

  23. class Caller{

  24. public static void call(Interface iface){

  25. iface.doSomething();

  26. }



  27. public static void main(String[] args){

  28. call(new SimplProxy(new RealObject()));

  29. }

  30. }

  31. /*输出:*/

  32. 1.处理一些通用的业务逻辑, 如参数校验等等

  33. 2.原始对象的行为

  34. 就这样,一些通用的业务逻辑被代理简单地切入到了原始对象之前执行

是采用静态织入,如AspectJ,使用其特定的语法创建切面,在编译期间将切面织入代码中。又如,通过AspectJ编译出来的class文件与普通编译出来的有很大区别,这块没有了解,不再赘述。

AOP使用场景

权限控制、异常处理、缓存、事务管理、日志记录、数据校验等等

AOP基本概念

  • 切面(Aspect): 程序运行过程中的某个的步骤或者阶段
  • 连接点(Joinpoint): 程序运行过程中可执行特定处理(增强处理)的点, 如异常处理。而在SpringAOP中,方法调用是连接点。
  • Advice(通知、处理、增强处理): 在符合的连接点进行的特定处理 (增强处理)
  • 切入点(Pointcut): 可切入进行增强处理的连接点。AOP核心之一就是如何用表达式来定义符合的切入点。在Spring中,默认使用AspectJ的切入点语法。
    由于Spring AOP只支持以Spring Bean的方法调用来作为连接点, 所以在这里切入点的定义包括:
    • 切入点表达式, 来限制该能作用的范围大小,即是,能匹配哪些bean的方法
    • 命名切入点


  1. @Pointcut("execution(* com.xxx.xxx.service.*.* (..)) ") /*切入点*/

  2. public void pointCutExpress(){   /*命名切入点*/

  3. }

  4. /*常见的 切入点表达式语法 如下:*/

  5. execution(返回值类型 方法所属类.方法名 方法形参列表 抛出的异常声明)

  6. 例如:

  7. 上面第一个 * 指匹配所有返回值类型

  8. 第二个 * service包下的所有类

  9. 第三个 * 指各个类中的所有方法

  10. (..)中的 .. 指零个或者多个(任意数量)的参数

  • 目标对象: 被进行增强处理的对象
  • AOP代理: 是一个重新封装了(增强处理 + 被代理对象的方法 )方法的代理对象。
  • 织入(Weaving): 就如它名字表述的一样,增强处理切入目标对象以后,并获得代理对象(AOP代理)的这个过程,就是织入。按其作用的时间分类为,编译时织入与运行时织入。

SpringAOP的使用方法

基于注解的零配置方式:
一、启动@AspectJ注解支持,旭在相应的容器内,加入如下片段:



  1. <beans xmlns:aop="http://www.springframework.org/schema/aop" <!-- 必须有相应的XML Schema 配置 -->

  2. http://www.springframework.org/schema/aop

  3. http://www.springframework.org/schema/aop/spring-aop-4.0.xsd



  4. <!-- 必须相应的容器内,启动@AspectJ支持,如对Springmvc的Contrller织入, 则应在Springmvc.xml中配置 -->

  5. <aop:aspectj-autoproxy />

  6. <!-- 扫描相应的包 -->

二、定义切面bean


  1. @Aspect

  2. @Compement

  3. public class Advice{



  4. /*定义切入点, 业务处理逻辑等等其他内容*/



  5. }

三、定义@Before、@After、@Around等增强处理




  1. /*定义切入点表达式*/

  2. /*配置匹配service包下所有的类、所有的方法*/

  3. @Pointcut("execution(* com.xxx.xxx.service.*.*(..))")

  4. public void pointCutExpress(){

  5. }

四、定义处理方法



  1. @After("pointCutExpress()")

  2. public void closeResource(){

  3. /*After注解,更适合于释放资源*/

  4. }



通过注解和动态代理实现简单AOP

一、切入点注解



  1. @Target(ElementType.METHOD)

  2. @Retention(RetentionPolicy.RUNTIME)

  3. @Documented

  4. public @interface MyPointCut {

  5. /*模拟简单的注解定义切入点*/

  6. public String expression();



  7. }

二、原始对象及接口




  1. interface SomeMethods{

  2. void method1();

  3. void method2(String args);

  4. }



  5. public class Implementation implements SomeMethods{



  6. @Override

  7. public void method1() {

  8. System.out.println("原始对象的方法1");

  9. }



  10. @Override

  11. public void method2(String args) {

  12. System.out.println("原始对象的方法2及参数:" + args);

  13. }

  14. }

三、动态代理工厂



  1. class MyAspect{



  2. @MyPointCut(expression = "com.auhnayuil.comm.Implementation.*")

  3. public void Logger(){

  4. System.out.println(">>>>>>>>>>>>>>>>>正在记载日志中<<<<<<<<<<<<<<<<<<<<<<<");

  5. }



  6. }


  7. class SimpleProxyFactory{

  8. /*简单代理工厂*/



  9. public static Object getProxyObject(final Object realObject, final Object aspectObject){/*代理对象 切面定义类*/

  10. final Class<?> realObjectClass = realObject.getClass();

  11. final Class<?> aspectObjectClass = aspectObject.getClass();

  12. return Proxy.newProxyInstance(

  13. realObjectClass.getClassLoader(),

  14. realObjectClass.getInterfaces(),

  15. new InvocationHandler(){

  16. /*模拟简单的@Before日志注解*/

  17. @Override

  18. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  19. /*加载切入点信息. 这里的方法Logger被硬编码了, 后期可以根据注解来解决*/

  20. Method pointCutMethod = aspectObjectClass.getMethod("Logger", new Class[] {});

  21. MyPointCut myPointCut = pointCutMethod.getAnnotation(MyPointCut.class);

  22. /*判断切入点, 并执行其方法*/

  23. String expression = myPointCut.expression();

  24. String[] express = expression.split("\\.");

  25. int exprLength = express.length;

  26. if("*".equals(express[exprLength - 1])){

  27. /*这里只演示一种情况*/

  28. pointCutMethod.invoke(aspectObject, new Class[] {});

  29. }

  30. /*执行原始对象的方法*/

  31. return method.invoke(realObject, args);

  32. }

  33. }

  34. );

  35. }



  36. }



  37. public class ProxyDemo {



  38. public static void main(String[] args){



  39. SomeMethods someMethods = new Implementation();

  40. SomeMethods proxyObject = (SomeMethods) SimpleProxyFactory.getProxyObject(someMethods, new MyAspect());

  41. proxyObject.method1();

  42. proxyObject.method2("auhnayuiL");



  43. }



  44. }

四、输出结果



  1. >>>>>>>>>>>>>>>>>正在记载日志中<<<<<<<<<<<<<<<<<<<<<<<

  2. 原始对象的方法1

  3. >>>>>>>>>>>>>>>>>正在记载日志中<<<<<<<<<<<<<<<<<<<<<<<

  4. 原始对象的方法2及参数:auhnayuiL

OOP的完美点缀—AOP之SpringAOP实现原理的更多相关文章

  1. Java AOP的底层实现原理

    Java AOP的底层实现原理 一.什么是AOP 1.AOP:Aspect Oriented Programming(面向切面编程),OOP是面向对象编程,AOP是在OOP基础之上的一种更高级的设计思 ...

  2. Spring AOP的底层实现原理

    Spring的两大核心之一就是AOP,AOP:面向切面编程.在说原理之前,得先知道一些 AOP的专业术语. AOP的专业术语 连接点(JoinPoint):增强执行的位置(增加代码的位置),Sprin ...

  3. AutoRegister ASM AOP 字节码 案例 原理 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  4. 从壹开始前后端分离 40 || 完美基于AOP的接口性能分析

    旁白音:本文是不定时更新的.net core,当前主线任务的Nuxt+VueAdmin教程的 nuxt.js 之 tibug项目已上线,大家可以玩一玩:http://123.206.33.109:70 ...

  5. Spring aop 原始的工作原理的理解

    理解完aop的名词解释,继续学习spring aop的工作原理. 首先明确aop到底是什么东西?又如何不违单一原则并实现交叉处理呢? 如果对它的认识只停留在面向切面编程,那就脏了.从oop(Objec ...

  6. springAOP配置原理

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  7. spring框架学习笔记4:SpringAOP实现原理

    AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...

  8. Spring面试,IoC和AOP的理解, @Transactional原理及使用

    spring 的优点?1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易实 ...

  9. AOP的定义和原理

    一.本课目标 理解Spring AOP的原理 掌握Spring AOP的七个术语 二.面向切面编程(AOP)  AOP的思想是,不去动原来的代码,而是基于原来代码产生代理对象,通过代理的方法,去包装原 ...

随机推荐

  1. 对Unity注入技术最简单的理解和应用

    Unity注入技术,我决定最大的作用在于一个项目,尤其是WEB项目在更远其中一个类时,不需要重新生成,直接通过WEBCONFIG文件的修改就可以更改对应关系和功能,实验步骤如下: 1:新建一个接口IS ...

  2. Finding distance between two curves

    http://answers.opencv.org/question/129819/finding-distance-between-two-curves/ 问题: Hello, Im trying ...

  3. 【CNMP系列】CentOS7.0下安装MySql5.6服务

    接上一回的话,CentOS7.0下安装好了Nginx服务,对于我们的CNMP,我们可以开始我们的M啦,就是传统意义上的MySql服务 MySql简介 MySQL是一个关系型数据库管理系统,由瑞典MyS ...

  4. SVN的具体使用方法介绍(安装以及操作)

    今天由于项目的需要安装了SVN,在这里和大家分享一下SVN安装的详细过程和分享一些资料. (1)首先是客户端的安装. 1)获取客户端安装包. --安装包的获取路径: TortoiseSVN的官方下载地 ...

  5. jeesite简单入口分析

    这两天要开新项目 , 准备使用比较受欢迎的 jeesite框架 . jeesite是一个写好的网站 , 用到的框架比较多 具体请看 -- > github链接 下载下来之后 , 手动把maven ...

  6. 一个简单的php站点配置

    一个简单的php站点配置   现在我们来看在一个典型的,简单的PHP站点中,nginx怎样为一个请求选择location来处理:   server {     listen      80;     ...

  7. javascript中加var和不加var的区别

    Javascript是遵循ECMAScript标准下的一个产物,自然ECMAScript的标准其要遵循. 先来看下var关键字的定义和用法 var 语句用于声明变量. JavaScript 变量的创建 ...

  8. php根据用户输入单词,匹配相似单词

    最近在使用一款app背单词的时候,会在某个单词下面,列出与之相类似的单词.于是我在想这个功能是如何做的,自己使用php版本,做了个简单的例子. 大致思路如下: 1.生成英文单词库,并将单词放置redi ...

  9. java线程学习(二)

    多个线程并发抢占资源是,就会存在线程并发问题,造成实际资源与预期不符合的情况.这个时候需要设置"资源互斥". 1.创建资源,这个地方我创建了一个资源对象threadResource ...

  10. TypeScript设计模式之备忘录、命令

    看看用TypeScript怎样实现常见的设计模式,顺便复习一下. 学模式最重要的不是记UML,而是知道什么模式可以解决什么样的问题,在做项目时碰到问题可以想到用哪个模式可以解决,UML忘了可以查,思想 ...