8.AspectJ对AOP的实现(重点)

AspectJ实现了AOP的功能,且实现方式更为简洁,使用更为方便,而且还支持注解式开发
在Spring中使用AOP开发时,一般使用AspectJ的实现方式


一、AspectJ简介

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守java字节码规范的Class文件。


二、AspectJ的通知类型

AspectJ中常用的通知有五种类型:

  1. 前置通知
  2. 后置通知
  3. 环绕通知
  4. 异常通知
  5. 最终通知:无论程序执行是否正常,该通知都会执行。类似于try…catch中的finally代码块。

三、AspectJ的切入点表达式

AspectJ除了提供了5种通知外,还定义了专门的表达式用于指定切入点。表达式的原型是:

execution([modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
[declaring-type-pattern 全限定性类名
name-pattern(param-pattern) 方法名(参数名)
[throws-pattern] 抛出异常类型)

切入点表达式要匹配的对象就是目标方法的方法名。所以execution表达式中明显就是方法的签名。注意,表达式中加[]的部分表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:

符号意义
*0至多个任意字符
. .用在方法参数中,表示任意多个参数/用在包名后,表示当前包及其子包路径
+用在类名后,表示当前类及其子类/用在接口后,表示当前接口及其实现类

例:
execution(public * * (. .))
指定切入点为:任意公共方法

execution(* set * (. .))
指定切入名为:任何一个以“set”开始的方法

execution(* com.xyz.service. * . * (. .))
指定切入名为:定义在service包里的任意类的任意方法

execution(* com.xyz.service. . * . * (. .))
指定切入点为:定义在service包或者子包里的任意类的任意方法。". ."出现在类名中时,后面必须跟“ * ”,表示包、子包下的所有类

execution(* *.service. * . *(. .))
指定只有一级包下的service子包下所有类(接口)中所有方法为切入点

execution(* * . .service. * . * (. .)) 重点掌握
指定所有包下的service子包下所有类(接口)中所有方法为切入点

execution(* * . . ISomeService . * (. .)) 重点掌握
指定所有包下的ISomeService接口中所有方法为切入点


四、AspectJ的开发环境
  1. 导入jar包
    aopalliance.jar
    aspectjrt.jar
    aspectjweaver.jar
    spring-aop.jar
    spring-aspects.jar(spring与aspectj整合的jar包)

五、AspectJ基于注解的AOP实现
AspectJ提供了以注解方式对于AOP的实现

接口类

//主业务接口
public interface ISomeService {
    //目标方法
    void doFirst();

    //目标方法
    String doSecond();

    //目标方法
    void doThird();

}

实现类

public class SomeServiceImpl implements ISomeService {
    @Override
    public void doFirst() {
        System.out.println("执行doFirst()方法");
    }

    @Override
    public String doSecond() {
        System.out.println("执行doSecond()方法");
        return "abcde";
    }

    @Override
    public void doThird() {
        System.out.println("执行doThird()方法" + 3 / 0);
        System.out.println("执行doThird()方法");
    }
}

切面类

@Aspect //表示当前类为切面
public class MyAspect {

    @Before("execution(* *..ISomeService.doFirst(..))") //放入切入点表达式
    public void before() {
        System.out.println("执行前置通知方法");
    }

    @AfterReturning(value = "execution(* *..ISomeService.doSecond(..))",returning = "result")
    public void myAfterReturning(Object result){
        System.out.println("执行后置通知方法 result = " + result);
    }

    @Around("execution(* *..ISomeService.doSecond(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("执行环绕通知方法,目标方法执行之前");
        //执行目标方法
        Object result = pjp.proceed();
        System.out.println("执行环绕通知方法,目标方法执行之后");
        if (result != null) {
            result = ((String)result).toUpperCase();
        }
        return result;
    }

    @AfterThrowing("execution(* *..ISomeService.doThird(..))")
    public void myAfterThrowing() {
        System.out.println("执行异常通知方法");
    }

    @AfterThrowing(value = "execution(* *..ISomeService.doThird(..))", throwing = "ex")
    public void myAfterThrowing(Exception ex) {
        System.out.println("执行异常通知方法 ex = " + ex.getMessage());
    }

    @After("doThirdPointcut()")
    public void myAfter() {
        System.out.println("执行最终通知方法");
    }

    //定义了一个切入点,叫doThirdPointcut()
    @Pointcut("execution(* *..ISomeService.doThird(..))")
    public void doThirdPointcut() {}
}

xml配置

	<!--注册切面-->
    <bean id="myAspect" class="com.chen.service.MyAspect"/>

    <!--注册目标对象-->
    <bean id="someService" class="com.chen.service.SomeServiceImpl"/>

    <!--注册AspectJ的自动代理-->
    <aop:aspectj-autoproxy/>

测试及结果

public class MyTest {
    @Test
    public void test01() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        ISomeService service = (ISomeService) ac.getBean("someService");
        service.doFirst();
        System.out.println("- - - - - -");
        service.doSecond();
        System.out.println("- - - - - -");
        service.doThird();
    }
}
/*
执行前置通知方法
执行doFirst()方法
- - - - - -
执行环绕通知方法,目标方法执行之前
执行doSecond()方法
执行环绕通知方法,目标方法执行之后
执行后置通知方法 result = ABCDE
- - - - - -
执行最终通知方法
执行异常通知方法
执行异常通知方法 ex = / by zero
*/

六、AspectJ基于xml的AOP实现(重点!!!)

切面类

public class MyAspect {

    public void before() {
        System.out.println("执行前置通知方法");
    }

    public void myAfterReturning(Object result){
        System.out.println("执行后置通知方法 result = " + result);
    }

    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("执行环绕通知方法,目标方法执行之前");
        //执行目标方法
        Object result = pjp.proceed();
        System.out.println("执行环绕通知方法,目标方法执行之后");
        if (result != null) {
            result = ((String)result).toUpperCase();
        }
        return result;
    }

    public void myAfterThrowing() {
        System.out.println("执行异常通知方法");
    }

    public void myAfterThrowing(Exception ex) {
        System.out.println("执行异常通知方法 ex = " + ex.getMessage());
    }

    public void myAfter() {
        System.out.println("执行最终通知方法");
    }


}

