当前位置: 首页 > news >正文

如何提高网站的访问速度/优化公司排名

如何提高网站的访问速度,优化公司排名,网站怎么做关键词怎么优化,建网站要花钱吗文章目录 前言MapperFactoryBean的工作原理底层实现剖析MapperFactoryBean的checkDaoConfig()方法总结 MapperFactoryBean的getObject()方法 思考联想后续 系列相关相关文章究竟FactoryBean是什么?深入理解Spring的工厂神器超硬核解析Mybatis动态代理原理&#xff0…

文章目录

    • 前言
    • MapperFactoryBean的工作原理
    • 底层实现剖析
      • MapperFactoryBean的checkDaoConfig()方法
        • 总结
      • MapperFactoryBean的getObject()方法
    • 思考联想
    • 后续

系列相关相关文章
究竟FactoryBean是什么?深入理解Spring的工厂神器
超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?
Mybatis与Spring结合深探——MapperFactoryBean的奥秘
后续TODO:MapperScannerConfigurer

前言

在这里插入图片描述

在没有Spring单独使用Mybatis的时候,我在之前的文章超硬核解析Mybatis动态代理原理!只有接口没实现也能跑? 讲解到了调用链路new SqlSessionFactoryBuilder().build(xml)-->XMLConfigBuilder#parse-->>XMLConfigBuilder#parseConfiguration--->XMLConfigBuilder#mapperElement-->XMLMapperBuilder#mapperParser.parse()-->XMLMapperBuilder#configurationElement-->XMLMapperBuilder#bindMapperForNamespace-->Configuration#MapperRegistry#addMappper()

在SqlSessionFactoryBuilder().build方法 中最终调用Configuration对象的addMappper()方法(实际上是委托给MapperRegistry的addMapper)添加对应的MapperProxyFactory代理工厂类,最终通过这个工厂类生成对应的代理对象MapperProxy 。

也就是MapperRegistry内部维护一个映射关系,每个接口对应一个MapperProxyFactory(生成动态代理工厂类)

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

这样便于在后面调用MapperRegistry的getMapper()时,直接从Map中获取某个接口对应的动态代理工厂类,然后再利用工厂类针对其接口生成真正的动态代理类。


如果想了解什么是FactoryBean是什么,可以查看前文究竟FactoryBean是什么?深入理解Spring的工厂神器

更详细的内容可以查看我之前的文章:超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?


而我们现在在Spring框架中整合Mybatis时,我们通常会使用MapperFactoryBean来生成Mapper的代理实例,也就是不需要再通过new SqlSessionFactoryBuilder().build(xml)的方式去注册动态代理接口。这是一种更简单且易于配置的方式,可让我们以Spring的形式操作Mybatis的持久层。本文将深入探索MapperFactoryBean的工作原理,并说明如何将Mybatis和Spring框架结合起来,以构建一个响应迅速而又易于维护的数据访问层。

MapperFactoryBean的工作原理

当应用启动时,Spring容器会为每个MapperFactoryBean生成一个相应的Bean实例。这个过程包含了几个关键步骤:

  • Bean的定义:在Spring配置文件中定义MapperFactoryBean,这包括指定其sqlSessionFactorysqlSessionTemplate
  • Bean的实例化:Spring容器将调用MapperFactoryBeangetObject()方法,这个方法内部又会调用Mybatis的SqlSession.getMapper()
  • 生成Mapper代理:正如前面提到的,Mybatis使用动态代理技术生成代理对象。这个过程由Mybatis内部的MapperProxyFactory完成。
  • Bean的使用:最终创建的Mapper被注入到其他组件中,这样,业务代码就可以通过普通的Java方法调用来执行SQL操作了。

下面我们看看实际的配置代码示例:

<!-- Mybatis的SqlSessionFactory配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="mapperLocations" value="classpath*:mapper/*.xml" />
</bean><!-- Mapper接口对应的FactoryBean配置 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="mapperInterface" value="com.example.mapper.UserMapper" /><property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

