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

前言

OOP与AOP

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

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

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


/*

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

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

* 如 下面的注释了的方法

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

*/

class dog{

void run(){

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

}



void sleep(){

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

}

}

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


class dog{

private Note note = new Note();



void run(){

note.write("散步了");

}

void sleep(){

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

}

}

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

AOP实现原理

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


interface Interface{

void doSomething();

}



/*原始对象*/

class RealObject implements Interface{

@Override

public void doSomething() {

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

}

}



/*代理*/

class SimplProxy implements Interface {

private Interface proxied;



public SimplProxy(Interface proxied){

this.proxied = proxied;

}



public void doSomething(){

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

proxied.doSomething();

}

}



/*调用者*/

class Caller{

public static void call(Interface iface){

iface.doSomething();

}



public static void main(String[] args){

call(new SimplProxy(new RealObject()));

}

}

/*输出:*/

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

2.原始对象的行为

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

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

AOP使用场景

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

AOP基本概念

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


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

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

}

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

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

例如:

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

第二个 * 指service包下的所有类

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

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

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

SpringAOP的使用方法

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



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

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

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



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

<aop:aspectj-autoproxy />

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

二、定义切面bean


@Aspect

@Compement

public class Advice{



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



}

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




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

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

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

public void pointCutExpress(){

}

四、定义处理方法



@After("pointCutExpress()")

public void closeResource(){

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

}



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

一、切入点注解



@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface MyPointCut {

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

public String expression();



}

二、原始对象及接口




interface SomeMethods{

void method1();

void method2(String args);

}



public class Implementation implements SomeMethods{



@Override

public void method1() {

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

}



@Override

public void method2(String args) {

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

}

}

三、动态代理工厂



class MyAspect{



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

public void Logger(){

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

}



}


class SimpleProxyFactory{

/*简单代理工厂*/



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

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

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

return Proxy.newProxyInstance(

realObjectClass.getClassLoader(),

realObjectClass.getInterfaces(),

new InvocationHandler(){

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

@Override

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

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

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

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

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

String expression = myPointCut.expression();

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

int exprLength = express.length;

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

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

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

}

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

return method.invoke(realObject, args);

}

}

);

}



}



public class ProxyDemo {



public static void main(String[] args){



SomeMethods someMethods = new Implementation();

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

proxyObject.method1();

proxyObject.method2("auhnayuiL");



}



}

四、输出结果



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

原始对象的方法1

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

原始对象的方法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. Top 10 Books For Advanced Level Java Developers

    Java is one of the most popular programming language nowadays. There are plenty of books for beginne ...

  2. 微信内置浏览器私有接口WinXinJsBridge介绍

    关于微信内置浏览器私有接口WeiXinJsBridge,只是之前接触过的一个微信公众号项目中遇到过,不过并没有深入研究过,可以说并没有了解过... 刚好今天无意中看到了这方面的知识,就补习一下,弥补一 ...

  3. 【转】44款Java 网络爬虫开源软件

    原帖地址 http://www.oschina.net/project/lang/19?tag=64&sort=time 极简网络爬虫组件 WebFetch WebFetch 是无依赖极简网页 ...

  4. WPF 自定义图片按钮

    此文档仅仅是一个BaseCode,已做后续查阅 XAML代码: <Button x:Class="IM.UI.UC.IM_ImageButton" xmlns="h ...

  5. 使用PHP生成二维码(PHPQRCode)

    关于什么是二维码,可以阅读 http://baike.baidu.com/view/132241.htm 这里就不多讲了,二维码的应用非常广泛,似乎一夜之间渗透到我们生活的方方面面,地铁广告.报纸.火 ...

  6. 第十八篇 js高级知识---作用域链

    一直有想法去写写js方面的东西,我个人是最喜欢js这门语言,喜欢的他的自由和强大,虽然作为脚本语言有很多限制的地方,但也不失为一个好的语言,尤其是在H5出现之后.下面开始说说js的方面的东西,由于自己 ...

  7. lua string.sub截取中英文

    cocos2dx 2.x环境,要做一个截取很长的字符串的前100个字符显示的小功能. PC环境ok,出了ios包发现有时候这个字符串会显示不出,猜测了下可能是跟中文字在lua里每个字占3个字符有关,举 ...

  8. MyBatis 使用Generator自动生成Model , Dao, mapper

    最近   我新建了一 个maven 项目,使用的是spring + springmvc + mybatis框架. 听说Mybatis可以自动生成model和mapper以及dao层,我就从网上查了查资 ...

  9. iOS集成ApplePay

    Apple Pay正式在国内上线的那天,一起工作的小伙伴就走进了Starbucks,7-11等带有银联闪付的店进行了尝鲜.不管是否要再次输入一次密码,但是它的出现确实给我们带来了极大的便捷.下面就尝试 ...

  10. SqlServer建立存储过程,方便.NET插入自增字段

    首先,需要在数据库中创建一个表,以在test数据库创建tableNo表为例: create table tablesNo ( tableName ) not null, --表名 num int no ...