手写Spring框架---AOP实现

news2024/11/13 9:05:11

目录

容器是OOP的高级工具

系统需求

关注点分离Concern Separation

原有实现

AOP的成员

Advice的种类

单个Aspect的执行顺序

多个Aspect的执行顺序

Introduction-引入型Advice

代理模式

JDK动态代理

Spring AOP的实现原理之JDK动态代理

Spring AOP的实现原理之CGLIB动态代理

JDK动态代理和CGLIB

自研框架AOP机制1.0

自研框架的AOP 1.0待改进的地方

AspectJ框架

自研框架AOP2.0


  • 容器是OOP的高级工具

  • 以低耦合低侵入的方式打通从上到下的开发通道
    • 按部就班填充代码逻辑实现业务功能,每层逻辑都可无缝替换
    • OOP将业务程序分解成各个层次的对象,通过对象联动完成业务
    • 无法很好地处理分散在各业务里的通用系统需求
  • 系统需求

  • 码农才去关心的需求
    • 添加日志信息:为每个方法添加统计时间
    • 添加系统权限校验:针对某些方法进行限制
    • OOP下必须得为每个方法都添加通用的逻辑工作,增加维护成本
  • 关注点分离Concern Separation

  • 不同的问题交给不同的部分去解决,每部分专注解决自己的问题
    • Aspect Oriented Programming就是其中一种关注点分离的技术
    • 通用化功能的代码实现即切面Aspect
    • Aspect之于AOP,就相当于Class之于OOP,Bean之于Spring
  • 原有实现

  • 在不改变业务代码的基础上,增加系统需求
  • @Aspect:告诉Spring这是一个需要被织入的通用逻辑,它修饰的类也需要被Spring作为bean管理起来所以可以使用@Component
  • @Pointcut:告诉Spring往哪里织入Aspect里面的逻辑
  • JoinPoint: 切面可以织入逻辑的地方;表示调用的方法;不能直接调用proceed方法,可以先强转为ProceedingJointPoint再使用
  • @Around:在方法执行的时候进行织入
  • 将被代理方法的结果返回
  • @AfterReturning:在方法返回结果时调用相关逻辑

  • 注意:
  • Spring是默认不开启支持aop注解的逻辑的,需要告诉Spring去开启aop注解的逻辑;即添加@EnableAspectJAutoProxy 注解

  • AOP的成员

  • 如果将Aspect比作类的话,Advice就是里面的方法
    • 切面Aspect:将横切关注点逻辑进行模块化封装的实体对象
    • 通知Advice:好比是Class里面的方法,还定义了织入逻辑的时机
    • 连接点Joinpoint,允许使用Advice的地方
    • SpringAOP默认只支持方法级别的Joinpoint
    • 切入点Pointcut:定义一系列规则对Joinpoint进行筛选
    • 目标对象Target:符合Pointcut条件,要被织入横切逻辑的对象
  • 织入:将Aspect模块化的横切关注点集成到OOP里
  • 织入器:完成织入过程的执行者,如ajc
  • Spring AOP则会使用一组类来作为织入器以完成最终的织入操作
  • Advice的种类

  • BeforeAdvice:在JoinPoint前被执行的Advice
  • AfterAdvice:好比try…catch...finally里面的finally(不管是否抛出异常都会被执行)
  • AfterReturningAdvice:在Joinpoint执行流程正常返回后被执行(若期间抛出了异常就不会被执行)
  • AfterThrowingAdvice:Joinpoint执行过程中抛出异常才会触发
  • AroundAdvice:在Joinpoint前和后都执行,最常用的Advice
  • 单个Aspect的执行顺序

  • 先去执行@Around 上半身的逻辑,即调用proceed方法之前的,再这就是@Before里面的逻辑,之后就是执行目标对象joinpoint的方法
  • 再就是执行@Around 方法的下半身逻辑(proceed之后的),之后就是@After
  • 如果正常返回就调用@AfterReturing,否则调用@AfterThrowing(前提是Around里面没有catch相关的异常,仅仅只是抛出也可以否则不会走到这步)
  • 多个Aspect的执行顺序

  • order值越小,优先级越高
  • 优先级高的入操作会被优先执行,优先级低的出操作会被优先执行
  • Introduction-引入型Advice

  • 为目标类引入新接口,而不需要目标类做任何实现
  • 使得目标类在使用的过程中转型成新接口对象,调用新接口的方法
  • @DeclareParent 可实现
  • 代理模式

  • 代理角色:代理类
  • 被代理角色:被代理类
  • 抽象主题:抽象类或者接口
  • 代理类和被代理类都需要继承或者实现抽象主题,而实例化的时候要使用代理类,用户只需要面向接口或者抽象类编程
  • Spring AOP就是实现一个代理类来替换掉实现类来对外提供服务
  • 例子:
    • 用户用支付宝支付,用户不需要关心支付宝怎么从银行卡里提取并且转帐给店家
    • 从银行卡里提取并且转帐给店家会委托给支付宝去整
    • 支付宝作为代理类

  • 用AlipayToC作为ToCPaymentImpl的代理
  • 主函数测试:

  • 以上是静态代理:代理对象在编译时就实现了
  • 他不能满足业务需要,因为针对的目标对象不同的话我们都需要单独实现一个代理对象

  • 针对不同的目标对象都需要去单独实现一个代理对象,而代理对象的逻辑都是一样的,都要创建一一对应的实现类,这也是OOP的局限
  • JDK动态代理

  • 类是通过类加载器加载进来的,该过程主要做3件事
  • 1---通过带有包名的类来获取对应class文件的二进制字节流
  • 2---根据读取的字节流,将代表的静态存储结构转化为运行时数据结构(有了数据结构才能供外界进行数据访问)
  • 3---生成一个代表该类的Class对象,作为方法区该类的数据访问入口
  • 字节流能定义类的行为,根据一定规则去改动或者生成新的字节流
  • 将切面逻辑织入其中,使其动态生成织入切面逻辑的类,该机制就为动态代理机制
  • 根据接口或者目标类,计算出代理类的字节码并加载到JVM中去
  • JDK动态代理小结:
  • java反射包中的Proxy类可以调用newProxyInstance创建一个代理类对象
  • 传入三个参数:
    • 一个是代理类的类加载器
    • 一个是所有的实现接口数组
    • 一个是调用处理器的实现类
  • 创建好了代理对象,代理对象就可以执行被代理类实现的接口的方法
  • 在执行方法时,会先去执行调用处理器实现类中的invoke方法
  • invoke方法就可以对被代理类进行功能增强
  • Spring AOP的实现原理之JDK动态代理

  • 静态代理:在编译前进行实现,完成后代理类是一个实际的class文件
  • 动态代理是动态生成的,编译完成后并没有实际的class文件,而是在运行时动态生成类的字节码,并加载到JVM中
    • 要求被代理的类必须实现接口
    • 并不要求代理对象去实现接口,所以可以复用代理对象的逻辑
  • InvocationHandler
  • 只是用来统一管理横切逻辑的Aspect
  • 只有实现了InvocationHandler接口的类才具有代理的功能

    • proxy:真实的代理对象
    • method:所要调用的目标对象的方法实例(对应上面例子就是ToBPaymentImpl 的pay()方法实例)
    • args:方法里面需要用到的参数
  • 静态代理需要显式地调用代理类的方法,例如上面toCProxy.pay()
  • 而对于动态代理来讲,显式调用的是目标对象的方法,而不是代理类的方法
  • 动态代理就是直接调用ToCPaymentImpl的方法,静态代理就是调用代理类的方法
  • Proxy
  • 主要用来创建动态代理类的

    • ClassLoader loader:类加载器
    • Class[] interfaces:给代理类提供什么样的接口数组,代理类会最终实现这些接口
    • InvocationHandler h:当前动态代理的方法被调用的时候会关联到哪一个InvocationHandler实现类实例上
  • 用来封装通用的横切逻辑相当于Aspect
  • 用来保存被代理的对象也就是目标类
  • 执行被代理的方法,invoke需要传入被代理的实例以及参数

  • 工具类里面去调用proxy.newProxyInstance去针对AlipayInvocationHandler创建出对应的动态代理
  • 生成代理类的实例

  • 主函数调用

  • JDK动态代理机制是通过让动态代理类来实现和被代理类一样的接口从而在运行中去替代被代理类来工作的
  • Spring AOP的实现原理之CGLIB动态代理

  • 使用CGLib实现动态代理,完全不受代理类必须实现接口的限制
  • 而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高
  • 唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类
  • 代码生成库: Code Generation Library
    • 不要求被代理类实现接口
    • 内部主要封装了ASM Java字节码操控框架
    • 对于代理没有生成接口的类,CGLIB很适用
    • 动态生成子类以覆盖非final的方法,绑定钩子回调自定义拦截器(从本质上说对于需要CGLIB代理的类,CGLIB只是生成子类以覆盖非final的方法,绑定钩子回调自定义拦截器)
  • MethodInterceptor
  • 是AOP项目中的拦截器,它拦截的目标是方法,而不是请求
  • 作用:定义横切逻辑Aspect
  • 好比JDK动态代理的InvocationHandler,实现MethodInterceptor就可以定义出Aspect

  • 分别对应参数:动态代理对象、被代理的方法对象实例、被代理对象方法需要的参数数组、动态代理生成的method对象实例
  • Enhancer
  • CGLIB库的Enhancer在Spring AOP中作为一种生成代理的方式被广泛使用
  • 它是一个字节码增强器,可以用来为无接口的类创建代理
  • 它的功能与java自带的Proxy类挺相似的
  • 它会根据某个给定的类创建子类,并且所有非final的方法都带有回调钩子
  • 在Spring中经常可以看到他的身影比如@Configuration 注解的类就会被Enhancer代理
  • 代理时底层用了个字节码处理ASM
  • 创建代理类例子:

    • 切面Aspect逻辑
    • 创建代理类
    • 支持不实现接口的类的动态代理
    • 没实现接口的类
    • 主函数测试
  • CGLIB支持对实现接口的类的织入、无实现接口的类的织入
  • JDK动态代理和CGLIB

  • 实现机制:
    • JDK动态代理:基于反射机制实现,要求业务类必须实现接口
    • CGLIB:基于ASM机制实现,生成业务类的子类作为代理类
  • JDK动态代理的优势:
    • JDK原生,在JVM里运行较为可靠(不需要额外的jar包依赖)
    • 平滑支持JDK版本的升级(而cglib需要升级支持在新的jdk上的使用)
  • CGLIB的优势:
    • 被代理对象无需实现接口,能实现代理类的无侵入
    • 使用字节码技术生成代理类,比使用Java反射效率要高
  • Spring AOP的底层机制:
    • CGLIB和JDK动态代理共存
    • 默认策略:Bean实现了接口则用JDK,否则使用CGLIB
  • 为什么CGLIB即支持实现接口的代理也支持没有实现接口的代理,还要用JDK代理呢?
    • 因为JDK动态代理不依赖其他的package,并且兼容性好,性能也不差
  • 自研框架AOP机制1.0

  • 使用CGLIB来实现:不需要业务类实现接口, 相对灵活
  • 思路:
    • 解决标记的问题(识别Aspect以及Advice),定义横切逻辑的骨架
    • 定义Aspect横切逻辑以及被代理方法的执行顺序
    • 将横切逻辑织入到被代理的对象以生成动态代理对象
  • 解决横切逻辑的标记问题以及定义Aspect骨架
  • 步骤:
    • 定义与横切逻辑相关的注解
    • 定义供外部使用的横切逻辑骨架
  • 定义注解:

  • value表示当前被@Aspect 标记的横切逻辑是会织入到被属性值注解标签标记的那些类里
  • 例如当value为@Controller,则表示会将Aspect逻辑织入到所有被@Controller 标记的类里
  • 指定@Aspect 的执行顺序

  • 定义框架支持几种Advice
  • 作为钩子方法,就是空实现,让用户选择是否实现

  • 之所以用钩子方法而不是用注解的形式,主要为了实现的简单
  • 用户只需要对DefaultAspect进行继承选择实现里面的钩子方法,就能实现对目标类方法的事前和事后的织入,满足绝大多数的需求
  • 实现Aspect横切逻辑以及被代理方法的定序执行
    • 创建MethodInterceptor的实现类
    • 定义必要的成员变量---被代理的类以及Aspect列表
    • 按照Order对Aspect进行排序
    • 实现对横切逻辑以及被代理对象方法的定序执行
  • 如果一个AlipayMethodInterceptor去对应一个Aspect会有问题,因为每个Aspect都要去实现Interceptor方法,但是它里面会调用invokeSuper方法
  • 调用被代理类的方法,如果存在多个Aspect,invokeSuper方法会被多次调用
  • 同时我们无法像Spring一样先升序执行所有Aspect的beforeAdvice之后再一路执行afterAdvice,所以一对一的关系不可行
  • 能否实现一个MethodInterceptor对应多个Aspect? 可以的
  • 可以在MethodInterceptor里面保存一个有序的Aspect列表用来保存排序好的Aspect集合
  • 之后遍历Aspect集合先顺序执行Aspect集合里面的before逻辑,之后只需要执行一次invokeSuper方法,逆序执行Aspect里面的after逻辑
  • 向被代理类对象的方法里面添加横切逻辑,因为是CGLIB,所以要继承MethodInterceptor
  • 定义两个成员变量
  • 接收与实现类对应的order值
  • AspectInfo用来封装@Order和DefaultAspect的属性值

  • 将其排序好之后再赋值给对应的成员变量
  • 排序以及定义成员变量的逻辑
  • 既然已经接受了order的属性值,为什么没有aspect的属性值?
  • 到给构造函数传参的时候,我们已经确定了那些aspect是为targetClass织入逻辑的了,毕竟这里就是绑定两者的关系
  • 因此aspect标签的值在创建该类的实例之前已经用来确定两者的关系了,就不再需要传递
  • 测试:
  • 导包:

  • 实现:

  • 实现了MethodInterceptor是远远不够的,还需要Handler来创建动态代理对象

  • 将横切逻辑织入到被代理的对象以生成动态代理对象
  • 从容器当中筛选出两种bean,一种是被Aspect标记的bean,一种是被代理的bean
  • 在构造器里获取容器单例实例赋值给成员变量
  • 不要忘记将被Aspect标签标记的类放到Spring容器里面管理

  • 被Aspect标记的类里面的属性值可能是不同的(即织入的目标类集合是不同的,需要按照Aspect的属性值进行归类)
  • 针对key(被Controller、Service标记的类进行织入操作)织入的是各自的Aspect列表
  • 获取织入前的目标类集合,比如说你传入Class,就可以获得被Class标签标记的所有的Class对象实例(传入Controller,就可以获得被Controller标签标记的所有对象实例)
  • 完成了对容器里所有需要加入Aspect横切逻辑的bean实例的织入操作

  • 依赖注入和AOP织入谁先执行?
  • 我们希望bean都被织入了横切逻辑之后才供外界去使用,这其中也包含了被@Autowired 标记的属性对应的bean
  • 所以AOP的注入操作要先于依赖注入执行的
  • 自研框架的AOP 1.0待改进的地方

  • Aspect只支持对被某个标签标记的类进行横切逻辑的织入(没法对被Controller标签标记的某些部分类进行织入)
  • 需要披上AspectJ的外衣
  • AspectJ框架

  • 提供了完整的AOP解决方案,是AOP的Java实现版本
  • 定义切面语法以及切面语法的解析机制
  • 提供了强大的织入工具
  • Spring AOP只支持方法级别的织入,但是AspectJ几乎支持所有连接点的织入,称为AOP的一套完整的解决方案

  • 既然AspectJ那么强大,为什么Spring不直接复用AspectJ呢?
  • 因为方法级别的织入已经能满足绝大多数的需求了,并且Aspect的学习成本比Spring AOP高很多,还没有Spring AOP用起来简单;花20%的代价完成80%的需求
  • AspectJ框架的织入时机:静态织入和LTW
    • 编译时织入:利用ajc,将切面逻辑织入到类里生成class文件
    • 编译后织入:利用ajc,修改javac编译出来的class文件
    • 类加载期织入:利用java agent,在类加载的时候织入切面逻辑
  • 前两种为静态织入,因为在class文件编译好之后切面逻辑已经织入好了(写死进了代码里面)
  • CGLIB和JDK动态代理都是依靠继承关系来生成类对应的代理对象,即最终会多出一个动态代理类
  • 自研框架AOP2.0

  • 引入jar包

  • 折衷方案改进框架里的AOP
  • 使用最小的改造成本,换取尽可能大的收益---理清核心诉求
  • 需求:我们为了让织入目标的选择(Pointcut)更加灵活
  • 即只需要引入AspectJ的切面表达式和相关的定位解析机制
  • 创建一个解析类解析AspectJ即可
  • 不再使用固定的注解标签去筛选被代理的类,所以将Aspect标签下的属性名从value改为pointcut,类型也改为String

  • PointcutParser实例是需要被创建出来并且装配上相关的语法树,才能识别注解Aspect属性里面的pointcut表达式
  • PointcutExpression:是PointcutParser根据表达式解析出来的产物,用来判断某个类或者方法是否匹配pointcut表达式
  • 针对类级别的判断

  • 精细筛选:需要对被代理类里的方法将他传入到pointcutExpression方法里去做精准的匹配
  • 完全匹配:alwaysMatches

  • 之前按照aspect标签的属性值进行分类没有意义,因为不同的pointcut表达式可能获取同样的被代理的目标
  • 例如不同的表达式均可获得一样的目标
  • 加上我们为每一个被Aspect标签标记的类创建一个专门的PointcutLoader,去按照Aspect里面对应的expression也就是pointcut表达式匹配目标类以及目标方法,因此就不需要进行Aspect的分类了

  • 将符合条件的AspectInfo给筛选出来
  • 使用foreach的方式去遍历某个集合,但在遍历的时候会对集合元素进行移除操作,此时会报错,为什么?
  • 因为foreach里面用到的iterator对象是工作在一个独立的线程中,并且会拥有一个mutex的锁,iterator在创建之后会建立一个指向原来对象的单列索引表,当原来的数量发生变化时(即集合发生变化时),索引表的内容不会同步地去改变,所以当索引指针向后移动时,就找不到要迭代的对象了,就会抛出异常
  • 因此iterator在工作时不允许被迭代的对象动态的变化
  • 也就是不支持调用集合的remove方法在遍历的过程中动态地移除元素
  • 但是我们可以使用iterator本身的remove方法来删除对象
  • 因为它会在删除当前迭代对象的同时去维护之前说的索引表的一致性
  • 对初筛列表的精筛

  • pointcut表达式解析及定位,粗筛精筛

  • 进行aop织入

  • 通知(Advice)1 & 切面(Aspect)

  • 通知(Advice)2 & 切面(Aspect)

  • 目标对象(Target)

  • 测试成功:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/660216.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS基础学习--19 下拉菜单

