开涛spring3(6.4) - AOP 之 6.4 基于@AspectJ的AOP

Spring除了支持Schema方式配置AOP,还支持注解方式:使用@AspectJ风格的切面声明。

6.4.1  启用对@AspectJ的支持

Spring默认不支持@AspectJ风格的切面声明,为了支持需要使用如下配置:

<aop:aspectj-autoproxy/>  

这样Spring就能发现@AspectJ风格的切面并且将切面应用到目标对象。

6.4.2  声明切面

@AspectJ风格的声明切面非常简单,使用@Aspect注解进行声明:

    @Aspect()
    Public class Aspect{
    ……
    }  

然后将该切面在配置文件中声明为Bean后,Spring就能自动识别并进行AOP方面的配置:

    <bean id="aspect" class="……Aspect"/>  

该切面就是一个POJO,可以在该切面中进行切入点及通知定义,接着往下看吧。

6.4.3  声明切入点

@AspectJ风格的命名切入点使用org.aspectj.lang.annotation包下的@Pointcut+方法(方法必须是返回void类型)实现。

@Pointcut(value="切入点表达式", argNames = "参数名列表")
public void pointcutName(……) {}  

value指定切入点表达式;

argNames指定命名切入点方法参数列表参数名字,可以有多个用“,”分隔,这些参数将传递给通知方法同名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。

pointcutName切入点名字,可以使用该名字进行引用该切入点表达式。

    @Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
    public void beforePointcut(String param) {}  

定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数名为“param”的参数类型。

6.4.4  声明通知

@AspectJ风格的声明通知也支持5种通知类型:

一、前置通知:使用org.aspectj.lang.annotation 包下的@Before注解声明;

@Before(value = "切入点表达式或命名切入点", argNames = "参数列表参数名") 

value指定切入点表达式或命名切入点;

argNames与Schema方式配置中的同义。

 

接下来示例一下吧:

1、定义接口和实现,在此我们就使用Schema风格时的定义;

package lqy.springh6_4;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

2、定义切面:
@Aspect
public class HelloWorldAspect2 {  

    3、定义切入点:
    @Pointcut(value="execution(* lqy.springh6_2..*.sayBefore(..)) && args(param)", argNames = "param")
    public void beforePointcut(String param) {}  

    4、定义通知:
    @Before(value = "beforePointcut(param)", argNames = "param")
    public void beforeAdvice(String param) {
        System.out.println("HelloWorldAspect2:" + param);
    } 

}

xml配置文件中进行如下配置:

<?xml version="1.0" encoding="UTF-8"?>
<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="helloWorldService"  class="lqy.springh6_2.HelloWorldService"/>  

  <bean id="aspect"  class="lqy.springh6_4.HelloWorldAspect2"/>  

</beans>  

测试

package lqy.springh6_4;

import lqy.springh6_2.IHelloWorldService;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test2 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        ApplicationContext ctx =  new ClassPathXmlApplicationContext("lqy/springh6_4/springh6_4.xml");  

        IHelloWorldService helloworldService = ctx.getBean("helloWorldService", IHelloWorldService.class);
        helloworldService.sayBefore("before");  

    }

}

切面、切入点、通知全部使用注解完成:

1)使用@Aspect将POJO声明为切面;

2)使用@Pointcut进行命名切入点声明,同时指定目标方法第一个参数类型必须是java.lang.String,对于其他匹配的方法但参数类型 不一致的将也是不匹配的,通过argNames = "param"指定了将把该匹配的目标方法参数传递给通知同名的参数上;

3)使用@Before进行前置通知声明,其中value用于定义切入点表达式或引用命名切入点;

4)配置文件需要使用<aop:aspectj-autoproxy/>来开启注解风格的@AspectJ支持;

5)需要将切面注册为Bean,如“aspect”Bean;

6)测试代码完全一样。

二、后置返回通知:使用org.aspectj.lang.annotation 包下的@AfterReturning注解声明;

    @AfterReturning(
    value="切入点表达式或命名切入点",
    pointcut="切入点表达式或命名切入点",
    argNames="参数列表参数名",
    returning="返回值对应参数名")  

value指定切入点表达式或命名切入点;

pointcut同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

argNames与Schema方式配置中的同义;

returning与Schema方式配置中的同义。

@AfterReturning(
    value="execution(* cn.javass..*.sayBefore(..))",
    pointcut="execution(* cn.javass..*.sayAfterReturning(..))",
    argNames="retVal", returning="retVal")
public void afterReturningAdvice(Object retVal) {
    System.out.println("===========after returning advice retVal:" + retVal);
} 

其中测试代码与Schema方式几乎一样,在此就不演示了

 

三、后置异常通知:使用org.aspectj.lang.annotation 包下的@AfterThrowing注解声明

    @AfterThrowing (
    value="切入点表达式或命名切入点",
    pointcut="切入点表达式或命名切入点",
    argNames="参数列表参数名",
    throwing="异常对应参数名")
       

value指定切入点表达式或命名切入点;

pointcut同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

argNames与Schema方式配置中的同义;

throwing与Schema方式配置中的同义。

@AfterThrowing(
    value="execution(* cn.javass..*.sayAfterThrowing(..))",
    argNames="exception", throwing="exception")
public void afterThrowingAdvice(Exception exception) {
    System.out.println("===========after throwing advice exception:" + exception);
} 

其中测试代码与Schema方式几乎一样,在此就不演示了

四、后置最终通知:使用org.aspectj.lang.annotation 包下的@After注解声明;

@After (
value="切入点表达式或命名切入点",
argNames="参数列表参数名") 

value指定切入点表达式或命名切入点;

