spring aop advice注解实现的几种方式

spring的aop advice(可以理解为切面上的逻辑)用注解来实现有五种实现方式:

  1. @Before(execution) 在方法执行前拦
  2. @AfterReturning(execution)在方法正常return结束后拦截
  3. @AfterThrowing(execution) 在方法抛出异常时拦截
  4. @After(execution) 在方法结束后拦截,无论正常结束还是异常结束
  5. @Around(execution)唯一可以使用ProceedingJoinPoint参数来控制流程的advice,在方法执行前拦截,可以在切面逻辑中手动释放拦截,且可以在其后加入逻辑代码,该代码段会在方法执行后执行.

这几种方式如果同时存在 , 会有一个先后顺序,下边测试后可以从打印结果中很明显地看到,但是一般情况下,尽量避免用这种先后顺序的方式来决定切面逻辑的设计,如果切面逻辑很复杂,可以用@Around整合在一起.

注意 : “表达式(execution)” 匹配到的方法必须为interface的实现类才可以,否则会抛出以下异常:Cannot proxy target class because CGLIB2 is not available.
如果一个类实现了接口 , spring就会通过jdk自带的Proxy 和 InvocationHandler自动生成代理 , 如果没有实现接口, 需要依赖cglib包 , 以直接操作二进制码的方式 , 来生成代理代码.
可以将获取到对象的class打印出来,可以很明显看到其中有”$$EnhancerByCGLIB”的字样,它是一个代理对象.

另外 , 测试中出现一个问题 , PointCut() 无法正常调用, 后来发现是aspectjrt 版本的问题 ,因为是跟着马士兵老师的视频走的 , 所以用的spring 2.5.6 的版本 , 我用pom构建项目的, spring2.5.6中集成的aspectjrt是1.6.1 版本的 , 这个版本和jdk1.7有冲突 , 将版本更换为新版的1.8.7就好了

下边上代码:

切面类:

@Aspect
@Component
public class LogInterceptor {

    //advice 切点语法规则,方法体不执行,其他advice可以直接将该方法作为参数
    //按照该语法来执行拦截
    @Pointcut("execution(* com.pindao.nine.dao.UserDao.show* (..))")
    public void pointCut1(){
        System.out.println("this is pointCut");
    }

    //拦截在方法执行之前
    @Before("pointCut1()")
    public void before(){
        System.out.println("method start...");
    }


    //拦截在方法体执行之后,无论正常执行结束或异常结束
    @After("execution(* com.pindao.nine.dao.UserDao.show* (..))")
    public void after(){
        System.out.println("method end!");
    }

    //拦截在方法正常return之后
    @AfterReturning(value = "pointCut1()")
    public void afterReturn(){
        System.out.println("this is afterReturing pointcut!");
    }

    //拦截在方法抛出异常之后
    @AfterThrowing("pointCut1()")
    public void afterThrowing(){
        System.out.println("this is afterThrowing pointcut!");
    }

    //拦截在方法体执行之前,插入代码,需要手动释放拦截,并且可以在继续运行之后插入代码
    //ProceedingJoinPoint 参数只能在@Around下用,在其他advice下用,会抛出异常
    @Around("pointCut1()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("this is around pointcut start..!");
        //拦截结束,程序继续运行, 继续下一个拦截或者进行正常逻辑代码
        Object obj = pjp.proceed();
        System.out.println("this is around pointcut end..!");
        return obj;

    }
}

执行切面的bean():

@Component("userDao")
public class UserDaoImpl implements UserDao {
    public void showUser() {
        System.out.println("this is the real method start...");
//        int i = 1/0;
        System.out.println("this is the real method end");
        return 0;
    }
}

spring启用注解和切面配置 beans.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

       <context:annotation-config />
       <context:component-scan base-package="com.pindao.nine" />
<!--aspectj是一个面向切面的框架,spring的aop,是基于aspectj来实现的-->       
       <aop:aspectj-autoproxy />

</beans>

手动启动spring容器,调用showUser()方法:

@Test
public void testShowUserDao() throws Exception {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    UserDao userDao = (UserDao) context.getBean("userDao");
    int result = userDao.showUser();
    System.out.println(result);
}

执行结果:
1. 正常流程:

method start...
this is around pointcut start..!
this is the real method start...
this is the real method end
method end!
this is afterReturing pointcut!
this is around pointcut end..!
0

2.方法体抛出异常流程:

method start...
this is around pointcut start..!
this is the real method start...
method end!
this is afterThrowing pointcut!
java.lang.ArithmeticException: / by zero ......

下边是maven依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>2.5.6</version>
    <exclusions>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>2.5.6</version>
    <exclusions>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.7</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.7</version>
</dependency>
<!-- cglib通过二进制的方式生成代理类 -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.0</version>
</dependency>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值