Spring之AOP配置实现及参数设置

配置(基于注解)

1. 引入aop相关的jar包。基于注解要多引入的两个包aspectjweaver.jar或aspectjrtweaver.jar,这个2个包中才有Aspect这个注解。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>

<!-- aop注解相关包 --> <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.2</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.2</version>
</dependency>

2. spring-mvc.xml中引入aop名称空间

<?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:mvc="http://www.springframework.org/schema/mvc"
    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/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
3. spring-mvc.xml中开启aop注解扫描,如下配置所示:
<!-- 启动自动扫描 -->
<context:component-scan base-package="vip.chencheng.*" />

<!--使用xml配置aop-->
<aop:aspectj-autoproxy proxy-target-class="true" />

使用(基于注解)

spring使用AspectJ注解来声明通知方法,注解参数如下:

  • @After: 通知方法会在目标方法返回或抛出异常后调用
  • @AfterReturning: 通知方法会在目标方法返回后调用
  • @AfterThrowing: 通知方法会在目标方法抛出异常后调用
  • @Around: 通知方法会将目标方法封装起来
  • @Before: 通知方法会在目标方法调用之前执行
本文转自:https://www.cnblogs.com/parryyang/p/5881523.html
新加评论 评论标题:

文章评论

    注解实例

        2019-02-25    
    修改 删除
    package vip.chencheng.aop;
    
    import java.util.Arrays;
    import java.util.List;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    /**
     * 
     * @author chen cheng
     * 注解方式声明aop
     * 1.用@Aspect注解将类声明为切面
     * 	如果用@Component("")注解注释为一个bean对象,那么就要在spring配置文件中开启注解
     * 	扫描,<context:component-scan base-package="com.cjh.aop2"/>否则要在spring配置文件中声明一个bean对象
     * 
     * 2.在切面需要实现相应方法的前面加上相应的注释,也就是通知类型。
     * 3.此处有环绕通知,环绕通知方法一定要有ProceedingJoinPoint类型的参数传入,然后执行对应的proceed()方法,环绕才能实现。
     */
    
    @Component
    @Aspect
    public class SleepHelper {
     
        public SleepHelper(){
            
        }
        
        /**
         * 定义一个方法,用于声明切入点表达式,方法中一般不需要添加其他代码
         * 使用@Pointcut声明切入点表达式
         * 后面的通知直接使用方法名来引用当前的切点表达式;如果是其他类使用,加上包名即可
         */
        @Pointcut("execution(* vip.chencheng.controller.UrlController.*(..))")
        public void declearJoinPointExpression(){}
        
        /**
         * 前置通知
         * @param joinPoint
         *
         * 前置通知(注解中的sayings()方法,其实就是上面定义pointcut切点注解所修饰的方法名,那只是个代理对象,不需要写具体方法,
         * 相当于xml声明切面的id名,如下,相当于id="embark",用于供其他通知类型引用)
         * <aop:config>
            <aop:aspect ref="mistrel">
                <!-- 定义切点 -->
                <aop:pointcut expression="execution(* vip.chencheng.controller.UrlController.*(..))" id="declearJoinPointExpression"/>
                <!-- 声明前置通知 (在切点方法被执行前调用) -->
                <aop:before method="beforMethod" pointcut-ref="declearJoinPointExpression"/>
                <!-- 声明后置通知 (在切点方法被执行后调用) -->
                <aop:after method="afterMethod" pointcut-ref="declearJoinPointExpression"/>
            </aop:aspect>
           </aop:config>
         */
        @Before("declearJoinPointExpression()") //该标签声明次方法是一个前置通知:在目标方法开始之前执行
        public void beforMethod(JoinPoint joinPoint){
            String methodName = joinPoint.getSignature().getName();
            List<Object> args = Arrays.asList(joinPoint.getArgs());
            System.out.println("this method "+methodName+" begin. param<"+ args+">");
        }
        
        /**
         * 后置通知(无论方法是否发生异常都会执行,所以访问不到方法的返回值)
         * @param joinPoint
         */
        @After("declearJoinPointExpression()")
        public void afterMethod(JoinPoint joinPoint){
            String methodName = joinPoint.getSignature().getName();
            System.out.println("this method "+methodName+" end.");
        }
        
        /**
         * 返回通知(在方法正常结束执行的代码)
         * 返回通知可以访问到方法的返回值!
         * @param joinPoit
         */
        @AfterReturning(value="declearJoinPointExpression()",returning="result")
        public void afterReturnMethod(JoinPoint joinPoint,Object result){
            String methodName = joinPoint.getSignature().getName();
            System.out.println("this method "+methodName+" end.result<"+result+">");
        }
        
        /**
         * 异常通知(方法发生异常执行的代码)
         * 可以访问到异常对象;且可以指定在出现特定异常时执行的代码
         * @param joinPoint
         * @param ex
         */
        @AfterThrowing(value="declearJoinPointExpression()",throwing="ex")
        public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
            String methodName = joinPoint.getSignature().getName();
            System.out.println("this method "+methodName+" end.ex message<"+ex+">");
        }
        
        /**
         * 环绕通知(需要携带类型为ProceedingJoinPoint类型的参数)
         * 环绕通知方法一定要有ProceedingJoinPoint类型的参数传入,然后执行对应的proceed()方法,环绕才能实现。
         * 环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin 类型的参数可以决定是否执行目标方法
         * 且环绕通知必须有返回值,返回值即目标方法的返回值
         * @param joinPoint
         */
        @Around(value="declearJoinPointExpression()")
        public Object aroundMethod(ProceedingJoinPoint point){
            
            Object result = null;
            String methodName = point.getSignature().getName();
            try {
                //前置通知
                System.out.println("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
                //执行目标方法
                result = point.proceed();
                //返回通知
                System.out.println("The method "+ methodName+" end. result<"+ result+">");
            } catch (Throwable e) {
                //异常通知
                System.out.println("this method "+methodName+" end.ex message<"+e+">");
                throw new RuntimeException(e);
            }
            //后置通知
            System.out.println("The method "+ methodName+" end.");
            return result;
        }
        
    }

    aop中获取及修改增强方法中的参数

        2019-02-25    
    修改 删除

    只能用在环绕通知中

    • 获取参数:Object[] args = point.getArgs();
    • 修改参数:调用环绕增强(Around)中的point.proceed(args)方法,就可以修改传进来的参数了。相当于重新传了一份参数进去。
    //获取方法名
    String methodName = point.getSignature().getName();
    //获取参数名的一个数组
    String[] parameterName = ((MethodSignature)point.getSignature()).getParameterNames();
    
    //将数字转化为list. Arrays.asList
    //该方法将数组与列表链接起来,当更新其中之一时,另一个自动更新
    //不适用于基本数据类型。不支持add和remove方法
    List<String> paramNameList = Arrays.asList(parameterName);
    
    //获取传入的参数,和上面参数名顺序一致
    Object[] args = point.getArgs();
    
    //遍历参数名及参数值
    for(int i =0; i< parameterName.length; i++) {
        System.out.println(parameterName[i] + "参数值:" + arg[i]);
    }
    
    //获取指定参数名的参数值
    args[paramNameList.indexOf("zt")] );
    
    //修改某一参数值
    args[0]="修改的参数值";
    //将修改后的参数值传入到增强的方法中
    point.proceed(args);

    aop修改方法的返回值 或者 跳过增强方法执行

        2019-02-25    
    修改 删除

    环绕通知中不执行 result = point.proceed(args); 这样就跳过增强方法执行。

    每个环绕通知都有一个返回值。可以修改上述result值,或者直接定义新的返回值作为争强方法的返回

    通过切断ProceedingJoinPoint能够获取到的信息

        2019-02-25    
    修改 删除

    加入定义切点为joinPoint,异常为ex


    类名 joinPoint.getTarget().getClass().getName()

    方法名 joinPoint.getSignature().getName()

    异常通知 ex.getMessage()

    参数 joinPoint.getArgs()

配置(基于注解)
使用(基于注解)
评论列表
注解实例
aop中获取及修改增强方法中的参数
aop修改方法的返回值 或者 跳过增强方法执行
通过切断ProceedingJoinPoint能够获取到的信息