摸鱼的时候继续复刻demo,没错,同之前一篇文章,在写aop时又发现自己对aop只停留在面试阶段,甚至还不如,完全不会实践,所以在此记录复刻aop用到的的一些且自己已经遗忘的知识。
那么复刻的一个需求点我以最简单来说对于此次要学习的内容:就是通过joinPoint获取方法上的特定注解。
注解代码如下:
import com.uum.common.core.enums.BusinessType;
import java.lang.annotation.*;
/**
* 自定义注解--操作日志记录
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Operation {
/**
* 模块
*/
String description() default "";
/**
* 功能
*/
BusinessType businessType() default BusinessType.OTHER;
/**
* 是否保存请求的参数
*/
boolean isSaveRequestData() default true;
/**
* 是否保存返回结果
*/
boolean isSaveResponseData() default true;
}
那么这个就是系统操作日志的注解,主要到时候用aop的joinPoint获取标注在方法上该注解联合方法的相关内容将其转化为系统日志并进行存储。那么问题来了,什么是joinPoint?
| 方法名 | 功能 |
|---|---|
| Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
| Object[] getArgs(); | 获取传入目标方法的参数对象 |
| Object getTarget(); | 获取被代理的对象 |
| Object getThis(); | 获取代理对象 |
| 其中关键方法就是这个getSignature(),该方法返回Signature对象,而通过该对象我们可以获得被增强方法的信息。 |
ProceedingJoinPoint继承JoinPoint,是它的子接口,在joinPoint的基础上对其增强功能。其实主要是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。
public interface ProceedingJoinPoint extends JoinPoint {
public Object proceed() throws Throwable;
public Object proceed(Object[] args) throws Throwable;
}
环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的
public Object around(ProceedingJoinPoint point) throws Throwable {
Signature signature = point.getSignature();
// AopUtils.getTargetClass(point.getTarget())获取原始对象,例如对于Mapper而言,它获取的是具体代理的Mapper如com.b.mapper.DefaultDsMapper(如果前者继承了后者的话)而不是定义该方法的Mapper如com.b.base.BaseMapper<Info, InfoExample, InfoKey>,如下图
Type[] types = AopUtils.getTargetClass(point.getTarget()).getGenericInterfaces(); // getGenericInterfaces方法能够获取类/接口实现的所有接口
Annotation nologgingAnno = ((Class)types[0]).getAnnotation(Nologging.class); // type是所有类型的父接口
MethodSignature methodSignature = (MethodSignature)signature;
Method targetMethod = methodSignature.getMethod();
}
此接口通常用于跟踪或记录应用程序以获取有关连接点的反射信息,下面是官方给的一个使用的例子
aspect Logging {
Logger logger = Logger.getLogger("MethodEntries");
before(): within(com.bigboxco..*) && execution(public * *(..)) {
Signature sig = thisJoinPoint.getSignature();
logger.entering(sig.getDeclaringType().getName(),
sig.getName());
}
}
源码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.aspectj.lang;
public interface Signature {
String toString();
//返回此签名的缩写字符串表示形式
String toShortString();
//返回此签名的扩展字符串表示形式
String toLongString();
//返回此签名的标识符部分。对于方法,这将返回方法名称。
String getName();
//返回表示为 int 的此签名上的修饰符。使用 java.lang.reflect.Modifier 上定义的常量和辅助方法来操作它,
// 检查此签名是否公开 java.lang.reflect.Modifier.isPublic(sig.getModifiers());
// 打印出修饰符 java.lang.reflect.Modifier.toString(sig.getModifiers());
int getModifiers();
//返回一个 java.lang.Class 对象,表示声明此成员的类、接口或方面。对于成员内声明,这将是声明成员的类型,而不是按词法写入声明的类型。使用 SourceLocation.getWithinType() 获取在词法上出现声明的类型。
//为了与 java.lang.reflect.Member 保持一致,这个方法应该被命名为 getDeclaringClass()
Class getDeclaringType();
//返回声明类型的完全限定名称。这等效于调用 getDeclaringType().getName(),但是为了更高的效率缓存了结果
String getDeclaringTypeName();
}
HttpClient请求
GET http://localhost:8080/test/testAnno?name=Indian frends
Accept: application/json
运行结果
I'm fine ,thank you
toString; String com.mz.testSpring.controler.testSpringControler.sayHello(String)
toShortString; testSpringControler.sayHello(..)
toLongString; public java.lang.String com.mz.testSpring.controler.testSpringControler.sayHello(java.lang.String)
getName; sayHello
getModifiers; 1
getDeclaringType; com.mz.testSpring.controler.testSpringControler
getDeclaringTypeName; com.mz.testSpring.controler.testSpringControler
可以看出,Signature 也是为了获取原始方法的各种信息而存在的,并且信息更加的简洁,方便我们截取,他与JoinPoint合作可以让我们更方便的获取原始方法的各种信息
当然我们通过Signature上面的方法还是不能很方便达成我们获取方法上的注解等操作。因为我们获取不了方法本身这个Method类。
那么这时MethodSignature就出现了,顾名思义,它就是方法签名,可以看下它的源码:
public interface MethodSignature extends CodeSignature {
Class getReturnType(); /* name is consistent with reflection API */
Method getMethod();
}
它就提供了两个方法,其中关键点就在于getMethod()方法,它可以获取被增强的方法本身Method这个类,通过该类就类似反射操作了,可以通过它的API完成获取注解等操作。
那怎么通过Signature得到MethodSignature呢
其实很简单,可以看一下它的依赖关系图:

