关闭

Spring-AOP基础知识

标签: springjavacglibaop
2372人阅读 评论(0) 收藏 举报
分类:

导读

Spring-AOP基础知识

Java-JDK动态代理

Java-CGLib动态代理


概述

Spring AOP 使用动态代理技术在运行期织入增强的代码.

为了解密SpringAOP底层的工作机制,我们需要先学习下涉及到的JAVA知识。

Spring使用两种代理机制:

  1. 一种是基于JDK的动态代理
  2. 另一种是基于CGLib的动态代理。

之所以需要两种代理,是因为JDK本身只能提供接口的代理,而不支持类的代理。


带有横切逻辑的实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

来看个实例,我们以性能监控为例子,在调用每个目标类方法时启动方法的性能监视,在目标类方法调用完成时记录方法的花费时间。

这里写图片描述

我们首先来看下包含性能监视横切代码的 ForumService

package com.xgj.aop.base.instance;

/**
 * 
 * 
 * @ClassName: ForumServiceImpl
 * 
 * @Description: ForumService实现类
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月12日 下午4:14:30
 */
public class ForumServiceImpl implements ForumService {

    @Override
    public void removeTopic(int topicId) {
        // 1-(1)开始对removeTopic方法的监控
        PerformanceMonitor.begin("removeTopic");

        // 模拟业务逻辑
        System.out.println("模拟删除Topic");
        try {
            Thread.currentThread().sleep((long) (Math.random() * 1000 * 10));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 1-(2)结束对removeTopic方法的监控
        PerformanceMonitor.end("removeTopic");
    }

    @Override
    public void removeForum(int forumId) {
        // 2-(1)开始对removeForum法的监控
        PerformanceMonitor.begin("removeForum");
        // 模拟业务逻辑
        System.out.println("模拟删除forum");
        try {
            Thread.currentThread().sleep((long) (Math.random() * 1000 * 10));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 2-(2)结束对removeForum法的监控
        PerformanceMonitor.end("removeForum");
    }

}

ForumServiceImpl 实现了ForumService接口。

package com.xgj.aop.base.instance;

/**
 * 
 * 
 * @ClassName: ForumService
 * 
 * @Description: ForumService接口
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月12日 下午4:13:31
 */
public interface ForumService {
    /**
     * 
     * 
     * @Title: removeTopic
     * 
     * @Description: 根据topicId删除Topic
     * 
     * @param topicId
     * 
     * @return: void
     */
    void removeTopic(int topicId);

    /**
     * 
     * 
     * @Title: removeForum
     * 
     * @Description: 根据forumId删除Forum
     * 
     * @param forumId
     * 
     * @return: void
     */
    void removeForum(int forumId);
}

其中1-(1) 1-(2) 2-(1)2-(2)标注的是具有横切逻辑特征的代码,每个Service类和每个业务方法体的前后都执行相同的代码逻辑:方法启动前启用PerformanceMonitor,方法调用后通知PerformanceMonitor结束性能监视并记录性能监视结果。

PerformanceMonitor是性能监视的实现类

package com.xgj.aop.base.instance;

public class PerformanceMonitor {
    // 通过一个ThreadLocal保存与调用线程相关的性能监视信息
    private static ThreadLocal<MethoPerformance> performanceLocal = new ThreadLocal<MethoPerformance>();

    /**
     * 
     * 
     * @Title: begin
     * 
     * @Description: 启动对某一目标方法的性能监视
     * 
     * @param method
     * 
     * @return: void
     */
    public static void begin(String method) {
        System.out.println("begin to monitor:" + method);
        MethoPerformance methoPerformance = new MethoPerformance(method);
        performanceLocal.set(methoPerformance);
    }

    /**
     * 
     * 
     * @Title: end
     * 
     * @Description: 输出性能监视结果
     * 
     * @param method
     * 
     * @return: void
     */
    public static void end(String method) {
        System.out.println("finish monitor:" + method);

        MethoPerformance methoPerformance = performanceLocal.get();
        // 打印出方法性能监视的结果信息
        methoPerformance.printPerformance();
    }
}

我们通过ThreadLocal将非线程安全类改造为线程安全的类。

PerformanceMonitor类中两个方法 begin和end ,其中method规定为目标类方法的全限定名。 两个方法必须配套使用。

用于记录性能监视信息的MethoPerformance 如下:

package com.xgj.aop.base.instance;

public class MethoPerformance {

    private long beginTime;
    private long endTime;
    private String methodName;

    /**
     * 
     * 
     * @Title:MethoPerformance
     * 
     * @Description:构造函数
     * 
     * @param methodName
     */
    public MethoPerformance(String methodName) {
        super();
        this.methodName = methodName;
        this.beginTime = System.currentTimeMillis();
    }

    /**
     * 
     * 
     * @Title: printPerformance
     * 
     * @Description: 计算耗时
     * 
     * 
     * @return: void
     */
    public void printPerformance() {
        endTime = System.currentTimeMillis();
        long cost = endTime - beginTime;
        System.out.println(methodName + " costs " + cost / 1000 + "秒\n");
    }
}

测试类:

package com.xgj.aop.base.instance;

public class ForumServiceTest {

    public static void main(String[] args) {
        ForumService forumService = new ForumServiceImpl();
        forumService.removeTopic(1);
        forumService.removeForum(2);
    }

}

运行结果:

这里写图片描述

问题:通过这个实例,我们可以看到当某个方法需要进行性能监视时,必须调整方法代码,在方法体前后分别添加开启性能监视和结束性能监视的代码。 这些非业务逻辑的性能监视代码破坏了业务实现类中业务逻辑的纯粹性。

改进:我们希望通过代理的方式将业务类方法中开启和结束性能监视的横切代码从业务类中完全移除,并通过JDK或者CGLib动态代理技术将横切代码动态的织入到目标方法的相应位置。


JDK动态代理

详情请访问另一篇博客: Java-JDK动态代理


CGLib动态代理

详情请访问另一篇博客: Java-CGLib动态代理


代理知识小结

Spring AOP的底层就是通过使用JDK或者CGLib动态代理技术为目标Bean织入横切逻辑的。

总结一下动态创建代理对象:

虽然通过PerformanceHandle或者CglibProxy实现了性能监视横切逻辑的动态织入,但是这种实现方式有3个明显需要改进的地方

  1. 目标类的所有方法都添加了性能监视横切逻辑,而有的时候这并不是我们所期望的,我们可能只希望对业务类中的某些特定方法添加横切逻辑

  2. 通过硬编码的方式指定了织入横切逻辑的织入点,即在目标类业务方法的开始和结束前织入代码

  3. 手工编写代理实例的创建过程,在为不同类创建代理时,需要分别编写相应的创建代码,无法做到通用。

以上3个问题在AOP中占有重要的地位,因为SpringAOP的主要工作就是围绕以上3点展开的: Spring AOP 通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等)。

此外,Spring通过Advisor(切面)将Point和Advice组装起来,有了Advisor信息,SPring就可以利用JDK或者CGLib动态代理结束采用统一的方式为目标Bean创建织入切面的代理对象了。

对应singleton的代理对象或者具有实例池的代理,因无需频繁创建对象,比较适合采用CGLib动态代理技术,反之则比较适合采用JDK动态代理技术

1
0
查看评论

Spring-AOP

转:http://labi47.javaeye.com/blog/169230 一,基本概念 横切(crosscutting) 关注点。 切面(Aspect): 对象操作过程中的截面。一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很...
  • foart
  • foart
  • 2009-07-27 17:34
  • 636

spring-aop

1.1  AspectJ(掌握) 1.1.1   介绍 l  AspectJ是一个基于Java语言的AOP框架 l  Spring2.0以后新增了对AspectJ切入点表达式支持 l  @Aspect 是AspectJ1....
  • u010073895
  • u010073895
  • 2016-06-30 21:33
  • 173

spring源代码学习(一)

git下载的spring源代码,运行gradle相关命令,导入eclipse,报错—— Project 'spring' is missing required Java project: 'spring-webmvc-tiles3' Project '...
  • gxftry1st
  • gxftry1st
  • 2016-12-23 12:07
  • 633

Spring-Aop

通知: 前置通知,后置通知,循环通知,异常通知,yiru
  • lv836735240
  • lv836735240
  • 2014-10-05 22:37
  • 493

spring-AOP

静态代理 动态代理
  • x532716636
  • x532716636
  • 2014-09-18 08:53
  • 164

spring AOP 基于注解(spring版本4.2.0)

spring AOP 概念点击打开链接spring AOP 如何获取目标方法的参数,如何在目标方法执行前,修改目标方法的参数。如何在目标方法执行后,修改目标方法的返回结果。点击打开链接spring AOP 基于注解的实现需要依赖的jar aopalliance-1.0.jar,aspectjrt-...
  • liang_love_java
  • liang_love_java
  • 2015-11-17 17:34
  • 1227

spring AOP asm冲突

最近在用spring AOP处理事务,使用maven来引用jar包,根据报错的提示一直增加jar包;结果在添加asm-util.jar的时候总是出现冲突;后来发现时cglib.jar中会引用asm-4.0.jar而使用asm-util.jar也会应用asm-3.1.jar;这样就冲突了; 解决方案:...
  • qq584852076
  • qq584852076
  • 2013-07-09 10:54
  • 1501

[教程]spring AOP详解

来源: http://blog.csdn.net/a906998248/article/details/7514969 ※AOP依赖Java的代理机制(JDK代理,CGLib代理) [我比较懒,直接拷过来,不改格式了] 一、什么是 AOP。 AOP(Aspect Orient Progra...
  • wangxsh42
  • wangxsh42
  • 2015-01-30 19:08
  • 168

Spring-AOP笔记

一 AOP概念 1 什么是 AOP AOP(Aspect Oriented Programming) 解决 OOP(Object Oriented Programming) 中遇到的一些问题.是 OOP 的延续和扩展. 2 为什么学习 AOP 对程序进行增强:不修改源码的情况下. ...
  • qq_33218873
  • qq_33218873
  • 2018-01-11 17:25
  • 42

spring-Aop切面编程

** 什么是面向切面编程? 面向切面编程主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。定义还挺邪乎的,其实我个人目前的理解就是把一个方法中重复使用的代码提取出来[类似于代理],建立一个专门的类来处理,并且是一种...
  • u013468915
  • u013468915
  • 2016-09-24 11:43
  • 450
    个人资料
    • 访问:1316250次
    • 积分:19097
    • 等级:
    • 排名:第554名
    • 原创:459篇
    • 转载:0篇
    • 译文:5篇
    • 评论:149条
    WeChat
      欢迎关注我的公众号,干货只有干货,还有更多惊喜和资源在等着你
    博客专栏