一、基本下拉菜单 当鼠标移动到指定元素上时&#xff0c;会出现下拉菜单 <!DOCTYPE html> <html> <head> <title>下拉菜单实例</title> <meta charset"utf-8"> <style> .dropdown {position: relative;display: inline-…

UnityVR-项目的管理阶层

目录 概述 项目的总体架构 单例基类 继承MonoBehaviour的单例基类 概述 一个具备一定规模的项目&#xff0c;一般都需要由不同人员合作完成&#xff0c;每个人的想法风格不相同&#xff0c;如果一开始没有定下基本的框架&#xff0c;会让实现时混乱不堪&#xff0c;而且无法…

【CesiumJS入门】(5)GooJSON的加载、更新、监听与销毁——GeoJsonDataSource应用

前言 本篇&#xff0c;我们将较完整得介绍Cesium中GeoJSON/TopoJSON相关的方法。 GeoJSON规范地址&#xff1a;RFC 7946: The GeoJSON Format (rfc-editor.org) GeoJSON在线绘制&#xff1a;geojson.io CesiumJS提供了一个名为DataSource的类&#xff0c;它主要是用来加载和展…

Java-API简析_java.util.UUID类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131270140 出自【进步*于辰的博客】 其实我的【Java-API】专栏内的博文对大家来说意义是不大的。…

