一文记住Spring-AOP原理

AOP面向切面编程(让业务更关注业务)

AOP面向切面编程技术思想是OOP面向对象编程思想的补充拓展
OOP通过继承、封装、多态等概念将一系列有共同载体的属性动作集合约束至一个对象中
AOP是不同业务模块相同行为功能统一管理实现的思想,这些功能通常是与业务无关的系统相关功能,例如日志记录、异常处理、事务管理、性能监控等.如果利用OOP实现则会造成高度耦合与代码重复性
AOP技术思想将这些与对象核心业务没有关系的功能层面称为切面,在运行中动态切入至指定切入点,而对业务方面没有感知,没有侵入,可以优雅的解决这个问题,这就是AOP思想

术语概念

它们之间的关系大概可总结为: 切面是切入点和通知处理的集合,
而切入点则定义了一系列连接点的位置让程序能够将通知织入连接点.

切面-Aspect

切面是AOP的核心概念.由切入点和通知组成,定义了不同的业务对象所需的通用边缘功能集合.

切入点-Pointcut

切入点定义了所要执行通知处理的连接点的位置&筛选条件,可由路径表达式/注解指定
路径表达式支持正则可指定切入(织入)那些路径下的类方法,注解则通过指定注解来切入(织入)被注解的方法.

通知-Advice

指定切入逻辑的执行时机
分为前置通知、后置通知、环绕通知、异常通知、正常退出通知

连接点-Joinpoint

程序正常执行的点,可以理解是被切入对象要执行的方法,在该方法执行前后会执行通知处理.

织入-Weaving

一个类被织入Advice产生的代理类就是原类逻辑加上AOP增强逻辑.织入就是将切面通知和对象连接并创建代理类的过程

使用场景举例

日志收集、权限认证、事务管理、链路追踪、性能统计、加分布式锁

SpringAOP注解方式使用

切面声明

通过在类上增加@Aspet声明类为切面类.其中可定义切入点和通知处理方法.切面类由Spring管理所以需要加上@Component注解.如果想要对不同切面执行顺序进行调整可使用@Order(value)注解,value越小执行顺序越靠前

切入点声明

切入点声明需要将该注解添加到方法上.方法体为空即可.

  1. 注解声明
    @Pointcut("@annotation(注解全路径名)")
  2. 路径表达式声明
    @Pointcut("execution(* com.reuben.springlearn.aop.jointPoint.service.impl.*.*(..))")
第一个 * 表示定义返回值类型为所有类型
中间路径为要切入的包名,包名后面两个点表示当前包和其下子包.一个点表示当前包
第二个 * 表示定义的类名为所有类
最后的 *(..) *表示所有方法,括号中两个.表示所有参数
通知声明
  1. 前置通知@Before("切入点声明标记方法()")
    前置通知标记方法将在连接点方法执行前执行,可进行路径记录/其他日志记录工作
  2. 环绕通知@Around("切入点声明标记方法()")
    环绕通知类似于MethodInterceptor,可手动进行方法继续执行/直接返回.还可进行参数增强.可记录方法执行效率
  3. 后置通知@After("切入点声明标记方法()")
    后置通知,可进行一些执行之后的处理记录工作,方法正常执行与否都会执行该注解标记的方法
  4. 返回通知@AfterReturning("切入点声明标记方法()", returning = "返回参数名称")
    方法后置返回通知,该通知可获取到方法返回信息.对返回信息进行记录或增强.只有方法正常执行后才会执行
  5. 异常通知@AfterThrowing(pointcut = "切入点声明标记方法()()", throwing = "异常名称")
    方法后置异常通知,切入方法发生异常时会执行该注解标记的方法

可参考该仓库Demo

白话讲解

  1. 以小区快递代收点举例,本来收快递的时候是需要每个人去执行收快递、拆快递、检查快递的动作,并且还需要执行快递箱的清理工作.但是这个功能对于每个人来说都是重复的,非常影响小区住户体验.所以小区就规定快递由小区代收点统一收取、检查与快递箱的清理.只需要收取一些代理费用(性能损耗)即可.
  2. 也可用洗菜/洗盘子/吃饭举例.不论什么蔬菜和盘子均需要进行清洗以及吃饭前后需要进行做饭和清理工作,而不管饭的种类是什么.

