【设计模式】从Mybatis源码中学习到的10种设计模式
文章目录
- 一、前言
- 二、源码:学设计模式
- 三、类型:创建型模式
- 1. 工厂模式
- 2. 单例模式
- 3. 建造者模式
- 四、类型:结构型模式
- 1. 适配器模式
- 2. 代理模式
- 3. 组合模式
- 4. 装饰器模式
- 五、类型:行为型模式
- 1. 模板模式
- 2. 策略模式
- 3. 迭代器模式
- 六、总结
一、前言
“为什么学设计模式、看框架源码、补技术知识,就一个普通的业务项目,会造飞机不也是天天写CRUD吗?”
你说的没错,但你天天写CRUD,你觉得烦不? 慌不? 是不是既担心自己没有得到技术成长,也害怕将来没法用这些都是CRUD的项目去参加述职、晋升、答辩,甚至可能要被迫面试时,自己手里一点干货也没有的情况。
所以,当然要扩充自己的知识储备,否则架构,架构思维不懂、设计,设计模式不会、源码、源码学习不深
,最后就用一堆CRUD写简历吗?
二、源码:学设计模式
在 Mybatis 两万多行的框架源码实现中,使用了大量的设计模式来解耦工程架构中面对复杂场景的设计,这些是设计模式的巧妙使用才是整个框架的精华
,整理有如下10种设计模式的使用,如图所示
讲道理,如果只是把这10种设计模式背下来,等着下次面试的时候拿出来说一说,虽然能有点帮助,不过这种学习方式就真的算是把路走窄了。就像你每说一个设计模式,能联想到这个设计模式在Mybatis的框架中,体现到哪个流程中的源码实现上了吗?这个源码实现的思路能不能用到你的业务流程开发里?别总说你的流程简单,用不上设计模式!
三、类型:创建型模式
1. 工厂模式
源码详见:com.demo.mybatis.session.SqlSessionFactory
public interface SqlSessionFactory {SqlSession openSession();}
源码详见:com.demo.mybatis.session.defaults.DefaultSqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory {private final Configuration configuration;public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}@Overridepublic SqlSession openSession() {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();TransactionFactory transactionFactory = environment.getTransactionFactory();tx = transactionFactory.newTransaction(configuration.getEnvironment().getDataSource(), TransactionIsolationLevel.READ_COMMITTED, false);// 创建执行器final Executor executor = configuration.newExecutor(tx);// 创建DefaultSqlSessionreturn new DefaultSqlSession(configuration, executor);} catch (Exception e) {try {assert tx != null;tx.close();} catch (SQLException ignore) {}throw new RuntimeException("Error opening session. Cause: " + e);}}}
- 工厂模式:简单工厂,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例对象的类型。
- 场景介绍:SqlSessionFactory 是获取会话的工厂,每次我们使用 Mybatis 操作数据库的时候,都会开启一个新的会话。在会话工厂的实现中负责获取数据源环境配置信息、构建事务工厂、创建操作SQL的执行器,并最终返回会话实现类。
- 同类设计:SqlSessionFactory、ObjectFactory、MapperProxyFactory、DataSourceFactory
2. 单例模式
源码详见:com.demo.mybatis.session.Configuration
public class Configuration {// 缓存机制,默认不配置的情况是 SESSIONprotected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;// 映射注册机protected MapperRegistry mapperRegistry = new MapperRegistry(this);// 映射的语句,存在Map里protected final Map<String, MappedStatement> mappedStatements = new HashMap<>();// 缓存,存在Map里protected final Map<String, Cache> caches = new HashMap<>();// 结果映射,存在Map里protected final Map<String, ResultMap> resultMaps = new HashMap<>();protected final Map<String, KeyGenerator> keyGenerators = new HashMap<>();// 插件拦截器链protected final InterceptorChain interceptorChain = new InterceptorChain();// 类型别名注册机protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();// 类型处理器注册机protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();// 对象工厂和对象包装器工厂protected ObjectFactory objectFactory = new DefaultObjectFactory();protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();protected final Set<String> loadedResources = new HashSet<>();//...
}
- 单例模式:是一种创建型模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。
- 场景介绍:Configuration 就像狗皮膏药一样大单例,贯穿整个会话的生命周期,所以的配置对象;映射、缓存、入参、出参、拦截器、注册机、对象工厂等,都在 Configuration 配置项中初始化。并随着 SqlSessionFactoryBuilder 构建阶段完成实例化操作。
- 同类场景:ErrorContext、LogFactory、Configuration
3. 建造者模式
源码详见:com.demo.mybatis.mapping.ResultMap#Builder
public class ResultMap {private String id;private Class<?> type;private List<ResultMapping> resultMappings;private Set<String> mappedColumns;private ResultMap() {}public static class Builder {private ResultMap resultMap = new ResultMap();public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings) {resultMap.id = id;resultMap.type = type;resultMap.resultMappings = resultMappings;}public ResultMap build() {resultMap.mappedColumns = new HashSet<>();// step-13 新增加,添加 mappedColumns 字段for (ResultMapping resultMapping : resultMap.resultMappings) {final String column = resultMapping.getColumn();if (column != null) {resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));}}return resultMap;}}// ... get
}
- 建造者模式:使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
- 场景介绍:关于建造者模式在 Mybatis 框架里的使用,那真是纱窗擦屁股,给你漏了一手。到处都是 XxxxBuilder,所有关于 XML 文件的解析到各类对象的封装,都使用建造者以及建造者助手来完成对象的封装。它的核心目的就是不希望把过多的关于对象的属性设置,写到其他业务流程中,而是用建造者的方式提供最佳的边界隔离。
- 同类场景:
SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder
四、类型:结构型模式
1. 适配器模式
源码详见:com.demo.mybatis.logging.Log
public interface Log {boolean isDebugEnabled();boolean isTraceEnabled();void error(String s, Throwable e);void error(String s);void debug(String s);void trace(String s);void warn(String s);}
源码详见:com.demo.mybatis.logging.slf4j.Slf4jImpl
public class Slf4jImpl implements Log {private Log log;public Slf4jImpl(String clazz) {Logger logger = LoggerFactory.getLogger(clazz);if (logger instanceof LocationAwareLogger) {try {// check for slf4j >= 1.6 method signaturelogger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class);log = new Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger);return;} catch (SecurityException e) {// fail-back to Slf4jLoggerImpl} catch (NoSuchMethodException e) {// fail-back to Slf4jLoggerImpl}}// Logger is not LocationAwareLogger or slf4j version < 1.6log = new Slf4jLoggerImpl(logger);}@Overridepublic boolean isDebugEnabled() {return log.isDebugEnabled();}@Overridepublic boolean isTraceEnabled() {return log.isTraceEnabled();}@Overridepublic void error(String s, Throwable e) {log.error(s, e);}@Overridepublic void error(String s) {log.error(s);}@Overridepublic void debug(String s) {log.debug(s);}@Overridepublic void trace(String s) {log.trace(s);}@Overridepublic void warn(String s) {log.warn(s);}}
- 适配器模式:是一种结构型设计模式,它能使接口不兼容的对象能够相互合作。
- 场景介绍:正是因为有太多的日志框架,包括:Log4j、Log4j2、Slf4J等等,而这些日志框架的使用接口又都各有差异,为了统一这些日志工具的接口,Mybatis 定义了一套统一的日志接口,为所有的其他日志工具接口做相应的适配操作。
- 同类场景:主要集中在对日志的适配上,Log 和 对应的实现类,以及在 LogFactory 工厂方法中进行使用。
Mybatis 适配器模式
2. 代理模式
源码详见:com.demo.mybatis.binding.MapperProxy
public class MapperProxy<T> implements InvocationHandler, Serializable {private static final long serialVersionUID = -6424540398559729838L;private SqlSession sqlSession;private final Class<T> mapperInterface;private final Map<Method, MapperMethod> methodCache;public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {this.sqlSession = sqlSession;this.mapperInterface = mapperInterface;this.methodCache = methodCache;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else {final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);}}// ...}
- 代理模式:是一种结构型模式,让你能够提供对象的替代品或其占位符。代理控制着对原对象的访问,并允许在将请求提交给对象前进行一些处理。
- 场景介绍:不吹牛的讲,没有代理模式,就不会有各类的框架存在。就像 Mybatis 中的 MapperProxy 映射器代理实现类,它所实现的功能就是帮助我们完成 DAO 接口的具体实现类的方法操作,你的任何一个配置的 DAO 接口所调用的 CRUD 方法,都会被 MapperProxy 接管,调用到方法执行器等一系列操作,并返回最终的数据库执行结果。
- 同类场景:
DriverProxy、Plugin、Invoker、MapperProxy
3. 组合模式
源码详见:com.demo.mybatis.scripting.xmltags.SqlNode
public interface SqlNode {boolean apply(DynamicContext context);}
源码详见:com.demo.mybatis.scripting.xmltags.IfSqlNode
public class IfSqlNode implements SqlNode{private ExpressionEvaluator evaluator;private String test;private SqlNode contents;public IfSqlNode(SqlNode contents, String test) {this.test = test;this.contents = contents;this.evaluator = new ExpressionEvaluator();}@Overridepublic boolean apply(DynamicContext context) {// 如果满足条件,则apply,并返回trueif (evaluator.evaluateBoolean(test, context.getBindings())) {contents.apply(context);return true;}return false;}}
源码详见:com.demo.mybatis.scripting.xmltags.XMLScriptBuilder
public class XMLScriptBuilder extends BaseBuilder {private void initNodeHandlerMap() {// 9种,实现其中2种 trim/where/set/foreach/if/choose/when/otherwise/bindnodeHandlerMap.put("trim", new TrimHandler());nodeHandlerMap.put("if", new IfHandler());}List<SqlNode> parseDynamicTags(Element element) {List<SqlNode> contents = new ArrayList<>();List<Node> children = element.content();for (Node child : children) {if (child.getNodeType() == Node.TEXT_NODE || child.getNodeType() == Node.CDATA_SECTION_NODE) {} else if (child.getNodeType() == Node.ELEMENT_NODE) {String nodeName = child.getName();NodeHandler handler = nodeHandlerMap.get(nodeName);if (handler == null) {throw new RuntimeException("Unknown element " + nodeName + " in SQL statement.");}handler.handleNode(element.element(child.getName()), contents);isDynamic = true;}}return contents;}// ...
}
配置详见:resources/mapper/Activity_Mapper.xml
<select id="queryActivityById" parameterType="com.demo.mybatis.test.po.Activity" resultMap="activityMap" flushCache="false" useCache="true">SELECT activity_id, activity_name, activity_desc, create_time, update_timeFROM activity<trim prefix="where" prefixOverrides="AND | OR" suffixOverrides="and"><if test="null != activityId">activity_id = #{activityId}</if></trim>
</select>
- 组合模式:是一种结构型设计模式,你可以使用它将对象组合成树状结构,并且能独立使用对象一样使用它们。
- 场景介绍:在 Mybatis XML 动态的 SQL 配置中,共提供了9种(trim/where/set/foreach/if/choose/when/otherwise/bind)标签的使用,让使用者可以组合出各类场景的 SQL 语句。而 SqlNode 接口的实现就是每一个组合结构中的规则节点,通过规则节点的组装完成一颗规则树组合模式的使用。
- 同类场景:主要体现在对各类SQL标签的解析上,以实现 SqlNode 接口的各个子类为主。
4. 装饰器模式
源码详见:com.demo.mybatis.session.Configuration
public Executor newExecutor(Transaction transaction) {Executor executor = new SimpleExecutor(this, transaction);// 配置开启缓存,创建 CachingExecutor(默认就是有缓存)装饰者模式if (cacheEnabled) {executor = new CachingExecutor(executor);}return executor;
}
- 装饰器模式:是一种结构型设计模式,允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
- 场景介绍:Mybatis 的所有 SQL 操作,都是经过 SqlSession 会话调用 SimpleExecutor 简单实现的执行器完成的,而一级缓存的操作也是在简单执行器中处理。那么这里二级缓存因为是基于一级缓存刷新操作的,所以在实现上,通过创建一个缓存执行器,包装简单执行器的处理逻辑,实现二级缓存操作。那么这里用到的就是装饰器模式,也叫俄罗斯套娃模式。
- 同类场景:主要提前在 Cache 缓存接口的实现和 CachingExecutor 执行器中。
五、类型:行为型模式
1. 模板模式
源码详见:com.demo.mybatis.executor.BaseExecutor
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {if (closed) {throw new RuntimeException("Executor was closed.");}// 清理局部缓存,查询堆栈为0则清理。queryStack 避免递归调用清理if (queryStack == 0 && ms.isFlushCacheRequired()) {clearLocalCache();}List<E> list;try {queryStack++;// 根据cacheKey从localCache中查询数据list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;if (list == null) {list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}} finally {queryStack--;}if (queryStack == 0) {if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {clearLocalCache();}}return list;
}
源码详见:com.demo.mybatis.executor.SimpleExecutor
protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {Statement stmt = null;try {Configuration configuration = ms.getConfiguration();// 新建一个 StatementHandlerStatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);// 准备语句stmt = prepareStatement(handler);// StatementHandler.updatereturn handler.update(stmt);} finally {closeStatement(stmt);}
}
- 模板模式:是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
- 场景介绍:只要存在一系列可被标准定义的流程,在流程的步骤大部分是通用逻辑,只有一少部分是需要子类实现的,那么通常会采用模板模式来定义出这个标准的流程。就像 Mybatis 的 BaseExecutor 就是一个用于定义模板模式的抽象类,在这个类中把查询、修改的操作都定义出了一套标准的流程。
- 同类场景:
BaseExecutor、SimpleExecutor、BaseTypeHandler
2. 策略模式
源码详见:com.demo.mybatis.type.TypeHandler
public interface TypeHandler<T> {/*** 设置参数*/void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;/*** 获取结果*/T getResult(ResultSet rs, String columnName) throws SQLException;/*** 取得结果*/T getResult(ResultSet rs, int columnIndex) throws SQLException;}
源码详见:com.demo.mybatis.type.LongTypeHandler
public class LongTypeHandler extends BaseTypeHandler<Long> {@Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {ps.setLong(i, parameter);}@Overrideprotected Long getNullableResult(ResultSet rs, String columnName) throws SQLException {return rs.getLong(columnName);}@Overridepublic Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return rs.getLong(columnIndex);}}
- 策略模式:是一种行为设计模式,它能定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够互相替换。
- 场景介绍:在 Mybatis 处理 JDBC 执行后返回的结果时,需要按照不同的类型获取对应的值,这样就可以避免大量的 if 判断。所以这里基于 TypeHandler 接口对每个参数类型分别做了自己的策略实现。
- 同类场景:
PooledDataSource\UnpooledDataSource、BatchExecutor\ResuseExecutor\SimpleExector\CachingExecutor、LongTypeHandler\StringTypeHandler\DateTypeHandler
3. 迭代器模式
源码详见:com.demo.mybatis.reflection.property.PropertyTokenizer
public class PropertyTokenizer implements Iterable<PropertyTokenizer>, Iterator<PropertyTokenizer> {public PropertyTokenizer(String fullname) {// 班级[0].学生.成绩// 找这个点 .int delim = fullname.indexOf('.');if (delim > -1) {name = fullname.substring(0, delim);children = fullname.substring(delim + 1);} else {// 找不到.的话,取全部部分name = fullname;children = null;}indexedName = name;// 把中括号里的数字给解析出来delim = name.indexOf('[');if (delim > -1) {index = name.substring(delim + 1, name.length() - 1);name = name.substring(0, delim);}}// ...}
- 迭代器模式:是一种行为设计模式,让你能在不暴露集合底层表现形式的情况下遍历集合中所有的元素。
- 场景介绍:PropertyTokenizer 是用于 Mybatis 框架 MetaObject 反射工具包下,用于解析对象关系的迭代操作。这个类在 Mybatis 框架中使用的非常频繁,包括解析数据源配置信息并填充到数据源类上,以及参数的解析、对象的设置都会使用到这个类。
- 同类场景:
PropertyTokenizer
六、总结
一份源码的成体系拆解渐进式学习,可能需要1~2个月的时间,相比于爽文和疲于应试要花费更多的经历。但你总会在一个大块时间学习完后,会在自己的头脑中构建出一套完整体系关于此类知识的技术架构,无论从哪里入口你都能清楚各个分支流程的走向,这也是你成为技术专家路上的深度学习。
相关文章:

【设计模式】从Mybatis源码中学习到的10种设计模式
文章目录 一、前言二、源码:学设计模式三、类型:创建型模式1. 工厂模式2. 单例模式3. 建造者模式 四、类型:结构型模式1. 适配器模式2. 代理模式3. 组合模式4. 装饰器模式 五、类型:行为型模式1. 模板模式2. 策略模式3. 迭代器模式…...

爬虫攻守道 - 猿人学第20题 - 殊途同归
写在开头 这题也是,自己搞顶多追踪到wasm代码,然后就走不下去了。找了2个参考方案,自己做的过程中还又遇到些新的问题,下面做个记录。解法1参考文章解法2参考文章 解法1:追根溯源 在 JS 代码中追踪到 Payload 赋值位…...

4.11日报
synchronized 和 ReentrantLock 区别是什么? synchronized 早期的实现比较低效,对比 ReentrantLock,大多数场景性能都相差较大,但是在 Java 6 中对 synchronized 进行了非常多的改进。 主要区别如下: ReentrantLock …...

【LeetCode每日一题: 1039. 多边形三角剖分的最低得分 | 暴力递归=>记忆化搜索=>动态规划 | 区间dp 】
🍎作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎 🍎座右…...

Okio 网络提速
文章目录网络数据处理流程Page Cache传统 I/O 拷贝的性能问题零拷贝技术DMA 技术零拷贝技术分类mmapsendfilespliceDirect I/O零拷贝技术性能分析小结OkioOkio 的使用Okio 网络提速的原理Okio 总结总结网络数据处理流程 在讲 Okio 之前,为了能更好的了解 Okio 的优…...

自动驾驶企业面临哪些数据安全挑战?
近期,“特斯拉员工被曝私下分享用户隐私”不可避免地成了新闻热点,据说连马斯克也不能幸免。 据相关媒体报道,9名前特斯拉员工爆料在2019年至2022年期间,特斯拉员工通过内部消息系统私下分享了一些车主车载摄像头记录的隐私视频和…...

Doris(2):Doris编译部署
1 Doris编译 Apache Doris提供直接可以部署的版本压缩包:https://cloud.baidu.com/doc/PALO/s/Ikivhcwb5 也可以自行编译压缩包后使用(推荐) 1.1 使用 Docker 开发镜像编译(推荐) 这个是官方文档推荐的,…...

使用MyBatis实现简单查询
文章目录一,创建数据库与表(一)在Navicat里创建MySQL数据库testdb(二)创建用户表 - t_user(三)在用户表里插入3条记录二,案例演示MyBatis基本使用(一)创建Mav…...

C指针(*point)[4]和char *point[4]
char (*point)[4] // 数组指针。 a[3][4] // 先申明二维数组,用它来指向这个二维数组. char *point[4] // 指针数组。 a[4][5] // 一连串的指针. char (*point)[4] // 一个指针,指向有4个元素的数组;占内存大小为 4 个字节 ch…...

【Bard】谷歌的人工智能工具—Bard初体验
文章目录一、Bard介绍二、Bard体验1、加入Bard的候补名单2、登入Bard篇3、使用Bard篇(1)提供三种预选方式✨(2)创作生成各类文案(3)无生成图画能力(4)支持语音转文本输入✨ÿ…...

2022国赛30:windows脚本题解析
大赛试题内容: ( 九) ) 脚本 【任务描述】 为了减少重复性任务的工作量,节省人力和时间,请采用脚本,实现快速批量的操作。 1.在 windows4 上编写 C:\CreateFile.ps1 的 powershell 脚本,创建20 个文件 C:\test\File00.txt 至 C:\test\File19.txt,如果文件存在,则首先删除…...

Excel常用函数公式20例
目录 一、【IF函数条件判断】 二、【多条件判断】 三、【条件求和】 四、【多条件求和】 五、【条件计数】 六、【多条件计数】 七、【条件查找】 八、【多条件查找】 九、【计算文本算式】 十、【合并多个单元格内容】 十一、【合并带格式的单元格内容】 十二、…...

233:vue+openlayers绘制渐变填充色的圆形、多边形
第233个 点击查看专栏目录 本示例的目的是介绍如何在vue+openlayer中绘制带有渐变填充色的圆形、多边形。这里用canvas的方式去渲染,用到了DEVICE_PIXEL_RATIO,设备上的物理像素与设备无关像素 (dips) 之间的比率 (window.devicePixelRatio)。 直接复制下面的 vue+openlayer…...

Flink的窗口机制
窗口机制 tumble(滚动窗口) hop(滑动窗口) session(会话窗口) cumulate(渐进式窗口) Over(聚合窗口) 滚动窗口(tumble) 概念 滚…...

了解分布式Session
大家好,我这名CRUD工程师又来了,最近我的一个同事突然在看分布式Seesion的问题,然后我们两个也是互相讨论了一下,今天我就想着把分布式Session的知识点好好的梳理一下。 在很多系统中,用户的登录功能都是用Session去实…...

仿真创新大赛—国三省一 智能鱼缸(proteus)(stm32)
⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。 ⏩去年下半年参加了全国仿真创新大赛,也是取得了国赛三等奖,省赛一等奖的好成绩。 ⏩本篇文章对我们的参赛作品《智能鱼缸》做一个简介。 ⏩感…...

【ARMv8 编程】A64 数据处理指令——位域字节操作指令
有些指令将字节、半字或字扩展到寄存器大小,可以是 X 或 W。这些指令存在于有符号(SXTB、SXTH、SXTW)和无符号(UXTB、UXTH)变体中,并且是适当的位域操作指令。 这些指令的有符号和无符号变体都将字节、半字…...

ctfshow 愚人杯菜狗杯部分题目(flasksession伪造ssti)
目录 <1>愚人杯 (1) easy_signin (2) easy_ssti(无过滤ssti) (3) easy_flask(flash-session伪造) (4) easy_php(C:开头序列化数据) <2> 菜狗杯 (1) 抽老婆(flask_session伪造) (2) 一言既出,驷马难追(intval) (3) 传说之下(js控制台&…...

linux拓展笔记——【补充学习知识点】
文章目录1. ./configure --prefix中的prefix详解1. ./configure --prefix中的prefix详解 源码的安装一般由3个步骤组成:配置(configure)、编译(make)、安装(makeinstall)。 Configure是一个可执行脚本,在待安装的源码路径下使用命令./configure–help输…...

为何银行各岗位之间的薪酬差别如此之大?
银行里的职位种类相对较多,观观整理了5个最常见的职位,看一下你要申请的职位薪资水平到底是怎样的?根据如信银行考试中心发布: 1、客户经理岗 客户经理分为对公客户经理和对私客户经理,他们的主要工作不同࿰…...

TensorFlow 深度学习第二版:1~5
原文:Deep Learning with TensorFlow Second Edition 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 不要担心自己的形象,只…...

微前端micro-app的使用
演示效果 子应用的项目 基应用嵌入子应用效果图 目录 前言 一、微前端是什么? 它主要解决了两个问题: 二、使用步骤 1.安装依赖 2.在入口处引入 3.子应用的路由() 4.分配一个路由给子应用(重要)࿰…...

【JUC】Java内存模型之JMM
【JUC】Java内存模型之JMM 文章目录【JUC】Java内存模型之JMM1. 概念2. JMM三大特性2.1 可见性2.2 原子性2.3 有序性3. 多线程对变量的读写过程4. 先行发生原则——happens-before4.1 happens-before八条规则4.1.1 次序规则4.1.2 锁定规则4.1.3 volatile变量规则4.1.4 传递规则…...

Win11快速打开便签和使用技巧分享
Win11快速打开便签和使用技巧分享。Win11系统中为用户提供了一个非常实用的系统组件,就是便签功能,使用这个功能可以帮助我们便捷的进行一些重要内容的记录。那么如何去开启开启这个程序来使用呢?来看看以下的详情分享吧。 详细分享ÿ…...

CSS:横向导航栏
横向导航栏(盗版导航栏,B站仿写。) 原视频链接 <html><head><title>demo</title><style>*{margin: 0;padding: 0;list-style: none;text-decoration: none;}body{display: flex;justify-content: center;a…...

视频动态库测试及心得
视频动态库测试及心得 这几天一直在弄动态库测试,h给的写好的动态库--预处理模块的库。视频处理项目一部分,需要连接实际情况测试。 需求: 1.把实际相机连接到,并读取实时数据流,保存到双循环链表里面; 2.测试背景建模…...

陶泓达:4.18午间欧盘黄金原油最新精准操作建议!
黄金方面: 黄金消息面解析:周一(4月17日)美市盘中,美国公布的4月纽约联储制造业指数和4月NAHB房产市场指数均超出预期,提振了美联储在5月继续加息的预期。数据公布之后,美元指数加速上扬&#x…...

环境变量相关知识
目录 目录 谢谢你的阅读,这是对我最大的鼓舞 先说结论: 开始论述: 让我们举个例子 相关指令 创建本地变量 创建环境变量 方法一: 方法二: 删除环境变量 子进程中也有环境变量 第一种: 第二种 …...

如何快速入门ChatGPT
作为一个AI模型,ChatGPT并不需要像人一样“学习”,它已经通过大量的训练数据和算法进行了预训练,可以回答广泛的问题。 然而,如果你想学习如何使用ChatGPT来进行对话或者问答,以下是一些建议: 一、了解Ch…...

Akka定时任务schedule()方法
Akka定时任务schedule()方法 文章目录Akka定时任务schedule()方法什么是Akka定时任务schedule()方法?如何使用Akka定时任务schedule()方法?如何在actor外部获取Scheduler对象为什么需要提供一个隐式的ExecutionContext对象,用于执行定时任务&…...