《计算之魂》读书笔记——递归与堆栈的关系

进入梅雨季节&#xff0c;一周末雨水连绵不绝&#xff0c;空气中泛着潮湿的凉爽。这个天气最适合找个角落&#xff0c;安安静静地读书写字。 继续读《计算之魂》&#xff0c;前次读到递归&#xff0c;今天则了解递归地数据结构实现。递归算法的层层实现&#xff0c;需要保留从…

大数据周会-本周学习内容总结018

开会时间&#xff1a;2023.06.18 15:00 线下会议 01【调研-数据分析&#xff08;质量、ETL、可视化&#xff09;】 ETL&#xff0c;是英文Extract-Transform-Load的缩写&#xff0c;用来描述将数据从来源端经过抽取&#xff08;extract&#xff09;、转换&#xff08;transform…

Tcl常用命令备忘录-正则命令篇

正则表达式是一种用于匹配、查找、替换文本中特定模式的工具。在Tcl脚本中&#xff0c;可以使用正则表达式对字符串进行匹配、查找和替换。 regexp 语法&#xff1a; regexp ?选项? 正则表达式 字符串 ?变量1 变量2 ...? 其中&#xff0c;?选项?为可选项&#xff0c;…

基于蒙特卡洛法的规模化电动汽车充电负荷预测(PythonMatlab实现)

