Spring3系列12- Spring AOP AspectJ

本文讲述使用AspectJ框架实现Spring AOP。

再重复一下Spring AOP中的三个概念,

  1. Advice:向程序内部注入的代码。
  2. Pointcut:注入Advice的位置,切入点,一般为某方法。
  3. Advisor:Advice和Pointcut的结合单元,以便将Advice和Pointcut分开实现灵活配置。

AspectJ是基于注释(Annotation)的,所以需要JDK5.0以上的支持。

AspectJ支持的注释类型如下:

  1. @Before
  2. @After
  3. @AfterReturning
  4. @AfterThrowing
  5. @Around

首先定义一个简单的bean,CustomerBo实现了接口ICustomerBo

ICustomerBo.java如下:

package com.lei.demo.aop.aspectj;

public interface ICustomerBo {
void addCustomer();
void deleteCustomer();
String AddCustomerReturnValue();
void addCustomerThrowException() throws Exception;
void addCustomerAround(String name); }

CustomerBo.java如下:

package com.lei.demo.aop.aspectj;

public class CustomerBo implements ICustomerBo {

    public void addCustomer() {
System.out.println("addCustomer() is running ...");
} public void deleteCustomer() {
System.out.println("deleteCustomer() is running ...");
} public String AddCustomerReturnValue() {
System.out.println("AddCustomerReturnValue() is running ...");
return "abc";
} public void addCustomerThrowException() throws Exception {
System.out.println("addCustomerThrowException() is running ...");
throw new Exception("Generic Error");
} public void addCustomerAround(String name) {
System.out.println("addCustomerAround() is running ,args:"+name); } }

一、      简单的AspectJ,Advice和Pointcut结合在一起

首先没有引入Pointcut之前,Advice和Pointcut是混在一起的

步骤,只需要两步,如下:

  1. 创建一个Aspect类
  2. 配置Spring配置文件

第一步,创建Aspect类

LoggingAspect.java如下:

package com.lei.demo.aop.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; @Aspect
public class LoggingAspect { @Before("execution(public * com.lei.demo.aop.aspectj.CustomerBo.addCustomer(..))")
public void logBefore(JoinPoint joinPoint){
System.out.println("logBefore() is running ...");
System.out.println("hijacked:"+joinPoint.getSignature().getName());
System.out.println("**********");
} @After("execution(public * com.lei.demo.aop.aspectj.CustomerBo.deleteCustomer(..))")
public void logAfter(JoinPoint joinPoint){
System.out.println("logAfter() is running ...");
System.out.println("hijacked:"+joinPoint.getSignature().getName());
System.out.println("**********");
}
}

解释:

1.  必须使用@AspectLoggingAspect声明之前注释,以便被框架扫描到

2.  此例AdvicePointcut结合在一起,类中的具体方法logBeforelogAfter即为Advice,是要注入的代码,Advice方法上的表达式为Pointcut表达式,即定义了切入点,上例中@Before注释的表达式代表执行CustomerBo.addCustomer方法时注入logBefore代码。

3.  LoggingAspect方法上加入@Before或者@After等注释

4.  "execution(public * com.lei.demo.aop.aspectj.CustomerBo.addCustomer(..))"Aspect的切入点表达式,其中,*代表返回类型,后边的就要定义要拦截的方法名,这里写的的是com.lei.demo.aop.aspectj.CustomerBo.addCustomer表示拦截CustomerBo中的addCustomer方法,(..)代表参数匹配,此处表示匹配任意数量的参数,可以是0个也可以是多个,如果你确定这个方法不需要使用参数可以直接用(),还可以使用(*)来匹配一个任意类型的参数,还可以使用 (* , String),这样代表匹配两个参数,第二个参数必须是String 类型的参数

5.  AspectJ表达式,可以对整个包定义,例如,execution(* com.lei.service..*.*(..))表示切入点是com.lei.sevice包中的任意一个类的任意方法,具体的表达式请自行百度。

第二步,配置Spring配置文件,

配置Spring-AOP-AspectJ.xml文件,如下:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy/> <bean id="customerBo" class="com.lei.demo.aop.aspectj.CustomerBo"/> <bean id="logAspect" class="com.lei.demo.aop.aspectj.LoggingAspect" /> </beans>

解释:

1.      <aop:aspectj-autoproxy/>启动AspectJ支持,这样Spring会自动寻找用@Aspect注释过的类,其他的配置与spring普通bean配置一样。

测试:

执行App.java如下:

package com.lei.demo.aop.aspectj;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class App {
public static void main(String[] args) { ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "Spring-AOP-AspectJ.xml" });
ICustomerBo customer=(ICustomerBo)appContext.getBean("customerBo"); customer.addCustomer(); System.out.println("-------------------------------------------"); customer.deleteCustomer(); }
}

结果:

logBefore() is running ...

hijacked:addCustomer

**********

addCustomer() is running ...

-------------------------------------------

deleteCustomer() is running ...

