Spring AOP 实现原理 与CGLIb应用

什么是Spring AOP

Spring AOP 是Spring的核心功能,因为Java是面向对象编程,更多的是一个纵向的,但是遇到存在不存在关联和继承关系的横向关系时,就无法处理。所以这时可以通过切入点,将不相关的逻辑织入到当前业务代码中。

Spring AOP的类型

AOP的代理可分为

  • 静态代理:编译时增强,使用AOP框架提供的命令进行编译,从而在编译阶段生成AOP代理类。
  • 动态代理:运行时增强,借助JDK动态代理、CGLIB在内存中临时生成AOP动态代理类。

Spring 使用了同AspectJ 5 一样的注解,但是并没有 使用AspectJ编译器和织入器(Weaver),底层依然使用的Spring AOP 来实现动态代理生成AOP。

使用Spring AOP 实现AOP

  • 启用注解模式
<!-- 启动 @AspectJ 支持 -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
  • 定义需要处理的Bean
// 使用 @Aspect 定义一个方面类
@Component 
public class Chinese
{ 
   public String sayHello(String name){ 
       System.out.println("-- 正在执行 sayHello 方法 --"); 
       // 返回简单的字符串
       return name + " Hello , Spring AOP"; 
   } 
// 定义一个 eat() 方法
   public void eat(String food){ 
      System.out.println("我正在吃 :"+ food); 
   } 
}
  • 切入增加方法:事务控制、日志记录
  //定义一个切面
@Aspect
public class AfterReturnTest{
  //匹配包下所有的方法执行为切入点
@AfterReturning(return="rvt",pointcut="execution(* cn.com.bluemoon.service.impl.*.*")
  public void log(Object rvt){
    System.out.println("获取目标方法返回值:"+ rvt);
    System.out.println("模拟日制记录...");
  }
}

在程序中增加System.out.println(p.getClass());

代码可以输入p变量所引用对象的实现类,再次执行将看到代码产生class org...**.Chinese$EnhancerByCgLib$$290441d2的输出,这才是p变量所引用的对象的实现类,同时也是Spring AOP动态生成的AOP代理类。

若将上面程序稍作修改:让业务罗积累Chinese类实现一个任意接口例如:

public interface Person 
{ 
String sayHello(String name); 
void eat(String food); 
}

接下来Beantest类面向Person接口、而不是Chinese类编程。

public class BeanTest 
{ 
public static void main(String[] args) 
{ 
// 创建 Spring 容器
ApplicationContext ctx = new 
ClassPathXmlApplicationContext("bean.xml"); 
Person p = ctx.getBean("chinese" ,Person.class);
System.out.println(p.sayHello("张三")); 
p.eat("西瓜"); 
System.out.println(p.getClass()); 
} 
}

执行输出的将会是class$Proxy7,说明AOP代理由JDK动态代理生成。

Spring AOP 动态代理原则

类型 实现方式
CGLIB 目标对象实现类没有实现接口
JDK 目标对象实现了接口

Spring AOP 原理

Spring AOP结构图

如图所示: Spring AOP的代理是由Spring的Ioc容易负责生成、管理,其依赖关系也由Ioc容器负责管理。因此,AOP代理可以直接使用容器中的其他bean实例座位目标,这种关系可由IOC容器的依赖注入提供。
而我们需要做的是:

  • 定义普通业务组件
  • 定义切入点,一个切入点可能横切多个业务组件
  • 定义增强处理(After、Before、Around),AOP框架为普通业务组件织入(weaver)处理动作。

CGLIB 生成代理类

CGLIB(Code Generation Library)即代码生成库。可以在运行时动态的生成某个类的自雷。

AroundAdivice.java : 拦截器实现类
public class AroundAdvice implements MethodInterceptor 
{ 
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)throws 
 java.lang.Throwable { 
  System.out.println("执行目标方法之前,模拟开始事务 ..."); 
  // 执行目标方法,并保存目标方法执行后的返回值
  Object rvt = proxy.invokeSuper(target, new String[]{"被改变的参数"}); 
  System.out.println("执行目标方法之后,模拟结束事务 ..."); 
  return rvt + " 新增的内容"; 
  } 
}

它的作可以在调用目标方法之前、调用目标方法之后织入增强处理。

ChineseProxyFactory.java:工作类
public class ChineseProxyFactory 
{ 
  public static Chinese getAuthInstance(){ 
    Enhancer en = new Enhancer(); 
    // 设置要代理的目标类
    en.setSuperclass(Chinese.class);
    // 设置要代理的拦截器
    en.setCallback(new AroundAdvice());
    // 生成代理类的实例 
    return (Chinese)en.create();
  } 
}

通过Enhancer 将Chinese类作为目标,以AroundAdvice对象作为ADvice,程序将会生成一个Chinese的子类,这个子类就是CGLIB生成的代理类,作为Chinese对象使用,但它增强了Chinese类的方法。

测试效果:

public class Main 
{ 
public static void main(String[] args) 
{ 
Chinese chin = ChineseProxyFactory.getAuthInstance(); 
System.out.println(chin.sayHello("孙悟空")); 
chin.eat("西瓜"); 
System.out.println(chin.getClass()); 
} 
}
-- 正在执行 sayHello 方法 --

执行目标方法之后,模拟结束事务 ...

被改变的参数 Hello , CGLIB 新增的内容

执行目标方法之前,模拟开始事务 ...

我正在吃 : 被改变的参数

执行目标方法之后,模拟结束事务 ...

class lee.Chinese$$EnhancerByCGLIB$$4bd097d9

小结

AOP广泛应用于处理一些具有横切性质的系统级服务,AOP的出现是对OOP的补充,它是的开发者能用更优雅的方式处理具有横切性质的服务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,135评论 6 514
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,317评论 3 397
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,596评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,481评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,492评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,153评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,737评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,657评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,193评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,276评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,420评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,093评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,783评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,262评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,390评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,787评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,427评论 2 359

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,689评论 18 139
  • 本文主要讲实现AOP的 代理模式原理,以及静态代理,动态代理的区别和具体实现。 对SpringAOP的概念和使用,...
    _Zy阅读 755评论 0 1
  • IOC和DI是什么? Spring IOC 的理解,其初始化过程? BeanFactory 和 FactoryBe...
    justlpf阅读 3,477评论 1 21
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,473评论 1 133
  • 中国有没有哲学呢?我原来只知道中国有孔孟老庄,有百家争鸣,中国的孔子学院遍地开花,却没有中国哲学的概念。冯友兰先生...
    明明如月还在阅读 964评论 1 3