ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

AOP spring boot 使用AOP面向切面编程

2022-08-22 20:34:03  阅读:186  来源: 互联网

标签:匹配 service spring void boot Pointcut AOP 类型 public


 

image

  • 关于AOP

    • AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。 OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候, OOP则显得无能为力。OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能,日志代码往往水平地散布在所有对象 层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处 的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

    • AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到 一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封 装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象” 是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部 的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

    • 使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分 是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的 作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思 想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

    • 实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行; 二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

  • AOP使用场景

    • Authentication 权限
    • Caching 缓存
    • Context passing 内容传递
    • Error handling 错误处理
    • Lazy loading 懒加载
    • Debugging  调试
    • logging, tracing, profiling and monitoring 记录跟踪 优化 校准
    • Performance optimization 性能优化
    • Persistence  持久化
    • Resource pooling 资源池
    • Synchronization 同步
    • Transactions 事务
  • Spring AOP实战使用

package cn.timebusker.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

import cn.timebusker.utils.DateUtil;

/**
 * 面向切面编程 主要功能:日志记录、性能统计、安全控制、事务处理、异常处理等等
 */
@Component
@Aspect
//使用 order对多个切面进行排序,参数越小,越在前
@Order(1)
public class LoggerHandlerAop {

    private final static Logger logger = LoggerFactory.getLogger(LoggerHandlerAop.class);

    /**
     * AOP切面中的同步问题:用于监控业务处理性能
     */
    ThreadLocal<Long> startTime = new ThreadLocal<>();

// ==========================================================匹配切点表达式========================================================================================
/**
 * 一、execution(方法表达式)
 * 1、匹配方法时,只能匹配到实现类,匹配到接口类不能成功
 * 2、匹配方法执行
 */
    // 匹配cn.timebusker.service包及子包下的任何方法执行
    @Pointcut(value="execution(* cn.timebusker.service.*.*(..))")
    public void log1() {
    }
    
    // 匹配任何包下的service包及子包下的任何方法执行(该模式只能匹配到一级的子包,多级子包不适用)
    @Pointcut(value="execution(* *..service.*.*(..))")
    public void log2() {
    }
    
    // 匹配任何包下的service包及子包下的任何方法执行(该模式能匹配到任何多级的子包下的方法执行)
    @Pointcut(value = "execution(* *..service..*(..))")
    public void log3() {
    }
    
    // 匹配返回值类型为java.lang.String的任何包下的service包及子包下的方法执行
    @Pointcut(value = "execution(java.lang.String *..service..*(..))")
    public void log4() {
    }
    
    // 匹配返回值类型为int的任何包下的service包及子包下的方法执行
    @Pointcut(value = "execution(int *..service..*(..))")
    public void log5() {
    }
    
    // 匹配任何返回值类型的cn.timebusker包及任何子包下的以add开头的参数为Strign类型的方法执行
    @Pointcut(value = "execution(* cn.timebusker..add*(String))")
    public void log6() {
    }
    
    // 匹配 OR、AND
    @Pointcut(value = "execution(* cn.timebusker.service.*.add*(int))")
    public void log7() {
    }
    
    // 匹配 OR、AND、
    @Pointcut(value = "execution(* cn.timebusker.service.*.add*(int)) OR execution(* cn.timebusker..add*(String))")
    public void log8() {
    }
    
/**
 * 二、within(类型表达式)
 * 1、匹配类型时,只能匹配到实现类,匹配到接口类不能成功
 * 2、匹配指定类型内的方法执行;
 */
    // 匹配指定类型内的方法执行--只能匹配类型
    @Pointcut(value = "within(cn.timebusker.service.order.Impl.OrderInfoServiceImpl)")
    public void logw1() {
    }
    