logAfter() is running ...

hijacked:deleteCustomer

**********

二、      将Advice和Pointcut分开

需要三步,

  1. 创建Pointcut
  2. 创建Advice
  3. 配置Spring的配置文件

第一步,PointcutsDefinition.java定义了Pointcut,如下:

package com.lei.demo.aop.aspectj;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; @Aspect
public class PointcutsDefinition { @Pointcut("execution(* com.lei.demo.aop.aspectj.CustomerBo.*(..))")
public void customerLog() {
}
}

解释:

1. 类声明前加入@Aspect注释,以便被框架扫描到。

2. @Pointcut是切入点声明,指定需要注入的代码的位置,如上例中指定切入点为CustomerBo类中的所有方法,在实际业务中往往是指定切入点到一个逻辑层,例如 execution (* com.lei.business.service.*.*(..)),表示aop切入点为service包中所有类的所有方法,具体的表达式后边会有介绍。

3. 方法customerLog是一个签名,在Advice中可以用此签名代替切入点表达式,所以不需要在方法体内编写实际代码,只起到助记功能,例如此处代表操作CustomerBo类时需要的切入点。

第二步,创建Advice类

LoggingAspect.java如下:

package com.lei.demo.aop.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; @Aspect
public class LoggingAspect { @Before("com.lei.demo.aop.aspectj.PointcutsDefinition.customerLog()")
public void logBefore(JoinPoint joinPoint){
System.out.println("logBefore() is running ...");
System.out.println("hijacked:"+joinPoint.getSignature().getName());
System.out.println("**********");
} @After("com.lei.demo.aop.aspectj.PointcutsDefinition.customerLog()")
public void logAfter(JoinPoint joinPoint){
System.out.println("logAfter() is running ...");
System.out.println("hijacked:"+joinPoint.getSignature().getName());
System.out.println("**********");
}
}

注释:

1.       @Before@After使用PointcutsDefinition中的方法签名代替Pointcut表达式找到相应的切入点,即通过签名找到PointcutsDefinitioncustomerLog签名上的Pointcut表达式,表达式指定切入点为CustomerBo类中的所有方法。所以此例中AdviceLoggingAdvice,为CustomerBo中的所有方法都加入了@Before@After两种类型的两种操作。

2.       对于PointcutsDefinition来说,主要职责是定义Pointcut,可以在其中第一多个切入点,并且可以用便于记忆的方法签名进行定义。

3.       单独定义Pointcut的好处是,一是通过使用有意义的方法名,而不是难读的Pointcut表达式,使代码更加直观;二是Pointcut可以实现共享,被多个Advice直接调用。若有多个Advice调用某个Pointcut,而这个Pointcut的表达式在将来有改变时,只需修改一个地方,维护更加方便。

第三步,配置Spring配置文件,配置文件并没有改变

配置Spring-AOP-AspectJ.xml文件,如下:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy/> <bean id="customerBo" class="com.lei.demo.aop.aspectj.CustomerBo"/> <bean id="logAspect" class="com.lei.demo.aop.aspectj.LoggingAspect" /> </beans>

App.java不变,运行测试代码App.java

输出结果:

logBefore() is running ...

hijacked:addCustomer

**********

addCustomer() is running ...

logAfter() is running ...

hijacked:addCustomer

**********

-------------------------------------------

logBefore() is running ...

hijacked:deleteCustomer

**********

deleteCustomer() is running ...

logAfter() is running ...

hijacked:deleteCustomer

**********

三、     切入点表达式

Spring3.0.5帮助文档中的切入点表达式如下:

Some examples of common pointcut expressions are given below.

the execution of any public method:

execution(public * *(..))

the execution of any method with a name beginning with "set":

execution(* set*(..))

the execution of any method defined by the AccountService interface:

execution(* com.xyz.service.AccountService.*(..))

the execution of any method defined in the service package:

execution(* com.xyz.service.*.*(..))

the execution of any method defined in the service package or a sub-package:

execution(* com.xyz.service..*.*(..))

any join point (method execution only in Spring AOP) within the service package:

within(com.xyz.service.*)

any join point (method execution only in Spring AOP) within the service package or a sub-package:

within(com.xyz.service..*)

any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:

this(com.xyz.service.AccountService)

'this' is more commonly used in a binding form :- see the following section on advice for how to make the proxy object available in the advice body.

any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:

target(com.xyz.service.AccountService)

'target' is more commonly used in a binding form :- see the following section on advice for how to make the target object available in the advice body.

any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable:

args(java.io.Serializable)
'args' is more commonly used in a binding form :- see the following section on advice for how to make the method arguments available in the advice body.

Note that the pointcut given in this example is different to execution(* *(java.io.Serializable)): the args version matches if the argument passed at runtime is Serializable, the execution version matches if the method signature declares a single parameter of type Serializable.

any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation:

@target(org.springframework.transaction.annotation.Transactional)

'@target' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:

