zoukankan      html  css  js  c++  java
  • Spring AOP面向切面编程

    一、AOP面向切面编程基本概念

    在软件系统中,有些行为对于绝大多数业务模块都是通用,例如日志管理、权限管理、事物管理等,在不同的业务模块中,我们很有可能会编写相同的代码来完成一个共同的功能点,这就造成了极大的代码冗余,和较高的维护成本,同时业务代码与特殊功能代码耦合交融到了一起,不利于系统的构建与开发。

    AOP:Aspect Oriented Programming ,面向切面编程,就是将众多的业务模块进行横向切割,提炼抽取其中的相同功能代码进行单独编程,已达到业务代码与非业务功能代码的隔离,从而使得业务逻辑部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。

    AOP最重要的功能:高内聚,低耦合

    二、Spring AOP的基本概念

    AOP把软件系统分成两个部分:核心关注点和横切关注点,业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点,描述横切关注点的具体内容称之为切面。

    描述切面的常用概念是:通知(Advice)切点(Pointcut)连接点(JoinPoint)、目标对象(Target)、织入(Weaving)、代理(Proxy)、切面(aspect)

    • 通知:定义了切面执行的代码内容是什么,在什么时候执行。
    • 切点:一个或多个连接点的集合,通常使用具体的类名和方法名来指定这些切点,或是使用正则表达式来定义匹配的类和方法来指定这些切点。
    • 连接点:在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时、抛出异常时、修改一个字段时,切面代码可以利用连接点插入到应用的正常流程之中,并执行切面代码。
    • 目标对象:被代理对象。
    • 织入:将通知应用到切入点的过程。
    • 代理:将通知织入到目标对象之后,形成代理对象。
    • 切面:切面是通知和切点的结合,通知和切点共同定义了关于切面的全部内容,切面内容是什么,在什么时候执行,在什么地方执行。(切点+通知)。

    Spring中实现AOP原理:

    • 动态代理:被代理对象必须实现接口才能实现代理对象,如果没有接口将不能使用动态代理技术。

    • cglib代理:第三方的代理技术,可以对任何类生成代理,代理的原理是对目标对象进行继承代理,如果目标被对象final修饰,那么该类无法被cglib代理。

    • 如果有接口优先使用动态代理。

    Spring AOP中定义了五种类型的通知:

    通知类型 描述
    Before 再切点方法执行之前,调用通知中指定的方法。
    After 再切点方法执行完成之后,调用通知中指定的方法,不管切点方法执行是否成功。
    After-returning 再切点方法成功执行之后,调用通知中指定的方法。
    After-throwing 再切点方法执行抛出异常后,调用通知中指定的方法。
    Around 通知方法包裹切点方法执行,改变切点方法中的执行逻辑

    三、Spring AOP编程

    1. 通过标签方式进行切面编程

    <!--切面配置标签块-->
    <aop:config>
        <!--切点定义,使用正则表达式来匹配连接点集合,通过id来命令切点-->
        <aop:pointcut expression="execution(* com.yingcai.service.*.*(..))" id="pointcut"/>
        <!--通知配置标签块,ref属性定义通知执行Bean-->
        <aop:aspect  ref="adviceInfo">
            <aop:before method="beforeAdvice" pointcut-ref="pointcut"/>
            <aop:after method="afterAdvice" pointcut-ref="pointcut"/>
            <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturnAdvice" pointcut-ref="pointcut"/>
            <aop:around method="aroundAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
    

    环绕通知详解:

    通过ProceedingJoinPoin类来获取操作连接点切入方法的相关信息

    获取切入方法执行类名称:

    Class executeClass = proceedingJoinPoint.getTarget().getClass();
    String className = executeClass.getName();
    

    获取切入方法名称:

    String methodName = proceedingJoinPoint.getSignature().getName();
    

    获取切入方法入参:

    Object[] args = proceedingJoinPoint.getArgs();
    

    执行切入方法内容:

    proceedingJoinPoint.proceed(args);
    

    注:环绕通知的方法格式必须与连接点方法格式相同,连接点方法有返参,环绕通知方法也必须有返参。

    实例:

        /**
         * 在业务方法的前后做处理
         *
         * @param joinPoint 是具体业务方法被封装的对象
         * @return
         */
        public Object around(ProceedingJoinPoint joinPoint) {
            String className = joinPoint.getTarget().getClass().getName();
            String method = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            logger.debug("enter=" + className + "." + method);
            logger.debug("args=" + Arrays.toString(args));
            try {
                Result result = (Result) joinPoint.proceed(args);
                logger.debug("result=" + result);
                return result;
            } catch (Throwable throwable) {
                logger.error("occur exception:", throwable);
                return new Result(null, "proceed failure");
            }
        }
    

    业务方法:

    @Service
    public class CollegeService implements IBaseService<College>{
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        public Result add(College college) {
    //        int num = 1/0;
            return new Result(true,"增加成功");
        }
    }
    

    输出日志:

    2. 使用注解方式进行切面编程

    切面注解的开启:

    <aop:aspectj-autoproxy/>
    
    • @Aspect:标注于类上,将一个类定义为切面类。

    • @Pointcut:标注于一个普通方法上,定义切点内容。

    • @Before:标注于前置通知方法之上。

    • @After:标注于后置方法之上。

    • @AfterThrowing:标注于后置失败通知方法之上。

    • @AfterReturning:标注于后置成功通知方法之上。

    • @Around:标注于环绕通知方法之上。

    实例:

    /**
     * copyright(c)2021 zbh.ALL rights Reserved
     * <p>
     * 描述:切面类
     *
     * @author zbh
     * @version 1.0
     * @date 2021/7/26
     */
    @Component
    @Aspect
    public class LogAop {
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Pointcut("execution(* com.ychs.service.*.*(..))")
        public void pc() {}
    
        /**
         * 在业务方法执行前打印日志
         */
        // @Before(value = "execution(* com.ychs.service.*.*(..))")
        @Before("pc()")
        public void before() {
            logger.debug("service method before...");
        }
    
        @After("pc()")
        public void after() {
            logger.debug("service method after...");
        }
    
        @AfterReturning("pc()")
        public void afterReturn() {
            logger.debug("service method afterReturn");
        }
    
        @AfterThrowing("pc()")
        public void afterThrowing() {
            logger.debug("service method afterThrowing");
        }
    
        /**
         * 在业务方法的前后做处理
         *
         * @param joinPoint 是具体业务方法被封装的对象
         * @return
         */
        @Around("pc()")
        public Object around(ProceedingJoinPoint joinPoint) {
            String className = joinPoint.getTarget().getClass().getName();
            String method = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            logger.debug("enter=" + className + "." + method);
            logger.debug("args=" + Arrays.toString(args));
            try {
                Result result = (Result) joinPoint.proceed(args);
                logger.debug("result=" + result);
                return result;
            } catch (Throwable throwable) {
                logger.error("occur exception:", throwable);
                return new Result(null, "proceed failure");
            }
        }
    }
    
  • 相关阅读:
    aspcms产品详情页调取相关产品
    构造函数中返回一个对象对结果有什么影响
    跨域的几种方法及案例代码
    localStorage兼容方案
    H5 拖放事件详解
    由作用域安全的构造函数想到的
    valueOf和toString的区别
    网页布局--自适应
    【MongoDB系列】简介、安装、基本操作命令
    【JavaWeb】之Servlet
  • 原文地址:https://www.cnblogs.com/zbh355376/p/14027419.html
Copyright © 2011-2022 走看看