当然,在Spring的Java配置中,我们通常用注解来代替上述XML配置,得益于Spring的@MapperScan,可以大幅简化这个配置:

@Configuration
@MapperScan("com.example.mapper")
public class AppConfig {@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);// ...其他配置...return sessionFactory.getObject();}
}

底层实现剖析

MapperFactoryBean的checkDaoConfig()方法

MapperFactoryBean本身extend自SqlSessionDaoSupport,SqlSessionDaoSupport又extend自DaoSupport接口,DaoSupport接口实现了InitializingBean接口,在对象初始化的时候会调用它的afterPropertiesSet方法,该方法中首先调用了checkDaoConfig()方法,MapperFactoryBean重载的checkDaoConfig()如下面所示—>这里最终会将调用configuration.addMapper(this.mapperInterface)(实际也是委托给MapperRegistry)

微信公众号:bugstack虫洞栈 & MapperFactoryBean类图

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {private Class<T> mapperInterface;public void setMapperInterface(Class<T> mapperInterface) {this.mapperInterface = mapperInterface;}protected void checkDaoConfig() {super.checkDaoConfig();Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");Configuration configuration = this.getSqlSession().getConfiguration();if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {try {configuration.addMapper(this.mapperInterface);} catch (Exception var6) {this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);throw new IllegalArgumentException(var6);} finally {ErrorContext.instance().reset();}}}@Overridepublic T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);}// ...
}

checkDaoConfig方法中,会检查mapperInterface是否已设置,符合Spring管理Bean生命周期的要求。

接着通过configuration.addMapper(this.mapperInterface)方法重点关注,最终实现是在MapperRegistry中:
到这里以后,跟我之前文章超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?解析的步骤又是一样的了

new SqlSessionFactoryBuilder().build(xml)-->XMLConfigBuilder#parse-->>XMLConfigBuilder#parseConfiguration--->XMLConfigBuilder#mapperElement-->XMLMapperBuilder#mapperParser.parse()-->XMLMapperBuilder#configurationElement-->XMLMapperBuilder#bindMapperForNamespace-->Configuration#MapperRegistry#addMappper()

  public <T> void addMapper(Class<T> type) {if (type.isInterface()) {if (hasMapper(type)) {throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {knownMappers.put(type, new MapperProxyFactory<T>(type));// It's important that the type is added before the parser is run// otherwise the binding may automatically be attempted by the// mapper parser. If the type is already known, it won't try.MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}}

parser.parse()完成了对mapper对应xml的解析成MappedStatement,并添加到了configuration对象中,这里的configuration也就是我们上面提到的new Configuration()创建的那个对象(非常重要)。

总结

mapper接口的定义在bean加载阶段会被替换成MapperFactoryBean类型,在spring容器初始化的时候会给我们生成MapperFactoryBean类型的对象,在该对象生成的过程中调用afterPropertiesSet()方法,为我们生成了一个MapperProxyFactory类型的对象存放于Configuration里的MapperRegistry对象中,同时解析了mapper接口对应的xml文件,把每一个方法解析成一个MappedStatement对象,存放于Configuration里mappedStatements这个Map集合中。

MapperFactoryBean的getObject()方法

MapperFactoryBean实现了FactoryBean接口,实现了FactoryBean接口的类型在调用getBean(beanName)既通过名称获取对象时,返回的对象不是本身类型的对象,而是通过实现接口中的getObject()方法返回的对象。

这里需要对spring的声明周期有一定的了解:下面是简化版的MapperFactoryBean的链路调用

getObject()--->doGetBean()--->getObjectForBeanInstance()--->getObjectFromFactoryBean()--->doGetObjectFromFactoryBean--->MapperFactoryBean.getObject()方法

protected <T> T doGetBean(final String name, final Object[] args) {Object sharedInstance = getSingleton(name);if (sharedInstance != null) {// 如果是 FactoryBean,则需要调用 FactoryBean#getObjectreturn (T) getObjectForBeanInstance(sharedInstance, name);}BeanDefinition beanDefinition = getBeanDefinition(name);//这里如果是MapperFactoryBean对象,初始化完成以后会进入下面的判断Object bean = createBean(name, beanDefinition, args);//这里如果是MapperFactoryBean对象,初始化完成以后会进入下面的判断return (T) getObjectForBeanInstance(bean, name);}private Object getObjectForBeanInstance(Object beanInstance, String beanName) {if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}Object object = getCachedObjectForFactoryBean(beanName);if (object == null) {FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;//这里如果是MapperFactoryBean对象,初始化完成以后会进入这里的逻辑object = getObjectFromFactoryBean(factoryBean, beanName);}return object;}

FactoryBeanRegistrySupport的方法getObjectFromFactoryBean--->doGetObjectFromFactoryBean()--->factory.getObject()方法

    protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName) {if (factory.isSingleton()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {//这里如果是MapperFactoryBean对象,初始化完成以后会进入这里的逻辑object = doGetObjectFromFactoryBean(factory, beanName);this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));}return (object != NULL_OBJECT ? object : null);} else {return doGetObjectFromFactoryBean(factory, beanName);}}private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName){try {//最终调用MapperFactoryBean的getObject方法获取实际的对象return factory.getObject();} catch (Exception e) {throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);}}

MapperFactoryBean的getObject()方法

public T getObject() throws Exception {return this.getSqlSession().getMapper(this.mapperInterface);
}

走到这里,是不是也跟我之前文章超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?解析的步骤又是一样的了

getMapper方法的大致调用逻辑链是: SqlSession#getMapper() ——> Configuration#getMapper() ——> MapperRegistry#getMapper() ——> MapperProxyFactory#newInstance() ——> Proxy#newProxyInstance()–>MapperProxy#invoke–>MapperMethod#execute

思考联想

  • 在之前的文章中超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?我们通过new SqlSessionFactoryBuilder().build(xml)最终调用委托给Configuration#MapperRegistry#addMappper() 方法进行mapper接口的注册,而在Spring结合mybatis的过程中,我们通过MapperFactoryBean的checkDaoConfig()最终调用委托给Configuration#MapperRegistry#addMappper() 方法进行mapper接口的注册方法实现,本质上是一样的。

  • 在之前的文章中超硬核解析Mybatis动态代理原理!只有接口没实现也能跑?,我们又通过SqlSessionFactory的openSession()新建一个SqlSession,然后通过session#getMapper()最终调用委托给MapperRegistry#getMapper()——> MapperProxyFactory#newInstance() 方法实现代理对象的生成,而在Spring结合mybatis的过程中,我们通过MapperFactoryBean的getObject()调用this.getSqlSession().getMapper(this.mapperInterface)最终也是委托给MapperRegistry#getMapper()——> MapperProxyFactory#newInstance() 方法实现代理对象的生成,本质也是一样的道理。

后续

刚刚上面的例子我们可以发现:每配置一个mapper,都需要写一个对应的MapperFactoryBean,如果mapper多了这样是很繁琐的。

<!-- Mapper接口对应的FactoryBean配置 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="mapperInterface" value="com.example.mapper.UserMapper" /><property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

为了解决这个问题,我们可以使用MapperScannerConfigurer,让它扫描特定的包,自动帮我们成批的创建映射器。这样一来,就能大大减少配置的工作量。具体的实现原理我们后面再进行讲解。

<!-- 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 注入sqlSessionFactory --><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/><!-- 给出需要扫描Dao接口包 --><property name="basePackage" value="com.joe.dao"/></bean>

相关文章:

Mybatis与Spring结合深探——MapperFactoryBean的奥秘

文章目录 前言MapperFactoryBean的工作原理底层实现剖析MapperFactoryBean的checkDaoConfig()方法总结 MapperFactoryBean的getObject()方法 思考联想后续 系列相关相关文章究竟FactoryBean是什么&#xff1f;深入理解Spring的工厂神器超硬核解析Mybatis动态代理原理&#xff0…...

processon使用及流程图和泳道图的绘画(登录界面流程图,门诊流程图绘制门诊泳道图,住院泳道图,OA会议泳道图),Axure自定义元件

目录 一.processon图形的使用场景介绍 二.流程图绘画 三.泳道图的绘画 1.绘制门诊流程图绘制门诊泳道图 2. 绘制住院泳道图​编辑 3.绘制药库采购入库流程图 4.绘制OA会议泳道图 四.Axure自定义元件 1.Axure载入元件库 一.processon图形的使用场景介绍 二.流程图绘画 示例&…...

【虹科干货】关于JSON数据库

文章速览&#xff1a; 什么是JSON什么是JSON数据库JSON数据库的显著优势关于JSON数据库的Q&A 如何理解JSON数据库&#xff1f;作为NoSQL数据库的一种类型&#xff0c;JSON数据库有哪些优势呢&#xff1f;JSON数据库如何运作&#xff0c;它为应用程序开发者带来了哪些价值呢…...

区块链的可拓展性研究【03】扩容整理

为什么扩容&#xff1a;在layer1上&#xff0c;交易速度慢&#xff0c;燃料价格高 扩容的目的&#xff1a;在保证去中心化和安全性的前提下&#xff0c;提升交易速度&#xff0c;更快确定交易&#xff0c;提升交易吞吐量&#xff08;提升每秒交易量&#xff09; 目前方案有&…...

golang学习笔记——互斥锁sync.Mutex、计数器sync.WaitGroup、读写锁sync.RWMutex

文章目录 互斥锁&#xff1a; sync.Mutexsync.WaitGroup 计数器例子func (*WaitGroup) Addfunc (*WaitGroup) Donefunc (*WaitGroup) Wait 读写互斥锁参考资料 临界区总是需要通过同步机制进行保护的&#xff0c;否则就会产生竞态条件&#xff0c;导致数据不一致。 互斥锁&…...

MFC 加载本地文件设置图标

基于单文件/多文件版 1、在CMainFrame中设置 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {//...........// 从本地文件加载图标HICON hIcon (HICON)::LoadImage(NULL, L"./vip.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);if (hIcon){ // 设置窗口图…...

飞天使-linux操作的一些技巧与知识点6-ansible结合jinja2使用,可规范化进行自动化管控

文章目录 在议playbook虚拟环境中安装ansibleplaybook 结合变量的一些演示普通的vars_files 变量&#xff0c;在同级目录创建目录使用host_vars 定义变量group_vars定义变量根据不同系统操作不同版本传递多个外置变量举例几个不同的示例factswhenloophandlers 与 notifytags 任…...

ROS2 Control分析讲解

ROS2 Control 文章目录 前言简述组成安装 框架Controller ManagerResource ManagerControllersUser Interfaces Hardware ComponentsURDF中的硬件描述机器人运行框架 总结 前言 ros2_control是一个使用&#xff08;ROS 2&#xff09;进行机器人&#xff08;实时&#xff09;控…...

Java TCP(一对一)聊天简易版

客户端 import java.io.*; import java.net.Socket; import java.util.Date; import javax.swing.*;public class MyClient {private JFrame jf;private JButton jBsend;private JTextArea jTAcontent;private JTextField jText;private JLabel JLcontent;private Date data;p…...

2.4 C语言之运算符

2.4 C语言之运算符 一、算术运算符二、关系运算符三、逻辑运算符四、自增自减运算符五、按位运算符六、赋值运算符七、条件表达式八、运算符优先级与求值次序 一、算术运算符 二元算术运算符包括&#xff1a;(加)、-(减)、*(乘)、/(除)、%(取模) 整数除法会截断结果中的小数部…...

做题笔记:SQL Sever 方式做牛客SQL的题目--SQL157

----SQL157 平均播放进度大于60%的视频类别 计算各类视频的平均播放进度&#xff0c;将进度大于60%的类别输出。 注&#xff1a; 播放进度播放时长视频时长*100%&#xff0c;当播放时长大于视频时长时&#xff0c;播放进度均记为100%。 结果保留两位小数&#xff0c;并按播放进…...

微信小程序map视野发生改变时切换定位点

<!--地图--> <view><map id"myMap" style"width: 100%; height: 300px;" latitude"{{latitude}}" longitude"{{longitude}}"scale"{{scale}}" markers"{{markers}}" controls"{{controls}}&q…...

javaweb搭配ajax和json

ajax一般用来前端界面与后端界面交互使用。数据格式一般使用json&#xff0c;优点是便于对象与字符串的转化。 1.不适用json对象封装。 jsp: <script>$.ajax({url: "/LoginServlet",data: {"name":name, "pwd":password},dataType: &qu…...

VS2022 将项目打包,导出为exe运行

我有一个在 VS2022 上开发的程序&#xff0c;基于.net 6框架, 想打包成 .exe程序&#xff0c;以在另一个没有安装VS的机器上运行&#xff0c;另一个机器是Win7系统&#xff0c;上面安装了.net 6框架。 虽然网上很多教程&#xff0c;需要安装Project Installer&#xff0c;配置A…...

【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试【DP】2023C-分班【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章目录 题目描述与示例题目描述输入描述输出描述示例一输入输出 示例二输入输出 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目描述与示例 题目描述 幼儿园两个班的小朋友在排队时混在了一起&#xff0c;每位小朋友都知道自己是否与前…...

pr模板哪个网站好?免费Pr模板视频素材下载网站 Prmuban.com

pr模板哪个网站好&#xff1f;哪里可以下载免费的pr模板视频素材&#xff0c;PR模板网&#xff08;Prmuban.com&#xff09;影视后期制作模板视频剪辑素材资源网站。 包含PR模板、PR插件、PR预设、MOGRT、LUT、转场特效、音乐素材、音效素材等&#xff0c;更好的剪辑师必备资源…...

【论文阅读】LoRA: Low-Rank Adaptation of Large Language Models

code&#xff1a;GitHub - microsoft/LoRA: Code for loralib, an implementation of "LoRA: Low-Rank Adaptation of Large Language Models" 做法&#xff1a; 把预训练LLMs里面的参数权重给冻结&#xff1b;向transformer架构中的每一层&#xff0c;注入可训练的…...

MybatisPlus的分页插件

PaginationInnerInterceptor 此插件是核心插件,目前代理了 Executor#query 和 Executor#update 和 StatementHandler#prepare 方法。 在SpringBoot环境中配置方式如下&#xff1a; /*** author giserDev* description 配置分页插件、方言、mapper包扫描等* date 2023-12-13 …...

保障网络安全:了解威胁检测和风险评分的重要性

在当今数字时代&#xff0c;网络安全问题变得愈发突出&#xff0c;而及时发现和迅速应对潜在威胁成为保障组织信息安全的首要任务。令人震惊的是&#xff0c;根据2023年的数据&#xff0c;平均而言&#xff0c;检测到一次网络入侵的时间竟然长达207天。这引起了对安全策略和技术…...

3D摄影棚布光:Set A Light 3D Studio

Set A Light 3D Studio是一款专业的灯光模拟软件&#xff0c;旨在帮助摄影师和电影制片人在电脑上进行虚拟灯光布置和场景模拟&#xff0c;以实现更加精准和高质量的拍摄效果。该软件提供了丰富的灯光和场景模型&#xff0c;支持灵活调整光源位置、强度、颜色和效果等参数&…...

#HarmonyOS:应用的包名配置--应用图标和标签配置--配置链接

配置相关 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/application-component-configuration-stage-0000001478340869-V2 应用的包名配置 应用需要在工程的AppScope目录下的app.json5配置文件中配置bundleName标签&#xff0c;该标签用于标识应用的唯…...

docker小白第三天

docker小白第三天 docker为什么会比虚拟机快 1、docker有着比虚拟机更少的抽象层。不需要Hypervisor实现硬件资源虚拟化&#xff0c;运行在docker容器上的程序直接使用的都是实际物理机的硬件资源&#xff0c;因此在CPU、内存利用率上docker将会在效率上有明显优势。 2、dock…...

FFmpegd的AVBSF

本章主要介绍AVBSF 文章目录 结构体定义对外函数常见的过滤器 从名字我们可以知道这是个码流过滤器&#xff0c;我们最常用的是一个叫做h264_mp4toannexb_bsf的东东 这个过滤器的作用是把h264以MP4格式的NALU转换为annexb&#xff08;0x000001&#xff09; const AVBitStreamF…...

深圳三男子写字楼内吸烟被罚,快用富维AI神器,实时监控防火灾

最近&#xff0c;在深圳&#xff0c;一专项控烟督查组在福田区新华保险大厦发现三名男子在写字楼内楼道违法吸烟&#xff0c;并对其进行了现场处罚。根据《控烟条例》&#xff0c;这类室内区域严禁吸烟&#xff0c;但人们往往忽视这一规定&#xff0c;从而引发潜在的安全风险。…...

有哪些已经上线的vue商城项目?

前言 下面是一些商城的项目&#xff0c;需要练手的同学可以挑选一些来练&#xff0c;废话少说&#xff0c;让我们直接开始正题~~ 1、newbee-mall-vue3-app 是一个基于 Vue 3 和 TypeScript 的电商前端项目&#xff0c;它是 newbee-mall 项目的升级版。该项目包含了商品列表、…...

Nginx服务器配置SSL证书

本文将全面介绍如何在Nginx或Tengine服务器配置SSL证书&#xff0c;具体包括下载和上传证书文件&#xff0c;在Nginx上配置证书文件、证书链和证书密钥等参数&#xff0c;以及安装证书后结果的验证。成功配置SSL证书后&#xff0c;您将能够通过HTTPS加密通道安全访问Nginx服务器…...

【JVM从入门到实战】(六)类加载器的双亲委派机制

一、双亲委派机制 在Java中如何使用代码的方式去主动加载一个类呢&#xff1f; 方式1&#xff1a;使用Class.forName方法&#xff0c;使用当前类的类加载器去加载指定的类。 方式2&#xff1a;获取到类加载器&#xff0c;通过类加载器的loadClass方法指定某个类加载器加载。 …...

SpringCloud面试题及答案(最新50道大厂版,持续更新)

在Java开发中&#xff0c;Spring Cloud作为微服务架构的关键组成部分&#xff0c;为了帮助广大Java技术爱好者和专业开发人员深入理解Spring Cloud&#xff0c;本文《SpringCloud面试题及答案&#xff08;最新50道大厂版&#xff0c;持续更新&#xff09;》提供了最前沿、最实用…...

Next.js 的设计理念

Next.js 的设计理念&#xff1a;简洁、强大与高效 Next.js 是一个流行的 React 框架&#xff0c;由 Vercel 公司开发。它的设计理念是简洁、强大和高效&#xff0c;这种理念贯穿于 Next.js 的所有功能中。下面我们将深入探讨这三个设计理念。 简洁 Next.js 的一个核心设计理…...

26、文件包含

文章目录 一、文件包含1.1 概念1.2 PHP文件包含原理1.3 文件包含重要函数1.4 文件包含利用条件 二、文件包含漏洞利用2.1 文件包含分类2.2 常见敏感文件2.3 包含Apache日志文件2.4 常见中间件的日志路径2.5 包含其他日志文件2.5.1 SSH日志文件2.5.2 Session文件 三、PHP封装伪协…...