zoukankan      html  css  js  c++  java
  • spring AOP-切面编程

    首先学习aop切面的顺序:

    • 前置通知:(Before advice)表明在连接点执行之前执行的动作。

      @Before("controllerLog()")

    • 环绕通知:(Around Advice) 环绕可以看作是包含前置通知和后置通知的一个通知,先了解,后面具体理解。

      @Around("controllerLog()")

    • 后置通知:(After returning advice)在某个连接点完成后通知,比如一个方法没有抛出任何异常,正常返回【第一个参数还是指定切点,第二个参数指定的是返回值】
      @AfterReturning(value = "controllerLog()",returning = "obj")
    • 异常通知:(After throwing advice) 在方法异常推出时候执行的通知。【这里和上面的后置通知差不多,不过第二个参数是一个异常类型对象】
      @AfterThrowing(value = "controllerLog()", throwing = "ex")
    • 最终通知:(After advice) 在连接点退出时候执行的通知。不论是正常退出还是异常退出。

       @After("controllerLog()")

    正常返回:

    异常返回:

     

    学习切面编程的时候学到两种方式。下面阐述一下

    公共部分

    引入aop包

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>

    1.直接配置类路径进行切面编程

    package com.whalecloud.uip.client.loggeraspect;
    
    import com.alibaba.fastjson.JSONObject;
    import com.whalecloud.common.cfg.Constants;
    import com.whalecloud.common.component.ExteParamObtain;
    import com.whalecloud.common.domain.CfgReqInfo;
    import com.whalecloud.common.domain.ReqServiceBean;
    import com.whalecloud.common.result.IomResult;
    import com.whalecloud.common.util.BeetlTemplateUtil;
    import com.whalecloud.common.util.MapToXmlUtils;
    import com.whalecloud.uip.client.feign.DataSourceFeignClient;
    import org.apache.commons.collections.MapUtils;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.DefaultParameterNameDiscoverer;
    import org.springframework.core.ParameterNameDiscoverer;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    
    
    @Aspect
    @Component
    public class WebLogAspect {
    
        private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
    
    
        /**
         * Service层切点
         */
        @Pointcut("execution(* com.whalecloud.uip.client.service.ToRestService.invokeRestReq(com.whalecloud.common.domain.ReqServiceBean)) || execution(* com.whalecloud.uip.client.service.ToWebserviceService.invokeWebServiceReq(com.whalecloud.common.domain.ReqServiceBean))")
        public void controllerAspect() {
        }
    
        /**
         * 配置Service环绕通知,使用在方法aspect()上注册的切入点
         *
         * @param point 切点
         * @return
         * @throws Throwable
         */
        @Around("controllerAspect()")
        public Object doAround(ProceedingJoinPoint point) throws Throwable {/*获取方法的参数值*/
            Map<String, Object> paramMap = getParam(point);
            ReqServiceBean reqServiceBean = (ReqServiceBean) MapUtils.getObject(paramMap, "reqServiceBean");
          /*获取结果*/
    result = (IomResult)point.proceed();return result; } /** * 获取参数的列表 * * @param joinPoint * @return */ private Map<String, Object> getParam(ProceedingJoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); String[] parameterNames = pnd.getParameterNames(method); Map<String, Object> paramMap = new HashMap<>(); assert parameterNames != null; for (int i = 0; i < parameterNames.length; i++) { paramMap.put(parameterNames[i], args[i]); } return paramMap; } }

    proceedingJoinPoint  可以拿到入参值和返回值。进行切面操作。

    2.根据注解进行切面编程

    1.先写个注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface OperationLog {
        String type();
    }

    2.AOP配置

    @Aspect
    @Component
    public class AOPConfig {
     
        @Around(value = "@annotation(OperationLog)")
        public Object around(ProceedingJoinPoint proceedingJoinPoint){
            System.out.println("方法环绕begin...参数:"+Arrays.toString(proceedingJoinPoint.getArgs()));
            try {
                Object ret= proceedingJoinPoint.proceed();
                System.out.println("方法环绕end...结果:"+ret);
                return ret;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return null;
        }
     
        @Before(value = "@annotation(OperationLog)")
        public void doBefore(JoinPoint joinPoint){
            ServletRequestAttributes requestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest req= requestAttributes.getRequest();
            System.out.println("uri:"+req.getRequestURI());
            System.out.println("执行方法前 : " + Arrays.toString(joinPoint.getArgs()));
        }
     
        @After(value = "@annotation(OperationLog)")
        public void after(JoinPoint joinPoint){
            System.out.println("执行方法后:"+ Arrays.toString(joinPoint.getArgs()));
        }
     
        @AfterReturning(pointcut = "@annotation(OperationLog)",returning = "ret")
        public void doAfterReturning(Object ret){
            System.out.println("方法的返回值 : " + ret);
        }
     
        @AfterThrowing(pointcut = "@annotation(OperationLog)",throwing = "ex")
        public void AfterThrowing(JoinPoint joinPoint,Throwable ex){
            System.out.println("方法执行异常 : " + ex);
        }
    }

    3.服务类

    @RequestMapping("/aop")
    @RestController
    public class AOPCtrl {
     
        @Autowired
        private MessageService messageService;
     
        @RequestMapping(value = "/test",method = RequestMethod.GET)
        public String test(){
            return messageService.sendMessage("xiaoming",29);
        }
    }
     
    @Service
    public class MessageService {
     
        @OperationLog(type = "sendMessage")
        public String sendMessage(String name,int age){
            return "this person: "+name+" age: "+age;
        }
    }

    4.返回结果

    运行结果:
    方法环绕begin...参数:[xiaoming, 29]
    uri:/aop/test
    执行方法前 : [xiaoming, 29]
    方法环绕end...结果:this person: xiaoming age: 29
    执行方法后:[xiaoming, 29]
    方法的返回值 : this person: xiaoming age: 29
  • 相关阅读:
    [原创]Android插件化的一种实现
    [原创]HierarchyView的实现原理和Android设备无法使用HierarchyView的解决方法
    使用linux mint 安装无线网卡驱动
    Ubuntu下U盘变成只读的解决方法
    在Android源码中查找Java代码中native函数对应的C++实现
    Android Training Caching Bitmaps 翻译
    [转]获取app的内部储存路径
    [转]sudo找不到命令:修改sudo的PATH路径
    [转]CDN(内容分发网络)技术原理
    电视的应用开发注意事项[持续更新]
  • 原文地址:https://www.cnblogs.com/linhongwenBlog/p/11892160.html
Copyright © 2011-2022 走看看