目录 0 概述 1 蒙特卡洛模拟方法介绍 2 规模化电动汽车充电负荷预测计算方法 3 完整代码 0 概述 对于本文的研究,依据不同用途电动汽车影响因素的分布函数和设定参数&#xff0c;采用蒙特卡洛法,对各用途电动汽车的日行驶里程、起始充电时间概率分布参数进行随机抽样&#xff0…

linuxOPS系统服务_Linux下软件的安装方式之源码安装

Linux下有哪些软件安装方式 ① RPM软件包管理&#xff08;软件名称.rpm&#xff09; ② YUM软件包管理&#xff08;使用yum命令install 软件名称&#xff09; > 下载 安装一体化 ③ 源码编译安装&#xff08;相对来说是最复杂的一种方式&#xff09; 软件包类型 ☆ 二…

十二、docker学习-docker核心docker网络之bridge网络(2)

bridge网络 bridge网络表现形式就是docker0这个网络接口。容器默认都是通过docker0这个接口进行通信。也可以通过docker0去和本机的以太网接口连接&#xff0c;这样容器内部才能访问互联网。 # 查看docker0网络&#xff0c;在默认环境中&#xff0c;一个名为docker0的linux b…

Go语言的TCP和HTTP网络服务基础

目录 【TCP Socket 编程模型】 Socket读操作 【HTTP网络服务】 HTTP客户端 HTTP服务端 TCP/IP 网络模型实现了两种传输层协议&#xff1a;TCP 和 UDP&#xff0c;其中TCP 是面向连接的流协议&#xff0c;为通信的两端提供稳定可靠的数据传输服务&#xff1b;UDP 提供了一种…

