Spring(十七):AOP——获取增强器
- 回顾
- 获取增强器
- getAdvisor方法
- 获取切入点
- 取出匹配的注解
- 封装数据
- 根据切入点信息生成增强方法
- 初始化增强器
- AspectJMethodBeforeAdvice
- AspectJAfterAdvice
- 增加同步实例增强器
- 获取DeclareParents注解
回顾
前面已经讲述了大致的AOP流程,从解析配置文件里面的AOP标签到创建AOP代理时去获取所有的增强方法,但对于增强方法的获取还没有看到具体实现的底层,下面就来看看具体的底层实现
获取增强器
回到ReflectiveAspectJAdvisorFactory中的getAdvisors方法
上一篇我们就是讲到这
- 对方法上的注解处理:即@Around,@Before,@After等。。。
- 使用getAdvisor方法将Method转化为Advisor
- 对字段上的注解处理:即@DeclaredParents
- 使用getDeclareParentsAdvisor对字段进行转化成Advisor
下面就对这两个方法进行分析
getAdvisor方法
这个方法是获取普通增强器的
源码如下
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {//校验操作validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());//获取切入点信息,也就是切面里面的@Pointcut注解,或者@Befor等注解里面的一些表达式//这个注解标识了切入点而已,切入点就是给切入方法使用的,表明该切入方法在什么时候被切入//获取切入点//参数有候选方法,切面工厂获取的切面ClassAspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());//判断切入点是否为空 if (expressionPointcut == null) {//如果没有切入点,直接返回null//代表没有需要增强的方法//没有切入点还增强什么咧return null;}//如果有切入点,就根据切点信息生成增强器return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}
总体的步骤如下
- 校验
- 获取切入点信息
- 判断切断是否为空
- 如果切入点为空,直接return null
- 如果切入点不为空,根据切入点信息去生成增强方法
拓展:可能这里有人对于切入点不太熟悉,切入点其实就是指你切入的方法在哪里去执行,一般在AOP类里有两种方法添加
- 注解式拦截:使用@PointCut注解去指定哪个注解会代表类被切入
- 方法规则式拦截:在切入方法的@Before等上面添加表达式,表达式里面的内容就是标识对于哪些类进行切入
使用注解式拦截
使用方法式规则拦截
下面就蓝看看是如何获取这两种切入点的
获取切入点
对应的方法为getPointCut
方法的源码如下
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {//要知道这里传进来的就是切面里面的方法//从候选方法里面寻找有没有对应的注解AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);//判断有没有匹配的注解if (aspectJAnnotation == null) {//没有匹配的注解直接返回Null,return null;}//使用AspectJExpressionPointCut来封装数据AspectJExpressionPointcut ajexp =new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);//注入切入点的表达式,也就是规则式拦截的表达式ajexp.setExpression(aspectJAnnotation.getPointcutExpression());if (this.beanFactory != null) {//注入beanFactoryajexp.setBeanFactory(this.beanFactory);}return ajexp;}
这里大概就两个流程
- 从候选方法上取出匹配的注解
- 使用AspectJExpressionPointCut来封装数据,比如切面对应的Class
- 注入切入点的表达式,也就是规则式拦截的表达式
- 注入beanFactroy
取出匹配的注解
从代码上可以看到,取出匹配的注解是交由AbstractAspectJAdvisorFactory去执行的,对应的方法是findAspectJAnnotationOnMethod
下面就来看看这个方法的源码
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {//遍历要匹配的注解for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {//调用findAnnotation方法从方法中看能不能找出当前的注解//并且封装在AspectJAnnotation里面AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);//如果不为null,就直接返回//从这里可以看到,如果给方法加上了多个注解还会有一个优先级顺序。。。。if (foundAnnotation != null) {return foundAnnotation;}}return null;}
可以看到这里遍历的注解,是不是十分熟悉咧。。
就是我们用于给Aop定义切入点和切入方法的6个注解,所以也是找这6个注解
同时还有一个顺序问题,先找PointCut、Around、Before、After、AfterReturing、AfterThrowing(后面再进行验证一下。。。。。),优先级也是从大往小,如果一个方法里面有PointCut又有Around,则会优先取PointCut
后面的封装进AspectJAnnotation里面就不详细说了,比较复杂,看不太懂。。。。。。。
还是直接分析下一个流程
封装数据
封装数据也没什么好讲的,就是如果存在匹配的注解,就代表要生成一个切入点了,Spring使用的是AspectJExpressionPointCut来保存这一部分信息的,最终将AspectJExpressionPointCut来返回结果即可
根据切入点信息生成增强方法
对应的代码如下
可以看到增强方法其实对应的是一个InstantiationModelAwarePointcutAdvisorImpl对象
接下来我们就看看其是怎么创建的,源码如下
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {this.declaredPointcut = declaredPointcut;this.declaringClass = aspectJAdviceMethod.getDeclaringClass();this.methodName = aspectJAdviceMethod.getName();this.parameterTypes = aspectJAdviceMethod.getParameterTypes();this.aspectJAdviceMethod = aspectJAdviceMethod;this.aspectJAdvisorFactory = aspectJAdvisorFactory;this.aspectInstanceFactory = aspectInstanceFactory;this.declarationOrder = declarationOrder;this.aspectName = aspectName;if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {// Static part of the pointcut is a lazy type.Pointcut preInstantiationPointcut = Pointcuts.union(aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.// If it's not a dynamic pointcut, it may be optimized out// by the Spring AOP infrastructure after the first evaluation.this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);this.lazy = true;}else {// A singleton aspect.this.pointcut = this.declaredPointcut;this.lazy = false;//对于建言进行初始化//建言就是指切入方法的注解,比如@Before,@After那些2//但那些不同类型的建言,对方法的增强类型也是不同的//@Before是方法执行前,@After是方法执行后,@Around则是一个包围this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);}
}
可以看到构造方法,emmmmm,很长,大部分的都是一些简单的赋值操作,但这里要注意的是对于建言的初始化,也就是对于增强器的初始化,不同类型的建言对应不同的增强器
而初始化增强器是在instantiateAdvice里面初始化的
初始化增强器
源码如下
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {//调用aspectAdvisorFactory来获取增强器Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,this.aspectInstanceFactory, this.declarationOrder, this.aspectName);return (advice != null ? advice : EMPTY_ADVICE);}
可以看到,增强器的初始化是交由AspectInstanceFactory接口来完成的,并且其只有一个实现类,就是ReflectiveAspectJAdvisorFactory
在ReflectiveAspectJAdvisorFactory的getAdvice方法的源码如下
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {//获取切面的classClass<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();//校验validate(candidateAspectClass);//获取方法上的注解AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);if (aspectJAnnotation == null) {return null;}// If we get here, we know we have an AspectJ method.// Check that it's an AspectJ-annotated classif (!isAspect(candidateAspectClass)) {throw new AopConfigException("Advice must be declared inside an aspect type: " +"Offending method '" + candidateAdviceMethod + "' in class [" +candidateAspectClass.getName() + "]");}if (logger.isDebugEnabled()) {logger.debug("Found AspectJ method: " + candidateAdviceMethod);}//AbstractAspectJAdvice其实就是建言(增强器)的一个抽象模板AbstractAspectJAdvice springAdvice;//这是最关键的一步//对注解的类型进行判断switch (aspectJAnnotation.getAnnotationType()) {//如果是@PointCut类型case AtPointcut:if (logger.isDebugEnabled()) {logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");}//@PointCut类型没有增强器,其代表的仅仅只是一个切入点return null;//如果是@Around类型case AtAround://返回一个AspectJAroundAdvicespringAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;//如果是@Before类型case AtBefore://返回一个AspectJMethodBeforeAdvicespringAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;//如果是@After类型case AtAfter://返回一个AspectJAfterAdvicespringAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);break;//如果是一个@AfterReturning注解case AtAfterReturning://返回一个AspectJAfterReturingAdvicespringAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);//获取@AfterReturing的属性AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();//判断是否为空,不为空就添加进springAdvice中//这里对应的属性是returningNameif (StringUtils.hasText(afterReturningAnnotation.returning())) {springAdvice.setReturningName(afterReturningAnnotation.returning());}break;//判断是不是@AfterThrowing注解case AtAfterThrowing://返回一个AspectJAfterThrowingAdvicespringAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);//获取@AfterThrowing注解上的属性AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();//判断是否为空,不为空就添加进springAdvice中//这里对应的属性是throwingName,if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {springAdvice.setThrowingName(afterThrowingAnnotation.throwing());}break;//如果不是上面的5种类型,抛错处理default:throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);}// Now to configure the advice...//接下来给建言添加一些配置//注入切入的名称springAdvice.setAspectName(aspectName);//springAdvice.setDeclarationOrder(declarationOrder);String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);if (argNames != null) {springAdvice.setArgumentNamesFromStringArray(argNames);}springAdvice.calculateArgumentBindings();return springAdvice;}
枚举类如下,可见与对应的注解是一一对应的
可以看到,初始化增强器是使用一个简单工厂模式来根据不同的注解来初始化的,增强器整体抽象成一个模板AbstractAspectAdvice
使用switch来根据注解类型选择哪种AbstractAspectAdvice的实现类
-
@PointCut:并不是一个建言,直接return null
-
@Around:返回一个AspectJAroundAdvice
-
@Before:返回一个AspectJMethodBeforeAdvice
-
@AfterReturing:返回一个AspectJAfterReturing,并且根据注解里面的returing属性来给AspectJAfterReturing设置returing属性
-
@AfterThrowing:返回一个AspectJAfterThrowingAdavice,并且根据注解里面的annotation属性去设置annotation属性
-
仅仅支持这5种类型,对于其他类型都会报错
-
最后就是一些简单配置信息注入进AbstractAspectAdvice上去,比如切面名字等。。。。。。
-
最终将AbstractAspectAdvice返回,返回到增强方法的构造方法
-
并且这里要注意,对于每个建言的构造方法里面都是传进了候选方法的Method的,同时也给上了切面的实例工厂,也就是说建言可以通过切面实例工厂来获取实例然后使用候选方法的Method来进行执行建言的
下面我们简单分析一下几个常用的增强器
AspectJMethodBeforeAdvice
AspectJMethodBeforeAdvice对应的就是@Before注解生成的建言(增强器)
可以看到,拦截对应的是一个before方法,里面执行了invokeAdviceMethod
而invokeAdviceMethod是AbstractAspectJAdivice里面去做的,执行了invokeAdviceMethodWithGivenArgs方法
源码如下
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {//对参数处理Object[] actualArgs = args;if (this.aspectJAdviceMethod.getParameterCount() == 0) {actualArgs = null;}try {//下面就是通过反射来调用方法了//先让方法变得可以访问ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);//使用切面实例共产获取切面实例,然后执行建言方法return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);}catch (IllegalArgumentException ex) {throw new AopInvocationException("Mismatch on arguments to advice method [" +this.aspectJAdviceMethod + "]; pointcut expression [" +this.pointcut.getPointcutExpression() + "]", ex);}catch (InvocationTargetException ex) {throw ex.getTargetException();}}
看到这,有点懵逼,@Before的特性呢?你这直接执行就完事了???
下面再看一看@After的
AspectJAfterAdvice
对应的invoke方法如下
可以看到,AspectJAfterAdvice是不一样的,其是使用invoke方法来进行执行的,并且还会先执行mi.proceed,最终才会进行invokeAdviceMethod(这个方法与AspectJMethodBeforeAdvice调用的before一样,这里不再赘述)
这里可以估计mi.proceed是执行原来方法的,后面的invokeAdviceMethod是执行@After的建言方法的,那么对于@Before而言是不是也应该有个mi.proceed方法的呢?只不过顺序会与@After的相反
后面看书发现,原来@Before对应的增强器其实是MethodBeforeAdviceInterceptor
里面就很清晰的说明了顺序,而且对应的也是invoke方法,先执行MethodBeforeAdvice的before方法,后面再执行mi.proceed继续被切方法的执行
但还是疑惑,明明返回的是AspectJMethodBeforeAdvice,是在哪里进行替换的呢?????
大致的结构是拦截器链中去放置这些AspectJxxxAdvice进行拦截,而对于前置增强就比较特殊点,放置的是MethodBeforeAdviceInterceptor
现在我们也完成根据切入点信息生成增强方法了
让我们返回上一层去,返回我们之前的ReflectiveAspectJAdvisorFactory的getAdvisors方法
接下来就应该到增加同步实例增强器了
增加同步实例增强器
首先会先判断,如果寻找到的增强器(建言)不为空并且又配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器
咳咳,这里在首位添加是没问题的,上一篇不小心搞混了,add方法是会将原来的元素进行右移的,腾出一个位置之后进行添加新元素
源码如下
// If it's a per target aspect, emit the dummy instantiating aspect.if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {//去实例化一个同步实例增强器Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);//添加进advisors结果集中advisors.add(0, instantiationAdvisor);}
步骤很简单,就是判断完之后去实例化一个同步实例增强器,然后添加进advisors结果集中,关键还是实例化
可以看到,这个是所谓的同步实力增强器仅仅只是ReflectiveAspectJAdvisorFactory的一个静态内部类
可以看到这仅仅是构建了父类而已,接下来看看父类的构造方法
可以看到,参数是一个PointCut和一个Advice,这下大概明白了,其实所谓的同步实例增强器仅仅也只是一个增强器,也是跟前面的各种建言增强器一样的,都是放在拦截器链上的
回到同步实力增强器的构建方法上,看看其给的增强器做了什么
可以看到,这个肯定是实例化了一个MethodBeforeAdvice接口
并且跟AspectMethodBeforeAdvice类似都是重写的是before方法,而before方法的内容是使用切面实例工厂去创建一个切面。。。。。
Emmmm,有点懵逼,并且这个before方法在前面的AspectJMethodBeforeAdvice上看到的是由另外一个拦截器来进行的,那么对于这个同步实例增强器是不是应该也是由另外一个拦截器来进行的呢?????
获取DeclareParents注解
接下来就是最后的对DeclareParents注解进行解析了
可以看到是使用getDeclareParentsAdvisor方法进行的
源码如下
@Nullableprivate Advisor getDeclareParentsAdvisor(Field introductionField) {//从传进来的字段里面去找注解DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);//判断是否找到if (declareParents == null) {// Not an introduction fieldreturn null;}//判断DeclareParents的defaultImpl属性是不是与DeclareParents的类一样//defaultImpl属性是用来定义待添加方法所在的类的,这个类要被bean托管//所以这个判断就代表不支持添加DeclareParents的方法if (DeclareParents.class == declareParents.defaultImpl()) {throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");}//返回一个DeclareParentsAdvisor增强器return new DeclareParentsAdvisor(introductionField.getType(), declareParents.value(), declareParents.defaultImpl());}
可以看到,步骤非常简单,因为这仅仅只是针对一个注解,而是形成的加强器也只有一个,不像建言注解一样,5个增强器提取出来
- 从传进来的字段里面寻找@DeclareParents注解
- 如果没找到,直接返回
- 找到了之后,校验@DeclareParents注解里面的defaultImpl属性,规定了defaultImpl属性对应的实现类的Class类型不能是DeclareParents属性的
- 创建DeclareParentsAdvisor增强器
至此,寻找所有的增强方法、增强器就结束了
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 洛谷第1题 P1042 乒乓球
洛谷AC的第一题! 主要卡点 (1)E之后的数据不能管,要break掉; (2)当输或赢的数量大于等于11时(注意是大于等于!不是等于!),还要判断输…...
2024/4/15 14:36:59 - 7.Linux中的无人职守安装脚本kickstart
在企业中安装多台操作系统时面临的问题 当安装Linux操作系统时,安装过程会需要回答很多关于设定的问题 这些问题必须手动选择,否则无法进行安装 当只安装1台Linux系统,手动选择设定工作量比较轻松 当安装多台Linux,这些设定需要重复多次,这些重复动作是效率底下的操作 如何解…...
2024/4/15 14:36:59 - string的模拟实现
文章目录拷贝构造和赋值重载的传统写法vs现代写法传统写法现代写法:拷贝构造和赋值重载的交换拷贝构造和赋值重载的现代写法可以复用swap范围for“增”的操作(从尾部添加)“改”的实现:insert<<、>>及inline的重载总体…...
2024/4/15 14:36:54 - LuoGu_Code01_P1042 乒乓球
洛谷AC的第一题! 主要卡点 (1)E之后的数据不能管,要break掉; (2)当输或赢的数量大于等于11时(注意是大于等于!不是等于!),还要判断输…...
2024/4/24 21:33:28 - 2021年G2电站锅炉司炉考试内容及G2电站锅炉司炉复审考试
题库来源:安全生产模拟考试一点通公众号小程序 安全生产模拟考试一点通:2021年G2电站锅炉司炉考试内容为正在备考G2电站锅炉司炉操作证的学员准备的理论考试专题,每个月更新的G2电站锅炉司炉复审考试祝您顺利通过G2电站锅炉司炉考试。 1、【…...
2024/4/15 14:36:34 - linux基础IO
愿所有梦见远方的人,心有惊雷,生似静湖。 基础IO前言一、C语言中文件的IO操作fopen函数打开文件fread函数读文件fwrite函数写文件stdin&stdout&stderr二、系统I/O操作open函数open的第一个形参open的第二个形参open的第三个形参open函数的返回值…...
2024/4/15 14:36:54 - 《中英双解》leetCode Merge Two Sorted List(合并两个有序链表)
Merge two sorted linked lists and return it as a sorted list. The list should be made by splicing together the nodes of the first two lists. 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 Example 1: Input: l…...
2024/4/17 17:27:29 - 【笔记】微服务架构
参考书籍:《Go 语言高并发与微服务实战》 参考书籍:《Go 微服务实战》 微服务架构设计早在 2014 年就被提出,其理念是将单体应用转化为多个可以独立开发、独立部署、独立运行和独立维护的服务或者应用的集合,从而满足业务快速变化…...
2024/4/24 14:11:28 - Java(54):Java 连接MySQL数据库进行操作
Java(54):Java 连接MySQL数据库进行操作 首先:Java 连接 MySQL 需要驱动包,最新版下载地址为:http://dev.mysql.com/downloads/connector/j/,解压后得到 jar 库文件,然后在对应的项目中导入该库文件。 1.1、IDEA的项…...
2024/4/21 17:38:04 - 垃圾回收器
GC分类和性能指标 垃圾回收器概述 垃圾收集器没有在规范中进行过多的规定,可以由不同的厂商来实现不同版本的JVM。由于JDK的版本处于高速迭代过程中,因此Java发展至今已经衍生了众多的GC版本。从不同角度分析垃圾收集器,可以将GC分为不同的…...
2024/4/6 12:02:11 - 屏蔽知乎首页的视频
背景 知乎越高越回去了,现在没营养的垃圾视频满天飞,所以就想到了把视频屏蔽掉 安装一个插件,我的浏览器的是 chrome 步骤 下载一个插件 链接: https://pan.baidu.com/s/15DpiqDXxTWEe5xOgDZVAWw 提取码:tc5v 解压 …...
2024/4/25 2:10:22 - 2021-10-31每日刷题打卡
一、LeetCode:94. 二叉树的中序遍历 (1)问题描述 给定一个二叉树的根节点 root ,返回它的 中序 遍历。 示例 1: 输入:root [1,null,2,3] 输出:[1,3,2] 示例 2: 输入:root [] 输出:[] 示例 …...
2024/4/20 7:26:09 - springboot工程错误 Error: Cannot download ‘https://start.spring.io/starter.zip?type=maven-proje
这个错误真的得记录下来了,最近创建springboot工程一直显示错误,跟着网上好多教程都无法解决 ,直到无意间看到了一个评论才弄好的 就是这个错 解决办法就是创建时把路径改为 https://start.springboot.io/至于究竟为什么错我也没有搞清楚&a…...
2024/4/24 19:58:24 - 将数据集标注的json格式文件转化成xml格式文件
之前训练的Faster R-CNN的标签用的是json格式的文件,现在训练SSD模型需要xml格式的文件。 1.新建存放jpg原图和json标签的两个文件夹 (PS:所有图片都必须是jpg格式,如果是png、jpeg等其他格式会报错) 如下图所示 2.在…...
2024/4/22 0:00:36 - C++中的内存模型和名称空间
1、单独编译 和C语言一样C也允许甚至鼓励程序员将组件函数放在独立的文件中,可以单独编译这些文件,然后将它们链接成可执行的程序。如果只修改一个文件,则可以只重新编译该文件,然后将它与其他文件的编译版本链接。 头文件中常包…...
2024/4/19 13:00:43 - java.lang.NumberFormatException: null的原因以及解决方法
java.lang.NumberFormatException: null 今天在写分页查询的时候遇到这样的报错。 然后马上检查了我的sql,发现是这里没有给值的原因。 为了确定是这个原因,我直接在jsp页面的跳转路径后面加了值。 结果是正确的。 确定是这个原因后,我将js…...
2024/4/19 5:07:52 - UVA1306 The K-League(最大流)
题面 有 nnn 支队伍进行比赛,每支队伍需要打的比赛数目相同。 每场比赛恰好一支队伍胜,另一支败。 给出每支队伍目前胜的场数 wiw_iwi 和败的场数(没用),以及每两个队伍还剩下的比赛场数 ai,ja_{i,j}ai,j&#…...
2024/4/21 16:08:48 - Web︱Servlet
简介 Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源…...
2024/4/25 7:11:28 - 内置对象之字符串String()对象
String 对象用于处理已有的字符块。 一个字符串用于存储一系列字符就像 "John Doe". 一个字符串可以使用单引号或双引号: 目录 字符串对象的创建 基本的包装类型 字符串的不可变性 字符串对象的属性和方法 获取简单随机验证码 字符串简单处理 字…...
2024/4/15 14:37:30 - 自定义javascript中call、bind、apply方法
call、bind、apply都是Function原型上的方法,用于改变this的指向 自定义函数 js中的call、bind、apply是用c代码实现的,我们这里使用js代码做一个模式,没有把所有的边界情况考虑进来,仅做一个简单的实现,三个函数在使…...
2024/4/24 6:04:55
最新文章
- Linux c++ onvif客户端开发(9):GetProfiles
本文是Linux c onvif客户端开发系列文章之一: Linux c onvif客户端开发(1): 根据wsdl生成cpp源文件Linux c onvif客户端开发(2): 获取摄像头H264/H265 RTSP地址Linux c onvif客户端开发(3): 扫描设备Linux c onvif客户端开发(4): 扫描某个设备是否支持onvifLinux c…...
2024/4/25 21:33:51 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 分享一个Python爬虫入门实例(有源码,学习使用)
一、爬虫基础知识 Python爬虫是一种使用Python编程语言实现的自动化获取网页数据的技术。它广泛应用于数据采集、数据分析、网络监测等领域。以下是对Python爬虫的详细介绍: 架构和组成:下载器:负责根据指定的URL下载网页内容,常用的库有Requests和urllib。解析器:用于解…...
2024/4/23 7:26:06 - Stable Diffusion 本地部署教程
Stable Diffusion 是一个开源的本地部署的软件,用于在本地网络中进行消息传递和同步。下面是 Stable Diffusion 的本地部署教程: 安装稳定扩散软件:首先,您需要从 Stable Diffusion 的官方网站或 GitHub 页面上下载并安装 Stable …...
2024/4/23 6:37:02 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/4/25 11:51:20 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/25 18:39:24 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/25 18:38:39 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/25 18:39:23 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/25 18:39:22 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/25 18:39:22 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/25 18:39:20 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/25 16:48:44 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/25 13:39:44 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/25 18:39:16 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/25 0:00:17 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/25 4:19:21 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/25 18:39:14 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/4/25 18:39:12 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/25 2:10:52 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/25 18:39:00 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/25 13:19:01 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/25 18:38:58 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/25 18:38:57 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57