@within(org.springframework.transaction.annotation.Transactional)

'@within' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation:

@annotation(org.springframework.transaction.annotation.Transactional)

'@annotation' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.

any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the@Classified annotation:

@args(com.xyz.security.Classified)

'@args' can also be used in a binding form :- see the following section on advice for how to make the annotation object(s) available in the advice body.

any join point (method execution only in Spring AOP) on a Spring bean named 'tradeService':

bean(tradeService)

any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression '*Service':

bean(*Service)

Spring3系列12- Spring AOP AspectJ的更多相关文章

  1. Spring框架系列(12) - Spring AOP实现原理详解之JDK代理实现

    上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分.@pdai Spring框架系列(12) - Spring AOP实现原理详解 ...

  2. Spring AOP + AspectJ Annotation Example---reference

    In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...

  3. 关于 Spring AOP (AspectJ) 该知晓的一切

    关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...

  4. 关于 Spring AOP (AspectJ) 你该知晓的一切

    版权声明:本文为CSDN博主「zejian_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/javazej ...

  5. Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现

    前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的.本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所 ...

  6. Spring AOP + AspectJ annotation example

    In this tutorial, we show you how to integrate AspectJ annotation with Spring AOP framework. In simp ...

  7. Spring学习(十八)----- Spring AOP+AspectJ注解实例

    我们将向你展示如何将AspectJ注解集成到Spring AOP框架.在这个Spring AOP+ AspectJ 示例中,让您轻松实现拦截方法. 常见AspectJ的注解: @Before – 方法 ...

  8. 关于 Spring AOP (AspectJ) 你该知晓的一切 (转)

    出处:关于 Spring AOP (AspectJ) 你该知晓的一切

  9. Spring5.0源码学习系列之Spring AOP简述

    前言介绍 附录:Spring源码学习专栏 在前面章节的学习中,我们对Spring框架的IOC实现源码有了一定的了解,接着本文继续学习Springframework一个核心的技术点AOP技术. 在学习S ...

  10. Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建

    上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor).本文在此基 ...

随机推荐

  1. Nginx提示502和504错误的解决方案

    一.错误提示说明: Nginx 502 Bad Gateway的含义是请求的PHP-CGI已经执行,但是由于某种原因(一般是读取资源的问题)没有执行完毕而导致PHP-CGI进程终止. Nginx 50 ...

  2. Neo4j 2.0 M4 发布

    Neo4j 发布了 2.0 的第四个里程碑版本,该版本要求 Java 7 的支持.详细的改进记录请看发行通知. Neo是一个网络——面向网络的数据库——也就是说,它是一个嵌入式的.基于磁盘的.具备完全 ...

  3. 手机数据抓包以及wireshark技巧

    本文主要讨论一种非常方便的抓取Android和iphone手机网络数据包的办法,以及介绍wireshark最常用的技巧 抓包工具介绍 (1).网页抓包工具 Chrome浏览器插件 FireBug 插件 ...

  4. 淘宝TFS分布式文件系统内部实现

    TFS文件名的结构 TFS的文件名由块号和文件号通过某种对应关系组成,最大长度为18字节.文件名固定以T开始,第二字节为该集群的编号(可以在配置项中指定,取值范围 1~9).余下的字节由Block I ...

  5. [WinAPI] API 6 [操作驱动器挂载点]

    驱动器挂载点,又可以称作卷挂载点.挂载点实际上是操作系统或者用户设置的,用来进入一个逻辑驱动器或者卷的入口.在设置了卷的挂载点后,用户或者应用程序可以使用卷标或者指定的挂载点来进入卷.比如在“C:\” ...

  6. django orm总结

    目录1.1.1 生成查询1.1.2 创建对象1.1.3 保存修改的对象1.1.4 保存 ForeignKey 和 ManyToManyField 字段1.1.5 检索对象1.1.6 检索所有的对象1. ...

  7. nosql/nodejs基础

    nosql定义:nosql--no only sql 目前流行的非关系型数据库:mongodb,redis,cassandra 非关系型数据库和内存存储hashmap数据结构有什么区别?hashmap ...

  8. iOS系统app崩溃日志手动符号化

    iOS系统app崩溃日志手动符号化步骤: 1.在桌面建立一个crash文件夹,将symbolicatecrash工具..crash文件..dSYM文件放到该文件夹中 a.如何查询symbolicate ...

  9. (转)雅虎WEB前端网站优化 -- 34条军规

    雅虎给出了优化网站加载速度的34条法则(包括Yslow规则22条) 详细说明,下载转发 ponytail 的译文(来自帕兰映像). 1.Minimize HTTP Requests 减少HTTP请求 ...

  10. atitit.团队建设总结o6o fix

    atitit.团队建设o6o fix #----- 无限放大梦想 2 要有自己的方向...主动添加自己的东东.. 3 有几个tech site,能晓得最新的的知识.. 3 有问题多交流, 3 失败的造 ...