在上一篇AspectJ的入门中,简单的介绍了下AspectJ的使用,主要是以AspectJ的example作为例子。介绍完后也留下了几个问题:
1)我们在spring中并没有看到需要aspectj之类的关键词,而是使用java代码就可以了,这是如何做到的
2)Spring中如何做到不使用特殊的编译器实现aop的(AspectJ如何在运行期使用)
3)Spring源码中与aspectJ 相关的AjType究竟是啥?

这篇文章会继续试着解决这几个问题。

aspectJ的几种织入方式

compile-time、post-compile 和 load-time Weavers

首先了解下AspectJ的几种织入方式,分别是compile-time、post-compile 和 load-time,分别对应着编译期、后编译期、加载期织入

编译期织入

首先是编译期织入,上一篇博客所介绍的方式就是使用的编译期织入。很容易理解,普通的java源码 + aspectJ特殊语法的‘配置’ 文件 + aspectJ特殊的编译器,编译时候生成已织入后的.class文件,运行时直接运行即可。

后编译期织入

后编译期织入和编译期的不同在于,织入的是class字节码或者jar文件。这种形式,可以织入一个已经织入过一次的切面。同样这种情况也需要特殊的编译器

加载期织入

加载期顾名思义,是在类被加载进虚拟机之前织入,使用这种方式,须使用AspectJ agent。

了解了这些概念,下面就要知道,spring是使用哪种呢?spring哪一种都不是,spring是在运行期进行的织入。

Spring 如何使用AspectJ

AspectJ 本身是不支持运行期织入的,日常使用时候,我们经常回听说,spring 使用了aspectJ实现了aop,听起来好像spring的aop完全是依赖于aspectJ

其实spring对于aop的实现是通过动态代理(jdk的动态代理或者cglib的动态代理),它只是使用了aspectJ的Annotation,并没有使用它的编译期和织入器,也就是说spring并不是直接使用aspectJ实现aop的

spring aop与aspectJ的区别

看了很多篇博客以及源码,我对spring aop与aspectJ的理解大概是这样;
1)spring aop 使用AspectJ语法的一个子集,一些method call, class member set/get 等aspectJ支持的语法它都不支持
2)spring aop 底层是动态代理,所以受限于这点,有些增强就做不到,比如 调用自己的方法就无法走代理

看下下面的例子:

@Component
public class A{
public void method1(){
method2();
} public void method2(){
//...
}
}

这个时候method2是无法被切到的,要想被切到可以通过如下奇葩的方式:

@Component
public class A{ @Autowired
private A a; public void method1(){
a.method2();
} public void method2(){
//...
}
}

之前碰到这样的问题时,我还特别不能理解,现在想下aop的底层实现方式就很容易理解了。

在之前写的jdk动态代理与cglib动态代理实现原理,我们知道了jdk动态代理是通过动态生成一个类的方式实现的代理,也就是说代理是不会修改底层类字节码的,所以可能生成的代理方法是这样的

public void method1(){
//执行一段代码
a.method1()
//执行一段代码
} public void method2(){
//执行一段代码
a.method2()
//执行一段代码
}

回头看a.method1()的源码,也就明白了,为啥method2()没有被切到,因为a.method1()执行的方法,最后调用的不是 代理对象.method2(),而是它自己的method2()(this.method2()) 这个方法本身没有任何改动

反观aspectJ,aspectJ是在编译期修改了方法(类本身的字节码被改了),所以可以很轻松地实现调用自己的方法时候的增强。

3)spring aop的代理必须依赖于bean被spring管理,所以如果项目没有使用spring,又想使用aop,那就只能使用aspectJ了(不过现在没有用spring的项目应该挺少的吧。。。)

4)aspectJ由于是编译期进行的织入,性能会比spring好一点
5)spring可以通过@EnableLoadTimeWeaving 开启加载期织入(只是知道这个东西,没怎么研究。。有兴趣的可以自己去研究下)
6)spring aop很多概念和aspectJ是一致的

AspectJ的注解在spring aop中的应用

了解了spring与aspectJ的关系后,就能更清晰的了解spring 的aop了。

先说明一点,虽然我介绍aspect的配置时,一直介绍的aspectJ文件配置方式,但是aspectJ本身是支持注解方式配置的。可以看官方文档,注解在aspectJ中的使用

而spring 使用了aspectJ注解的一小部分(正如前面所说的,受限于jdk的动态代理,spring只支持方法级别的切面)

回头看看AjType

回头看看之前看到的这段源码,什么是AjType,经过aspectJ解析器解析后对类的一种描述,比如正常的方法可能是这样

/*
* 配置前置通知,使用在方法aspect()上注册的切入点
* 同时接受JoinPoint切入点对象,可以没有该参数
*/
@Before("aspect()")
public void before(JoinPoint joinPoint) {
log.info("before " + joinPoint);
}

在AjType中就能获取到很多其他的aspectJ所需的相关信息(除了java反射所能获取到的信息以外)

/**
* Return the pointcut object representing the specified pointcut declared by this type
*/
public Pointcut getDeclaredPointcut(String name) throws NoSuchPointcutException; /**
* Return the pointcut object representing the specified public pointcut
*/
public Pointcut getPointcut(String name) throws NoSuchPointcutException;

