1.切面

作者: 小竹猫 | 来源:发表于2018-12-22 18:47 被阅读0次

    在类上使用 @Aspect 注解 使之成为切面类

    public class CheckAspect {
        //前置通知,在方法执行前通知
        @Before("execution(* com.igeek.service.impl.ClientServiceImpl.getAll(..))")
        public void checkBeforeLog(JoinPoint joinpoint){
            System.out.println("我是验证切面的前置通知"+joinpoint);
        }
    }
    
    • @Before 标示前置通知 。指的意思是 在特定位置之前 去执行该方法 。
    • 通知 其实就是切面类中一个具体的方法 。
    • 使用前置通知注解。 在目标方法开始之前执行。
      execution
      JoinPoint 标示连接点 。
    com.igeek.service.impl.ClientServiceImpl.getAll(..))")
    

    可以使用AspectJ表达式,对目标方法进行抽象概括。

    • 第一个* 表示匹配所有访问修饰符 以及所有返回值类型的方法
      第二个* 表示当前包下所有的类
      第三个* 表示所有的方法名称
      .. 表示匹配任意多个参数。
      (String,.. )表示匹配第一个参数为String类型的方法,..表示匹配任意数量任意类型的参数。
      String,String 表示匹配参数为两个字符串的方法。

    如果调用的同一个类的某个方法,不想重复的写路径,也可以进行封装,例:

    @Pointcut("execution(* com.igeek.service.impl.*.*(..))")
        public void declareRepeatJoinPointExpression(){
            
        }
    

    前置通知

    @Before("declareRepeatJoinPointExpression()")
            public void beforeLog(JoinPoint joinpoint){
                //通过连接点对象可以获得调用目标方法的名称以及参数。
                //获得方法名称。    能拿到你要调用的方法的名字 。
                String method = joinpoint.getSignature().getName();
                //获得调用方法时传递的参数。
                List arguments = Arrays.asList(joinpoint.getArgs());
                //System.out.println("前置日志。。。调用了:"+method+"方法,参数是:"+arguments);
                System.out.println("前置日志。");
            }
    

    后置通知,注:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。 需要使用返回通知。。。

    @After("declareRepeatJoinPointExpression()")
            public void afterLog(JoinPoint joinpoint){
                String method = joinpoint.getSignature().getName();
                List arguments = Arrays.asList(joinpoint.getArgs());
                System.out.println("后置日志 。");
            }
    

    返回通知,注:返回通知 ,其实跟后置通知一样 。都是在目标方法执行完之后 才会被执行

    
    @AfterReturning(value="execution(* com.igeek.service.impl.*.*(..))",returning="sb")
    //注:returning="sb"  名字  要跟参数列表中  Object 对象的名称一致 ,不然产生异常。
            public void testAfterReturning(JoinPoint joinpoint,Object sb){
                String method = joinpoint.getSignature().getName();
                System.out.println("我是返回通知  。 我在目标方法核心业务执行完才会执行 。"+sb);
            }
    

    异常通知 。

    @AfterThrowing(value="execution(* com.igeek.service.impl.*.count())",throwing="e")
            public void testAfterThrowing(JoinPoint joinpoint,Exception e){
                System.out.println("我是异常通知 ,我是在方法产生异常后执行的。"+e);
            }
    

    环绕通知 .跟动态代理的代码很像。

    @Around("execution(* com.igeek.service.impl.ClientServiceImpl.getAll())")
            public void around(ProceedingJoinPoint pjp){
                //声明一个Object 对象 用来表示 目标方法的返回值 。
                Object result = null;
                String methodName=pjp.getSignature().getName();
                try {
                    System.out.println("我是前置日志 。。。"+methodName);
                    result=pjp.proceed();
                    System.out.println("我是返回通知 。。。"+result+methodName);
                    //Throwable 所有异常类跟错误类的父类 。Exception  Error ...
                } catch (Throwable e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    System.out.println("异常通知,产生异常的时候 会执行catch 里面的代码 。");
                }//调用proceed() 表示执行被代理类的目标方法。
                System.out.println("我是后置通知 。。。"+result+methodName); 
                
            }
    

    如果在方法前添加了注解,那么在xml文件中,只需添加如下代码:

    <!-- 自动扫描组件 -->
        <context:component-scan base-package="com/igeek"></context:component-scan>
            <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 
    

    当然也利用xml语句指定方法

    <aop:config>
            <aop:pointcut expression="execution(* com.igeek.service.impl.*.*(..))" id="pointcut"/>
            <aop:aspect ref="loggingAspect" order="1">
                <aop:around method="around" pointcut-ref="pointcut"/>
            </aop:aspect>
        </aop:config> 
    
    public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("springaop.xml");
            ClientService bean = (ClientService)ac.getBean("clientService");
            List all = bean.getAll();
            
        }
    

    输出结果:

    我是前置日志 。。。getAll
    核心业务  getAll执行完毕...
    我是返回通知 。。。[我是敖冠海叔叔]getAll
    我是后置通知 。。。[我是敖冠海叔叔]getAll
    

    所有类型的方法

    @Before("declareRepeatJoinPointExpression()")
    public void beforeLog(JoinPoint joinpoint){
                //通过连接点对象可以获得调用目标方法的名称以及参数。
                //获得方法名称。    能拿到你要调用的方法的名字 。
                String method = joinpoint.getSignature().getName();
                //获得调用方法时传递的参数。
                List arguments = Arrays.asList(joinpoint.getArgs());
                //System.out.println("前置日志。。。调用了:"+method+"方法,参数是:"+arguments);
                System.out.println("前置日志。");
            }
            ///注意:后置通知即使方法异常也会成功执行,但是后置通知无法拿到目标方法的返回结果。 需要使用返回通知。。。
            @After("declareRepeatJoinPointExpression()")
            public void afterLog(JoinPoint joinpoint){
                String method = joinpoint.getSignature().getName();
                List arguments = Arrays.asList(joinpoint.getArgs());
                System.out.println("后置日志 。");
            }
            //注意:返回通知 ,其实跟后置通知一样  。都是在目标方法执行完之后 才会被执行  。
            //returning="sb"  名字  要跟参数列表中  Object 对象的名称一致 ,不然产生异常。
            //返回通知 :  xml   注解 。
            //@AfterReturning(value="execution(* com.igeek.service.impl.*.*(..))",returning="sb")
            public void testAfterReturning(JoinPoint joinpoint,Object sb){
                //
                String method = joinpoint.getSignature().getName();
                System.out.println("我是返回通知  。 我在目标方法核心业务执行完才会执行 。"+sb);
            }
            
            //异常通知 。
            //@AfterThrowing(value="execution(* com.igeek.service.impl.*.count())",throwing="e")
            public void testAfterThrowing(JoinPoint joinpoint,Exception e){
                System.out.println("我是异常通知 ,我是在方法产生异常后执行的。"+e);
            }
    
            //环绕通知 。   跟动态代理的代码很像。
    @Around("execution(* com.igeek.service.impl.ClientServiceImpl.getAll())")
            public void around(ProceedingJoinPoint pjp){
                //声明一个Object 对象 用来表示 目标方法的返回值 。
                Object result = null;
                String methodName=pjp.getSignature().getName();
                try {
                    System.out.println("我是前置日志 。。。"+methodName);
                    result=pjp.proceed();
                    System.out.println("我是返回通知 。。。"+result+methodName);
                    //Throwable 所有异常类跟错误类的父类 。Exception  Error ...
                } catch (Throwable e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    System.out.println("异常通知,产生异常的时候 会执行catch 里面的代码 。");
                }//调用proceed() 表示执行被代理类的目标方法。
                System.out.println("我是后置通知 。。。"+result+methodName); 
                
            }
            
    }
    

    相关文章

      网友评论

          本文标题:1.切面

          本文链接:https://www.haomeiwen.com/subject/ilyvkqtx.html