zoukankan      html  css  js  c++  java
  • aop的应用和简单原理

    实现过程:

    1.pom引包

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

    2.写你的aspect

    @Aspect
    @Component
    public class InlogAspect {
    
        @Autowired
        private PipeInLogMapper pipeInLogMapper;
    
        /**
         * 定义切点 @Pointcut
         * 在注解的位置切入代码
         */
        @Pointcut("execution(* com.zytcft.pipe.server.controller.Zytc*.*(..))")
        public void logPointCut() {
            System.out.println("切面已进入");
        }
    
        @Around("logPointCut()")
        public void saveSysLog(ProceedingJoinPoint joinPoint) throws Throwable {
            //前置操作
            //保存日志
            PipeInLog log = new PipeInLog();
            //从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
            //获取方法的注解
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            //根据注解获取value
            log.setInterfaceName(apiOperation.value());
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            //获取请求的方法名
            String methodName = method.getName();
            log.setInterfaceCode(className + "." + methodName);
            //请求的参数
            Object[] paramsArray = joinPoint.getArgs();
            //将参数所在的数组转换成json
            String params = JSON.toJSONString(paramsArray[0]);
            log.setInputParam(params);
            //将参数所在的数组转换成json
            JSONObject jsonObject = JSONObject.parseObject(params);
            String flowId = jsonObject.getString("flowId");
            log.setFlowId(flowId);
            String contractId = jsonObject.getString("contractId");
            log.setContractId(contractId);
            //request 和 response 留着用
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
            //通过这获取到方法的所有参数名称的字符串数组
            String[] parameterNames = signature.getParameterNames();
            log.setStatus("0");
            try {
                //让目标方法执行之后的就是后置行为了
                Response reslut = (Response) joinPoint.proceed();
                boolean isSuccess = reslut.isSuccess();
                if (isSuccess) {
                    log.setStatus("1");
                } else {
                    log.setStatus("9");
                }
            } catch (Exception e) {
                log.setException(e.getMessage());
            } finally {
                pipeInLogMapper.insert(log);
            }
        }
    }

    还有其他的行为:

    @AfterThrowing(pointcut = "webPointcut()", throwing = "e")//切点在webpointCut()
        public void handleThrowing(JoinPoint joinPoint, Exception e) {//controller类抛出的异常在这边捕获}
    @AfterReturning(value = "execution(* com.zy.test.controller.*.*(..)))", returning = "returnVal")
        public void returnProcess(JoinPoint joinPoint, Object returnVal) {}
    @Before("execution(* com.zy.test.controller.*.*(..))")
        public void beforeProcess(JoinPoint joinPoint) {}

    注意事项:

    如果想要获取异常就必须让异常抛出 如果在目标方法体异常被捕获 则无法记录异常信息

    类上必须加 @Aspect @Component 注解  因为需要通过类路径扫描自动检测它们,就像任何其他Spring管理bean一样,因此在启动类要使用@ComponentScan对其进行扫描

    @ComponentScan(basePackages = {"com.zytcft.kernel","com.alibaba.cola","com.zytcft.pipe.server"})
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }

    @Aspect:作用是把当前类标识为一个切面供容器读取
    @Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。
    @Around:环绕增强,相当于MethodInterceptor
    @AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行
    @Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有
    @AfterThrowing:异常抛出增强,相当于ThrowsAdvice
    @After: final增强,不管是抛出异常或者正常退出都会执行

    AOP原理

    AOP(这里的AOP指的是面向切面编程思想,而不是Spring AOP)主要的的实现技术主要有Spring AOP和AspectJ。
    1、AspectJ的底层技术。
           AspectJ的底层技术是静态代理,即用一种AspectJ支持的特定语言编写切面,通过一个命令来编译,生成一个新的代理类,该代理类增强了业务类,这是在编译时增强,相对于下面说的运行时增强,编译时增强的性能更好。
    2、Spring AOP
           Spring AOP采用的是动态代理,在运行期间对业务方法进行增强,所以不会生成新类,对于动态代理技术,Spring AOP提供了对JDK动态代理的支持以及CGLib的支持。
           JDK动态代理只能为接口创建动态代理实例,而不能对类创建动态代理需要获得被目标类的接口信息(应用Java的反射技术),生成一个实现了代理接口的动态代理类(字节码),再通过反射机制获得动态代理类的构造函数,利用构造函数生成动态代理类的实例对象,在调用具体方法前调用invokeHandler方法来处理。
           CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类。
           但是Spring AOP基于注解配置的情况下,需要依赖于AspectJ包的标准注解,但是不需要额外的编译以及AspectJ的织入器,而基于XML配置不需要。

  • 相关阅读:
    【整理】close 和 shutdown 的原理
    【理解】 Error 10053和 Error 10054
    【转载】 socket recv 和 read
    【转载】socket 的 connect、listen、accept 和全连接队列、半连接队列的原理
    【原创】MySQL 生产环境备份还原
    【原创】【问题记录】系统管理员设置了系统策略,禁止此安装的最终解决办法
    【原创】rabbitmq 学习
    mvc, web mvc, spring web mvc 区别
    Spring 读取配置文件的俩种方式
    移动端web开发技巧和常见问题
  • 原文地址:https://www.cnblogs.com/xcgShare/p/12058651.html
Copyright © 2011-2022 走看看