比如看着两个方法,可以获取到切入点信息。

在看看PerClauseKind.SINGLETON 这里就复用了aspectJ的概念

总结下

这篇文章回答了之前学习aspectJ时候碰到的几个问题,然后讨论了下aspectJ在spring中的应用。最大的收获是了解了spring与aspectJ 的关系,了解了两者对aop的不同实现所造成的使用上的影响。以后当遇到了spring aop相关的概念如果不理解,可以去aspectJ上去搜搜看了 = =

原文链接
本文为云栖社区原创内容,未经允许不得转载。

AspectJ在Spring中的使用的更多相关文章

  1. spring中AspectJ的使用

    目录 AspectJ: AOP术语 通知的类型 切入点表达式 基于xml的AspectJ编程 导入jar包 定义切面类 引入约束 AOP配置 基于注解的AspectJ编程 AspectJ: 什么是AO ...

  2. 在Spring中使用AspectJ实现AOP

    在Spring中,最常用的AOP框架是AspectJ,使用AspectJ实现AOP有2种方式: 基于XML的声明式AspectJ 基于注解的声明式AspectJ 基于XML的声明式AspectJ 1. ...

  3. Spring实战(十二) Spring中注入AspectJ切面

    1.Spring AOP与AspectJ Spring AOP与AspectJ相比,是一个功能比较弱的AOP解决方案. AspectJ提供了许多它不能支持的类型切点,如在创建对象时应用通知,构造器切点 ...

  4. Spring 中基于 AOP 的 @AspectJ

    Spring 中基于 AOP 的 @AspectJ @AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格. 通过在你的基于架构的 XML ...

  5. Spring中文文档-第一部分

    一. Spring 框架概述 Spring是为了构建企业应用的轻量级框架.然而,Spring是模块化的,允许你只是使用其中的一部分,不需要引入其他的.你可以在任何web框架上使用IoC容器,也可以只使 ...

  6. Spring中文文档

    前一段时间翻译了Jetty的一部分文档,感觉对阅读英文没有大的提高(*^-^*),毕竟Jetty的受众面还是比较小的,而且翻译过程中发现Jetty的文档写的不是很好,所以呢翻译的兴趣慢慢就不大了,只能 ...

  7. 基于@AspectJ配置Spring AOP之一--转

    原文地址:http://tech.it168.com/j/2007-08-30/200708302209432.shtml 概述 在低版本Spring中定义一个切面是比较麻烦的,需要实现特定的接口,并 ...

  8. Spring中的通知(Advice)和顾问(Advisor)

    在Spring中,目前我学习了几种增强的方式,和大家分享一下 之前的话: 1.AOP  (Aspect  Oriented Programming  面向切面编程) 在软件业,AOP为Aspect O ...

  9. 浅析Spring中的注解

    Spring的配置,通常有两种:使用配置文件和注解.那么Spring如何知道各个Bean或者Service.Controller以及Bean中各类属性之间的关系呢?答案肯定是在定义各个Java文件的时 ...

随机推荐

  1. 【翻译】Flume 1.8.0 User Guide(用户指南) source

    翻译自官网flume1.8用户指南,原文地址:Flume 1.8.0 User Guide 篇幅限制,分为以下5篇: [翻译]Flume 1.8.0 User Guide(用户指南) [翻译]Flum ...

  2. 学习Acegi应用到实际项目中(7)- 缓存用户信息

    在默认情况下,即在用户未提供自身配置文件ehcache.xml或ehcache-failsafe.xml时,EhCache会依据其自身Jar存档包含的ehcache-failsafe.xml文件所定制 ...

  3. 手机端-万种bt在线观看器,安卓正版下载!

    安卓正版下载, 点击下载 无广告,完全免费!寻找任何你想要的资源!

  4. 关于CSS层叠机制

    谈到层叠机制,首先我们要知道什么是声明冲突. 声明冲突有三个条件:①多个选择器选中同一个元素:②声明块里的属性相同:③属性的属性值不同.同时满足这三点时就会产生声明冲突.比如下图html代码: < ...

  5. Linux时间戳转换成BCD码(转载)

    #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> / ...

  6. JavaScript自定义鼠标右键菜单

    下面为JavaScript代码 window.onload = function () { //好友列表 var f = 0; //判断指定id的元素在页面中是否存在 if (document.get ...

  7. keepalived给LVS带来了什么

    LVS+Keepalived 1>Keepalived简介  Keepalived是Linux下一个轻量级别的高可用解决方案,高可用(High Avalilability,HA),其实两种不同的 ...

  8. socket实现FTP上传下载功能

    '''服务器端''' 1 _author__ = "Dbass" import socketserver import json,os class MyTCPHandler(soc ...

  9. 卷积神经网络中的channel 和filter

    在深度学习的算法学习中,都会提到 channels 这个概念.在一般的深度学习框架的 conv2d 中,如 tensorflow .mxnet,channels 都是必填的一个参数. channels ...

  10. Product and Sum in Category Theory

    Even if you are not a functional programmer, the notion of product type should be familiar to you, e ...