实现原理

实现原理简单描述为使用JDK动态代理和CGLIB代理技术,在JVM运行期间,程序初始化对象时动态生成目标对象的代理对象加载到内存中(织入).默认使用JDK动态代理,如目标对象(不能是final)未实现目标接口则使用CGLIB.

静态AOP和动态AOP异同

两种AOP均基于代理模式,生成被切入类的代理对象实现
静态代理是代理类字节码由程序员手动编写源码编译得到,运行时不会改动
动态代理的代理类则是由运行时通过反射动态生成字节码并加载出来的

静态AOP由AspectJ实现,实现代理逻辑于编译时期
动态AOP由JDK动态代理和CGLIB实现,于运行期动态生成代理

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    //其余方法均已隐藏.该方法是Spring动态代理方法.可以在最后一个return看出如果有实现接口则优先使用JDK动态代理
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (NativeDetector.inNativeImage() || !config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            } else {
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }
}

JDK动态代理和CGLIB实现机制

  1. JDK动态代理通过实现InvocationHandler接口的invoke方法,在初始化时加入源类对象,使用Proxy.newProxyInstance()创建代理对象,代理对象就可以通过拦截目标方法执行对应的代理逻辑并通过反射执行目标方法
  2. CGLIB通过FastClass机制,对被代理类方法建立索引,通过拦截方法通过方法索引直接调用对应方法实现代理功能.自定义MethodInterceptor重写intercept方法,并通过Enhancer.create()创建代理类.

参考

JavaGuide
AOP面试造火箭事件始末
GitHub仓库练习

全部评论

相关推荐

昨天晚上打电话约面,约了今晚上,大约50分钟,从项目问到基础知识再问408,还有一堆开放性试题,最后一个口述快排。PS:我明明投的是上海市,投递记录里面也是上海市,怎么面试官那边意向地点成我家所在的城市了???面试官还问我这里是上海美团,我说我投的就是上海,面试官跟我说应该是解析错了,我???PPS:面试官最后问我是不是应届,我说我是25届,结合牛客上有些人说上海美团没hc,是真的吗?不会是kpi吧???(回忆版,有些可能不记得了,顺序可能不准确)自我介绍为什么学前端了解过移动端的开发吗?(我说的不知道)看过一些大型项目的源码吗?(我说的没有)vue和react的区别类组件和函数组件的生命周期useeffect是什么时候执行的(这里面试官好像没懂我的意思,跟我扯了好久。。。)多次setstate结果如何,如何验证(PS:面试官这里跟我说面试不会因为一道题答不出来就挂,但我说的有对有错,建议再查一下资料)react渲染过程,如何判断是否更新(他问我如何判断数据发生了变化,我跟他解释了好久,感觉自己是不是说的不好。。。)vue如何实现数据监听react的虚拟dom的diff算法redux原理以及过程跨域是什么前后端发送请求的过程,要从整个网络的角度去说http状态码(我忘了是个啥题了,但我回答的是用状态码解决)https与http的区别,为什么是安全的从数学角度讲述非对称加密的过程(不会)了解多线程吗?你实际项目中用过多线程吗?你除了js以外还会什么语言呢?(我说c++,我还以为他要问c++,但是一个也没问)用c++写过项目吗?(我说没有,只是用作课程作业和算法题,但我讲到了操作系统课设)实现一个操作系统需要做什么你们的操作系统是每个人都一样还是各自实现(我说的都一样,课设是写好了一个框架我们自己实现功能)你的项目如何实现架构?(指简历上的项目)你在学习和项目中遇到过什么难点?(面试官以为我一帆风顺,我说肯定不是)简述快排过程和复杂度你是哪一年毕业的?(25)你还投了其他的哪些公司呢?(我说了饿了么一面挂的经历)反问:1、我的状态如何,后续需要提升什么?答:你的状态很好,是个e人,你的知识都是出自理论,可以多看一些源码性的东西2、面试结果和后续什么时候出?答:还要经过hr筛选,还有几轮面试,过一两周出结果
点赞 评论 收藏
转发
2 16 评论
分享
牛客网
牛客企业服务