所以你应该就明白了,强转即可。
那么我们就可以完成通过Signature获取注解的操作,方法如下:
private Optional<Operation> getAnnotationLog(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
if(method != null){
return Optional.ofNullable(method.getAnnotation(Operation.class));
}
return Optional.empty();
}
四、参考链接
https://blog.csdn.net/M_amazing/article/details/121747188
https://blog.csdn.net/qq_46940224/article/details/125960508
https://blog.csdn.net/qq_15037231/article/details/80624064
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva
文章目录华为OD面试流程1.mysql数据库建了两个字段,且设置了联合索引,如果其中有一个字段为空会出现什么问题?2.谈谈springIOC的理解,有什么好处,解决了什么问题3.谈谈springAOP的理解,切面编程有没有实际应用,有哪些注解,作用是什么,有那些应用场景?4.Erika和zookeeper有了解过吗,作用是什么,主要解决了什么问题5.谈谈JDK、JRE、JVM的理解,区别是什么6.谈谈对泛型的理解7.JVM的组成华为OD面试流程机试:三道算法题,关于机试,橡皮擦已经准备好了各语言专栏,可以直接订阅。性格测试:机试技术一面(本专栏核心)技术二面(本专栏核心)主管面试定级定薪发of
所以我从维基百科上抓取了这段ruby代码并做了一些修改:@trie=Hash.new()defbuild(str)node=@triestr.each_char{|ch|cur=chprev_node=nodenode=node[cur]ifnode==nilprev_node[cur]=Hash.new()node=prev_node[cur]end}endbuild('dogs')puts@trie.inspect我首先在控制台irb上运行它,每次我输出node时,每次{}都会给我一个空哈希值,但当我实际调用时该函数使用参数'dogs'字符串构建,它确实有效,并输出{"d"=>
运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid
各位朋友们,大家好啊,今天我要分享的是关于文件操作方面的知识。文章目录为什么会有文件操作什么是文件文件操作文件指针文件的打开与关闭fopen(打开文件)fclose(关闭文件)打开文件的方式文件的顺序读写fgets函数fputc函数fgets函数fputs函数fprintf函数fscanf函数文件的非顺序读写fseek函数ftell函数rewind函数二进制读写fwrite函数`fread函数结语为什么会有文件操作那么大家可能会问:为什么会有文件操作呢?前面我们可能都了解了通讯录,我们知道当我们使用通讯录的时候我们可以添加联系人,也可以删除联系人,但是当我们退出程序之后下次再进来的时候,我们要
本篇博文目录:一.SpringSecurity简介1.SpringSecurity2.SpringSecurity相关概念二.认证和授权1.认证(1)使用SpringSecurity进行简单的认证(SpringBoot项目中)(2)SpringSecurity的原理(3)SpringSecurity核心类(4)认证登入案例(JWT+SpringSecurity实现登入案例)2.授权(1)加入权限到Authentication中(2)SecurityConfig配置文件中开启注解权限配置(3)给接口中的方法添加访问权限(4)用户权限表的建立3.自定义失败处理(1)创建异常处理类(2)配置移除处理
性能指标一、性能测试指标性能测试是通过测试工具模拟多种正常、峰值及异常负载条件来对系统的各项性能指标进行测试。目的:验证软件系统是否能够达到用户提出的性能指标,发现系统中存在的性能瓶颈并加以优化。二、指标分为两大类:软件指标:术语释义TPS:(每秒事务数)在每秒时间内系统可处理完毕的事务数。TPS很大程度体现系统性能能力。TPS(TransactionPerSecond)是指单位时间(每秒)系统处理的事务量。事务可以是用户自定义的一系列操作或者动作的集合,比如“用户注册“事务是点击注册按钮,填写用户注册信息,点击提交按钮,以及加载注册成功页面的动作集合。这3个个公式都是对的第1个公式计算的是绝
之前已经写过一篇关于去重的文章,讲解了视频去重的原理,但是还是有很多人一直问这个问题,这次我就写的更加详细一些,同时给出一些案例,希望可以帮助更多的人。写作不易,如果觉得不错,还请点个赞。看完这篇文章,你就明白视频该如何去重以及为什么别人可以搬运,我一搬运就不行。文章末尾会解答几个很多人问过的问题,还有福利赠送。关注小程序:Al原创短视频,了解学习更多视频技术。为什么要深入理解去重虽然现在各大自媒体平台对视频查重越来越严格,但是,搬运这行永远不会落幕,永远有利可图,查重严格,也许是一件好事,这直接过滤掉大部分搬运的人,搬运的人越少,自然收益空间就越大。那么如何让自己避免成为那被过滤的大
前文在阅读论文前,首先我们要有一定的知识储备,包括人脸建模,表情制作,旋转转换等,才能方便我们的论文理解,所以首先我会讲解一些关键的知识点。Flame模型的作用?Flame是一个3D人脸的通用模型,举个例子,你现在有一个特定人的3D人脸扫描序列,那么我便可以通过Flame模型拟合,构建个性化的模型,然后通过改变表情参数,动作参数,从而生成一些新的表情,动作的3D数据,以进行动画制作等。除此之外,因为扫描数据的误差和缺失,我可以通过Flame模型,对数据进行拟合平滑,得到较为完善,完美的3D数据。除此之外,我还可以使用通用的模板T,从而实现对人脸较为粗糙的3D重建。比如Deca中,通过深度学习与