xml配置

	<!--注册切面-->
    <bean id="myAspect" class="com.chen.service.MyAspect"/>

    <!--注册目标对象-->
    <bean id="someService" class="com.chen.service.SomeServiceImpl"/>

    <!--AOP配置-->
    <aop:config>
        <aop:pointcut id="doFirstPointcut" expression="execution(* *..ISomeService.doFirst(..))"/>
        <aop:pointcut id="doSecondPointcut" expression="execution(* *..ISomeService.doSecond(..))"/>
        <aop:pointcut id="doThirdPointcut" expression="execution(* *..ISomeService.doThird(..))"/>
        <aop:aspect ref="myAspect">
            <aop:before method="before" pointcut-ref="doFirstPointcut"/>
            <aop:after-returning method="myAfterReturning(java.lang.Object)" pointcut-ref="doSecondPointcut" returning="result"/>
            <aop:around method="myAround" pointcut-ref="doSecondPointcut"/>
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="doThirdPointcut"/>
            <aop:after-throwing method="myAfterThrowing(java.lang.Exception)" pointcut-ref="doThirdPointcut" throwing="ex"/>
            <aop:after method="myAfter" pointcut-ref="doThirdPointcut"/>
        </aop:aspect>
    </aop:config>

测试及结果

	@Test
    public void test01() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        ISomeService service = (ISomeService) ac.getBean("someService");
        service.doFirst();
        System.out.println("- - - - - -");
        service.doSecond();
        System.out.println("- - - - - -");
        service.doThird();
    }
    /*
	执行前置通知方法
	执行doFirst()方法
	- - - - - -
	执行环绕通知方法,目标方法执行之前
	执行doSecond()方法
	执行环绕通知方法,目标方法执行之后
	执行后置通知方法 result = ABCDE
	- - - - - -
	执行doThird()方法
	执行最终通知方法
	*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值