NodeJSMongodbMVC管理开发⑨

文章目录 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持&#x1f618;前言MVC思想开发 服务器代码演示 M层 Services 或 Model V层 Views C层 Controllers总结 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c…

C语言笔记之结构体总结

C语言笔记之结构体总结 code review! 文章目录 C语言笔记之结构体总结一.介绍二.3种结构体类型变量说明1. 先定义结构&#xff0c;再定义结构变量2. 定义结构体类型的同时说明变量3. 直接说明结构变量(匿名结构体) 四.结构体成员表示方法五.结构体指针做参数六.结构体初始化1…

阵列信号处理笔记(2):均匀线阵、均匀加权线阵、波束方向图

阵列信号处理笔记&#xff08;2&#xff09; 文章目录 阵列信号处理笔记&#xff08;2&#xff09;均匀线阵&#xff08;Uniform Linear Array&#xff09;均匀加权线阵波束方向图的关键参数附polardb.m用来计算HPBW的Mathematica代码&#xff0c;以及用于拟合的数据拟合的MATL…

二、DSMP/OLS等夜间灯光数据贫困地区识别——MPI和灯光指数计算

一、前言 其实在计算MPI和灯光指数之前,最重要是DMSP/OLS等夜间灯光指数的校正还有就是MPI计算,那么校正分为DMSP/OLS和NPP/VIIRS夜间灯光数据,DMSP/OLS夜间灯光数据校正主要采取不变目标区域法原理进行校正,当前对其有很多优化后的做法,但是万变不离其宗,核心思想还是没…