argNames与Schema方式配置中的同义;

    @After(value="execution(* cn.javass..*.sayAfterFinally(..))")
    public void afterFinallyAdvice() {
        System.out.println("===========after finally advice");
    }  

其中测试代码与Schema方式几乎一样,在此就不演示了

五、环绕通知:使用org.aspectj.lang.annotation 包下的@Around注解声明;

    @Around (
    value="切入点表达式或命名切入点",
    argNames="参数列表参数名")  

value指定切入点表达式或命名切入点;

argNames与Schema方式配置中的同义;

@Around(value="execution(* cn.javass..*.sayAround(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("===========around before advice");
    Object retVal = pjp.proceed(new Object[] {"replace"});
    System.out.println("===========around after advice");
    return retVal;
} 

其中测试代码与Schema方式几乎一样,在此就不演示了,如果需要请参考AopTest.java中的annotationAroundAdviceTest测试方法。

6.4.5  引入

省略

时间: 2024-10-11 22:37:28

开涛spring3(6.4) - AOP 之 6.4 基于@AspectJ的AOP的相关文章

利用基于@AspectJ的AOP实现权限控制

一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理解为在系统中,我们需要很多次重复实现的功能.比如计算某个方法运行了多少毫秒,判断用户是不是具有访问权限,用户是否已登录,数据的事务处理,日志记录等等. AOP的术语 连接点(Joinpoint) 程序执行的某个特殊位置:比如类开始初始化前,类初始化后,某个方法调用前,调用后等. 连接点 可 以 理解

开涛spring3(6.9) - AOP 之 6.9 代理机制

Spring AOP通过代理模式实现,目前支持两种代理:JDK动态代理.CGLIB代理来创建AOP代理,Spring建议优先使用JDK动态代理. JDK动态代理:使用java.lang.reflect.Proxy动态代理实现,即提取目标对象的接口,然后对接口创建AOP代理. CGLIB代理:CGLIB代理不仅能进行接口代理,也能进行类代理,CGLIB代理需要注意以下问题: 不能通知final方法,因为final方法不能被覆盖(CGLIB通过生成子类来创建代理). 会产生两次构造器调用,第一次是目

开涛spring3(6.3) - AOP 之 6.3 基于Schema的AOP

6.3  基于Schema的AOP 基于Schema的AOP从Spring2.0之后通过“aop”命名空间来定义切面.切入点及声明通知. 在Spring配置文件中,所以AOP相关定义必须放在<aop:config>标签下,该标签下可以 有<aop:pointcut>.<aop:advisor>.<aop:aspect>标签,配置顺序不可变. <aop:pointcut>:用来定义切入点,该切入点可以重用: <aop:advisor>:

[Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.

前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习. 一, AspectJ的概述: AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件. Spring为了简化自身的AOP的开发,将AspectJ拿过来作为Spring自身一个AOP的开发.

开涛spring3(6.1) - AOP 之 6.1 AOP基础

6.1.1  AOP是什么 考虑这样一个问题:需要对系统中的某些业务做日志记录,比如支付系统中的支付业务需要记录支付相关日志,对于支付系统可能相当复杂,比如可能有自己的支付系统,也可能引入第三方支付平台,面对这样的支付系统该如何解决呢? 传统解决方: 1)日志部分提前公共类LogUtils,定义“longPayBegin”方法用于记录支付开始日志,“logPayEnd”用于记录支付结果: 2)支付部分,定义IPayService接口并定义支付方法“pay”,并定义了两个实现:“PointPayS

开涛spring3(6.6) - AOP 之 6.6 通知参数

前边章节已经介绍了声明通知,但如果想获取被被通知方法参数并传递给通知方法,该如何实现呢?接下来我们将介绍两种获取通知参数的方式. 使用JoinPoint获取:Spring AOP提供使用org.aspectj.lang.JoinPoint类型获取连接点数据,任何通知方法的第一个参数都可以是JoinPoint(环绕通 知是ProceedingJoinPoint,JoinPoint子类),当然第一个参数位置也可以是JoinPoint.StaticPart类型,这 个只返回连接点的静态部分. 1) J

开涛spring3(6.8) - AOP 之 6.8 切面实例化模型

所谓切面实例化模型指何时实例化切面. Spring AOP支持AspectJ的singleton.perthis.pertarget实例化模型(目前不支持percflow.percflowbelow 和pertypewithin). singleton:即切面只会有一个实例: perthis:每个切入点表达式匹配的连接点对应的AOP对象都会创建一个新切面实例: pertarget:每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例: 默认是singleton实例化模型,Schem

开涛spring3(6.7) - AOP 之 6.7 通知顺序

如果我们有多个通知想要在同一连接点执行,那执行顺序如何确定呢?Spring AOP使用AspectJ的优先级规则来确定通知执行顺序.总共有两种情况:同一切面中通知执行顺序.不同切面中的通知执行顺序. 首先让我们看下 1) 同一切面中通知执行顺序:如图6-6所示. 图6-6 同一切面中的通知执行顺序 而如果在同一切面中定义两个相同类型通知(如同是前置通知或环绕通知(proceed之前))并在同一连接点执行时,其执行顺序是未知的,如果确实需要指定执行顺序需要将通知重构到两个切面,然后定义切面的执行顺

开涛spring3(6.2) - AOP 之 6.2 AOP的HelloWorld

6.2.1  准备环境 首先准备开发需要的jar包   org.springframework.aop-3.0.5.RELEASE.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar com.springsource.org.aopalliance-1.0.0.jar com.springsource.net.sf.cglib-2.2.0.jar 目前,项目里包是 6.2.2  定义目标类 1)定义目标接口: package lqy