    // 匹配指定类型内的方法执行(包下所有的类)
    @Pointcut(value = "within(cn.timebusker.service.order.Impl.*)")
    public void logw2() {
    }

/**
 * 三、this(类型全限定名)
 * 1、可以直接匹配接口类型完成  类型全名限定匹配
 * 2、注意是AOP代理对象的类型匹配,这样就可能包括引入接口方法也可以匹配;注意this中使用的表达式必须是类型全限定名,不支持通配符
 */
    // 匹配指定类型内的方法执行(包下所有的类)
    @Pointcut(value = "this(cn.timebusker.service.order.OrderInfoService)")
    public void logt1() {
    }
    
/**
* 四、target(类型全限定名)--匹配当前目标对象类型的执行方法
* 1、可以直接匹配接口类型完成  类型全名限定匹配
* 2、注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;注意target中使用的表达式必须是类型全限定名,不支持通配符
*/
        // 匹配指定类型内的方法执行(包下所有的类)
        @Pointcut(value = "target(cn.timebusker.service.order.OrderInfoService)")
        public void logt2() {
        }
        
/**
* 五、args(参数类型列表)--匹配当前执行的方法传入的参数为指定类型的执行方法
* 1、注意是匹配传入的参数类型,不是匹配方法签名的参数类型;参数类型列表中的参数必须是类型全限定名,通配符不支持;
* 2、args属于动态切入点,是在运行时动态匹配的,这种切入点开销非常大,非特殊情况最好不要使用;
* 3、此处不作示例
*/
        
/**
* 六、@within(注解类型)--匹配所以持有指定注解类型内的方法;注解类型也必须是全限定类型名;
* 1、注解类型也必须是全限定类型名;
*/
        // 匹配被org.springframework.stereotype.Service这个注解标注的类----注解标注在接口上不起作用
        @Pointcut(value = "@within(org.springframework.stereotype.Service)")
        public void logaw1() {
        }
        
        // 匹配 自定义注解标注的类----注解标注在接口上不起作用
        @Pointcut(value = "@within(cn.timebusker.annotation.timebuskerBean)")
        public void logaw2() {
        }
        
/**
* 七、@target(注解类型)--匹配当前目标对象类型的执行方法
* 1、目标对象持有指定的注解;
* 2、注解类型也必须是全限定类型名;
* 3、此处不作示例
*/        

/**
* 八、@annotation(注解类型)--匹配当前执行方法持有指定注解的方法
* 1、注解类型也必须是全限定类型名;
*/    
        // 匹配 自定义注解标注的类----注解标注在接口的方法上不起作用
        @Pointcut(value = "@annotation(cn.timebusker.annotation.timebuskerMethod)")
        public void logaa1() {
        }

// ==========================================================匹配切点表达式========================================================================================

    /**
     * 前置通知:在连接点执行前的通知,但不能阻止连接点前的执行(除非它抛出一个异常)
     */

// 引用多个切入点
//    @Before("log6() OR log7()")
// 引用单个切入点
    @Before("logaa1()")
    public void beforeAdvice(JoinPoint point) {
        logger.info("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS");
        logger.info("LoggerHandlerAop.beforeAdvice...time:" + DateUtil.now());
        Signature signature = point.getSignature();
        logger.info("所属类名称:" + signature.getDeclaringTypeName() + "\n代理类:" + signature.getClass() + "\n方法名称:" + signature.getName() + "\n所属类:" + signature.getDeclaringType());
        Object[] args = point.getArgs();
        logger.info("参数是:" + JSON.toJSONString(args));
        logger.info("被织入的对象是:" + point.getTarget());
        logger.info("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE");
    }

    /**
     * 返回后通知:在连接点正常执行完后执行的通知
     */
    @AfterReturning("logaa1()")
    public void afterReturningAdvice() {
        logger.info("LoggerHandlerAop.afterReturningAdvice...time:" + DateUtil.now());
    }

    /**
     * 抛出异常后通知:在连接节点抛出异常退出时执行的通知
     */
    @AfterThrowing("logaa1()")
    public void afterThrowingAdvice() {
        logger.info("LoggerHandlerAop.afterThrowingAdvice...time:" + DateUtil.now());
    }

    /**
     * 后置通知:当某连接节点退出的时候执行的通知(不论是正常返回还是异常退出)
     */
    @After("logaa1()")
    public void afterFinallyAdvice() {
        logger.info("LoggerHandlerAop.afterFinallyAdvice...time:" + DateUtil.now());
    }

    /**
     * 环绕通知:包围一个连接点(join point)的通知
     * 
     * @param pjp
     * @return
     */
    @Around("logaa1()")
    public Object aroundAdvice(ProceedingJoinPoint pjp) {
        logger.info("LoggerHandlerAop.aroundAdvice...time:" + DateUtil.now());
        Object obj = null;
        try {
            System.out.println("MoocAspect around 1.");
            obj = pjp.proceed();
            System.out.println("MoocAspect around 2.");
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return obj;
    }
}

 

 

标签:匹配,service,spring,void,boot,Pointcut,AOP,类型,public
来源: https://www.cnblogs.com/l-926/p/16614129.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有