LeetCode257. 二叉树的所有路径

写在前面&#xff1a; 题目链接&#xff1a;LeetCode257. 二叉树的所有路径 题目难度&#xff1a;简单 编程语言&#xff1a;C 一、题目描述 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的…

阿里P8架构师手码的Java工程师面试小抄在Github火了,完整版限时开源

网上的 JAVA 面试文档更是层出不穷。但是单单刷 JAVA 面试题就足够了吗&#xff1f; 答案显然是不够的&#xff01;那么为什么呢&#xff1f; 因为现在的程序员就业环境早就和两年前不可同日而语了。 如果你在两年前面试&#xff1a; 就拿 JVM 来说&#xff0c;刷面试题可能…

Springboot+vue.js+协同过滤推荐+余弦相似度算法实现新闻推荐系统

Springbootvue.js协同过滤推荐余弦相似度算法实现新闻推荐系统 - 简书 针对海量的新闻资讯数据&#xff0c;如何快速的根据用户的检索需要&#xff0c;完成符合用户阅读需求的新闻资讯推荐&#xff1f;本篇文章主要采用余弦相似度及基于用户协同过滤算法实现新闻推荐&#xff0…

SpringMvc详解

SpringMvc用来代替展示层Servlet&#xff0c;均属于Web层开发技术 Servlet是如何工作的 1、导入Servlet依赖坐标 2、创建一个Servlet接口实现类&#xff0c;重写其中的所有方法 3、在Servlet实现类上加上WebServlet注解&#xff0c;用来配置Servlet访问路径 4、启动Tomca…

Misc(6)

隐藏的钥匙 还是一样挨个试&#xff0c;详细信息里没有发现flag信息&#xff0c;就用010打开试试 文件头正常&#xff0c;暂时没有发现隐藏文件 喝&#xff0c;多搜搜还是有收获的&#xff0c;一开始以为是有隐藏文件就利用ctrlf在010中进行搜索 分别搜索了txt和rar文件都没有反…