Spring - Mybatis-設計模式總結

Mybatis-設計模式總結

1、Builder模式

2、工廠模式

3、單例模式

4、代理模式

5、組合模式

6、模板方法模式

7、適配器模式

8、裝飾者模式

9、迭代器模式

雖然我們都知道有26個設計模式,但是大多停留在概念層面,真實開發中很少遇到,Mybatis源碼中使用了大量的設計模式,閱讀源碼并觀察設計模式在其中的應用,能夠更深入的理解設計模式。

Mybatis至少遇到了以下的設計模式的使用:

Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder; 工廠模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory; 單例模式,例如ErrorContext和LogFactory; 代理模式,Mybatis實現的核心,比如MapperProxy、ConnectionLogger,用的jdk的動態代理;還有executor.loader包使用了cglib或者javassist達到延遲加載的效果; 組合模式,例如SqlNode和各個子類ChooseSqlNode等; 模板方法模式,例如BaseExecutor和SimpleExecutor,還有BaseTypeHandler和所有的子類例如IntegerTypeHandler; 適配器模式,例如Log的Mybatis接口和它對jdbc、log4j等各種日志框架的適配實現; 裝飾者模式,例如Cache包中的cache.decorators子包中等各個裝飾者的實現; 迭代器模式,例如迭代器模式PropertyTokenizer;

接下來挨個模式進行解讀,先介紹模式自身的知識,然后解讀在Mybatis中怎樣應用了該模式。

1、Builder模式

Builder模式的定義是“將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。”,它屬于創建類模式,一般來說,如果一個對象的構建比較復雜,超出了構造函數所能包含的范圍,就可以使用工廠模式和Builder模式,相對于工廠模式會產出一個完整的產品,Builder應用于更加復雜的對象的構建,甚至只會構建產品的一個部分。

0

在Mybatis環境的初始化過程中,SqlSessionFactoryBuilder會調用XMLConfigBuilder讀取所有的MybatisMapConfig.xml和所有的*Mapper.xml文件,構建Mybatis運行的核心對象Configuration對象,然后將該Configuration對象作為參數構建一個SqlSessionFactory對象。

其中XMLConfigBuilder在構建Configuration對象時,也會調用XMLMapperBuilder用于讀取*Mapper文件,而XMLMapperBuilder會使用XMLStatementBuilder來讀取和build所有的SQL語句。

在這個過程中,有一個相似的特點,就是這些Builder會讀取文件或者配置,然后做大量的XpathParser解析、配置或語法的解析、反射生成對象、存入結果緩存等步驟,這么多的工作都不是一個構造函數所能包括的,因此大量采用了Builder模式來解決。

對于builder的具體類,方法都大都用build*開頭,比如SqlSessionFactoryBuilder為例,它包含以下方法:

0

即根據不同的輸入參數來構建SqlSessionFactory這個工廠對象。

設計模式是什么鬼(建造者)

2、工廠模式

在Mybatis中比如SqlSessionFactory使用的是工廠模式,該工廠沒有那么復雜的邏輯,是一個簡單工廠模式。

簡單工廠模式(Simple Factory Pattern):又稱為靜態工廠方法(Static Factory Method)模式,它屬于類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。

0

SqlSession可以認為是一個Mybatis工作的核心的接口,通過這個接口可以執行執行SQL語句、獲取Mappers、管理事務。類似于連接MySQL的Connection對象。

0

可以看到,該Factory的openSession方法重載了很多個,分別支持autoCommit、Executor、Transaction等參數的輸入,來構建核心的SqlSession對象。

在DefaultSqlSessionFactory的默認工廠實現里,有一個方法可以看出工廠怎么產出一個產品:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit){ Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call // close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }

這是一個openSession調用的底層方法,該方法先從configuration讀取對應的環境配置,然后初始化TransactionFactory獲得一個Transaction對象,然后通過Transaction獲取一個Executor對象,最后通過configuration、Executor、是否autoCommit三個參數構建了SqlSession。

在這里其實也可以看到端倪,SqlSession的執行,其實是委托給對應的Executor來進行的。

而對于LogFactory,它的實現代碼:

public final class LogFactory { private static Constructor<? extends Log> logConstructor; private LogFactory() { // disable construction } public static Log getLog(Class<?> aClass) { return getLog(aClass.getName()); } }

這里有個特別的地方,是Log變量的的類型是Constructorextends?Log>,也就是說該工廠生產的不只是一個產品,而是具有Log公共接口的一系列產品,比如Log4jImpl、Slf4jImpl等很多具體的Log。

3、單例模式

單例模式(Singleton Pattern):單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統提供這個實例,這個類稱為單例類,它提供全局訪問的方法。

單例模式的要點有三個:一是某個類只能有一個實例;二是它必須自行創建這個實例;三是它必須自行向整個系統提供這個實例。單例模式是一種對象創建型模式。單例模式又名單件模式或單態模式。

0

在Mybatis中有兩個地方用到單例模式,ErrorContext和LogFactory,其中ErrorContext是用在每個線程范圍內的單例,用于記錄該線程的執行環境錯誤信息,而LogFactory則是提供給整個Mybatis使用的日志工廠,用于獲得針對項目配置好的日志對象。

ErrorContext的單例實現代碼:

public class ErrorContext { private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<ErrorContext>(); private ErrorContext() { } public static ErrorContext instance() { ErrorContext context = LOCAL.get(); if (context == null) { context = new ErrorContext(); LOCAL.set(context); } return context; } }

構造函數是private修飾,具有一個static的局部instance變量和一個獲取instance變量的方法,在獲取實例的方法中,先判斷是否為空如果是的話就先創建,然后返回構造好的對象。

只是這里有個有趣的地方是,LOCAL的靜態實例變量使用了ThreadLocal修飾,也就是說它屬于每個線程各自的數據,而在instance()方法中,先獲取本線程的該實例,如果沒有就創建該線程獨有的ErrorContext。

設計模式是什么鬼(單例)

4、代理模式

代理模式可以認為是Mybatis的核心使用的模式,正是由于這個模式,我們只需要編寫Mapper.java接口,不需要實現,由Mybatis后臺幫我們完成具體SQL的執行。

代理模式(Proxy Pattern) :給某一個對象提供一個代 理,并由代理對象控制對原對象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一種對象結構型模式。

代理模式包含如下角色:

  • Subject: 抽象主題角色
  • Proxy: 代理主題角色
  • RealSubject: 真實主題角色

0

0

這里有兩個步驟,第一個是提前創建一個Proxy,第二個是使用的時候會自動請求Proxy,然后由Proxy來執行具體事務;

當我們使用Configuration的getMapper方法時,會調用mapperRegistry.getMapper方法,而該方法又會調用mapperProxyFactory.newInstance(sqlSession)來生成一個具體的代理:

public class MapperProxyFactory<T> { private final Class<T> mapperInterface; private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>(); public MapperProxyFactory(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } public Class<T> getMapperInterface() { return mapperInterface; } public Map<Method, MapperMethod> getMethodCache() { return methodCache; } @SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } }

在這里,先通過T newInstance(SqlSession sqlSession)方法會得到一個MapperProxy對象,然后調用T newInstance(MapperProxy mapperProxy)生成代理對象然后返回。

而查看MapperProxy的代碼,可以看到如下內容:

public class MapperProxy<T> implements InvocationHandler, Serializable { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } }

非常典型的,該MapperProxy類實現了InvocationHandler接口,并且實現了該接口的invoke方法。

通過這種方式,我們只需要編寫Mapper.java接口類,當真正執行一個Mapper接口的時候,就會轉發給MapperProxy.invoke方法,而該方法則會調用后續的sqlSession.cud>executor.execute>prepareStatement等一系列方法,完成SQL的執行和返回。

設計模式是什么鬼(代理)

5、組合模式

組合模式組合多個對象形成樹形結構以表示“整體-部分”的結構層次。

組合模式對單個對象(葉子對象)和組合對象(組合對象)具有一致性,它將對象組織到樹結構中,可以用來描述整體與部分的關系。同時它也模糊了簡單元素(葉子對象)和復雜元素(容器對象)的概念,使得客戶能夠像處理簡單元素一樣來處理復雜元素,從而使客戶程序能夠與復雜元素的內部結構解耦。

在使用組合模式中需要注意一點也是組合模式最關鍵的地方:葉子對象和組合對象實現相同的接口。這就是組合模式能夠將葉子節點和對象節點進行一致處理的原因。

0

Mybatis支持動態SQL的強大功能,比如下面的這個SQL:

XHTML

<update id="update" parameterType="org.format.dynamicproxy.mybatis.bean.User"> UPDATE users <trim prefix="SET" prefixOverrides=","> <if test="name != null and name != ''"> name = #{name} </if> <if test="age != null and age != ''"> , age = #{age} </if> <if test="birthday != null and birthday != ''"> , birthday = #{birthday} </if> </trim> where id = ${id} </update>

在這里面使用到了trim、if等動態元素,可以根據條件來生成不同情況下的SQL;

在DynamicSqlSource.getBoundSql方法里,調用了rootSqlNode.apply(context)方法,apply方法是所有的動態節點都實現的接口:

public interface SqlNode { boolean apply(DynamicContext context); }

對于實現該SqlNode 接口的所有節點,就是整個組合模式樹的各個節點:

0

組合模式的簡單之處在于,所有的子節點都是同一類節點,可以遞歸的向下執行,比如對于TextSqlNode,因為它是最底層的葉子節點,所以直接將對應的內容append到SQL語句中:

@Override public boolean apply(DynamicContext context) { GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter)); context.appendSql(parser.parse(text)); return true; } 但是對于IfSqlNode,就需要先做判斷,如果判斷通過,仍然會調用子元素的SqlNode,即contents.apply方法,實現遞歸的解析。@Override public boolean apply(DynamicContext context) { if (evaluator.evaluateBoolean(test, context.getBindings())) { contents.apply(context); return true; } return false; }

設計模式是什么鬼(組合)

6、模板方法模式

模板方法模式是所有模式中最為常見的幾個模式之一,是基于繼承的代碼復用的基本技術。

模板方法模式需要開發抽象類和具體子類的設計師之間的協作。一個設計師負責給出一個算法的輪廓和骨架,另一些設計師則負責給出這個算法的各個邏輯步驟。代表這些具體邏輯步驟的方法稱做基本方法(primitive method);而將這些基本方法匯總起來的方法叫做模板方法(template method),這個設計模式的名字就是從此而來。

模板類定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

0

在Mybatis中,sqlSession的SQL執行,都是委托給Executor實現的,Executor包含以下結構:

0

其中的BaseExecutor就采用了模板方法模式,它實現了大部分的SQL執行邏輯,然后把以下幾個方法交給子類定制化完成:

protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException; protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException; protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;

該模板方法類有幾個子類的具體實現,使用了不同的策略:

  • 簡單SimpleExecutor:每執行一次update或select,就開啟一個Statement對象,用完立刻關閉Statement對象。(可以是Statement或PrepareStatement對象)
  • 重用ReuseExecutor:執行update或select,以sql作為key查找Statement對象,存在就使用,不存在就創建,用完后,不關閉Statement對象,而是放置于Map內,供下一次使用。(可以是Statement或PrepareStatement對象)
  • 批量BatchExecutor:執行update(沒有select,JDBC批處理不支持select),將所有sql都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個Statement對象,每個Statement對象都是addBatch()完畢后,等待逐一執行executeBatch()批處理的;BatchExecutor相當于維護了多個桶,每個桶里都裝了很多屬于自己的SQL,就像蘋果藍里裝了很多蘋果,番茄藍里裝了很多番茄,最后,再統一倒進倉庫。(可以是Statement或PrepareStatement對象)

比如在SimpleExecutor中這樣實現update方法:

@Override public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.update(stmt); } finally { closeStatement(stmt); } }

設計模式是什么鬼(模板方法)

7、適配器模式

適配器模式(Adapter Pattern) :將一個接口轉換成客戶希望的另一個接口,適配器模式使接口不兼容的那些類可以一起工作,其別名為適配器(Adapter )。適配器模式既可以作為類結構型模式,也可以作為對象結構型模式。

0

在Mybatsi的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); }

該接口定義了Mybatis直接使用的日志方法,而Log接口具體由誰來實現呢?Mybatis提供了多種日志框架的實現,這些實現都匹配這個Log接口所定義的接口方法,最終實現了所有外部日志框架到Mybatis日志包的適配:

0

比如對于Log4jImpl的實現來說,該實現持有了org.apache.log4j.Logger的實例,然后所有的日志方法,均委托該實例來實現。

public class Log4jImpl implements Log { private static final String FQCN = Log4jImpl.class.getName(); private Logger log; public Log4jImpl(String clazz) { log = Logger.getLogger(clazz); } @Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } @Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } @Override public void error(String s, Throwable e) { log.log(FQCN, Level.ERROR, s, e); } @Override public void error(String s) { log.log(FQCN, Level.ERROR, s, null); } @Override public void debug(String s) { log.log(FQCN, Level.DEBUG, s, null); } @Override public void trace(String s) { log.log(FQCN, Level.TRACE, s, null); } @Override public void warn(String s) { log.log(FQCN, Level.WARN, s, null); } }

設計模式是什么鬼(適配器)

8、裝飾者模式

裝飾模式(Decorator Pattern) :動態地給一個對象增加一些額外的職責(Responsibility),就增加對象功能來說,裝飾模式比生成子類實現更為靈活。其別名也可以稱為包裝器(Wrapper、Decorator)。根據翻譯的不同,裝飾模式也有人稱之為“油漆工模式”,它是一種對象結構型模式。

* 1,不改變原類文件。 * 2,不使用繼承。 * 3,動態擴展。

0

在mybatis中,緩存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定義。整個體系采用裝飾器設計模式,數據存儲和緩存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久緩存實現,然后通過一系列的裝飾器來對PerpetualCache永久緩存進行緩存策略等方便的控制。如下圖:

0

用于裝飾PerpetualCache的標準裝飾器共有8個(全部在org.apache.ibatis.cache.decorators包中):

  1. FifoCache:先進先出算法,緩存回收策略
  2. LoggingCache:輸出緩存命中的日志信息
  3. LruCache:最近最少使用算法,緩存回收策略
  4. ScheduledCache:調度緩存,負責定時清空緩存
  5. SerializedCache:緩存序列化和反序列化存儲
  6. SoftCache:基于軟引用實現的緩存管理策略
  7. SynchronizedCache:同步的緩存裝飾器,用于防止多線程并發訪問
  8. WeakCache:基于弱引用實現的緩存管理策略

另外,還有一個特殊的裝飾器TransactionalCache:事務性的緩存

正如大多數持久層框架一樣,mybatis緩存同樣分為一級緩存和二級緩存

  • 一級緩存,又叫本地緩存,是PerpetualCache類型的永久緩存,保存在執行器中(BaseExecutor),而執行器又在SqlSession(DefaultSqlSession)中,所以一級緩存的生命周期與SqlSession是相同的。
  • 二級緩存,又叫自定義緩存,實現了Cache接口的類都可以作為二級緩存,所以可配置如encache等的第三方緩存。二級緩存以namespace名稱空間為其唯一標識,被保存在Configuration核心配置對象中。

二級緩存對象的默認類型為PerpetualCache,如果配置的緩存是默認類型,則mybatis會根據配置自動追加一系列裝飾器。

Cache對象之間的引用順序為:

SynchronizedCache–>LoggingCache–>SerializedCache–>ScheduledCache–>LruCache–>PerpetualCache

設計模式是什么鬼(裝飾)

9、迭代器模式

迭代器(Iterator)模式,又叫做游標(Cursor)模式。GOF給出的定義為:提供一種方法訪問一個容器(container)對象中各個元素,而又不需暴露該對象的內部細節。

0

Java的Iterator就是迭代器模式的接口,只要實現了該接口,就相當于應用了迭代器模式:

0

比如Mybatis的PropertyTokenizer是property包中的重量級類,該類會被reflection包中其他的類頻繁的引用到。這個類實現了Iterator接口,在使用時經常被用到的是Iterator接口中的hasNext這個函數。

public class PropertyTokenizer implements Iterator<PropertyTokenizer> { private String name; private String indexedName; private String index; private String children; public PropertyTokenizer(String fullname) { 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); } } public String getName() { return name; } public String getIndex() { return index; } public String getIndexedName() { return indexedName; } public String getChildren() { return children; } @Override public boolean hasNext() { return children != null; } @Override public PropertyTokenizer next() { return new PropertyTokenizer(children); } @Override public void remove() { throw new UnsupportedOperationException( "Remove is not supported, as it has no meaning in the context of properties."); } }

可以看到,這個類傳入一個字符串到構造函數,然后提供了iterator方法對解析后的子串進行遍歷,是一個很常用的方法類。

設計模式是什么鬼(迭代器)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/168025.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/168025.shtml
英文地址,請注明出處:http://en.pswp.cn/news/168025.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【數據結構】時間和空間復雜度

馬上就要進入到數據結構的學習了 &#xff0c;我們先來了解一下時間和空間復雜度&#xff0c;這也可以判斷我們的算法是否好壞&#xff1b; 如何衡量一個算法的好壞&#xff1f; 就是看它的算法效率 算法效率 算法效率分析分為兩種&#xff1a;第一種是時間效率&#xff0c;第…

C++ Qt QVariant類型使用介紹與代碼演示

作者:令狐掌門 技術交流QQ群:675120140 csdn博客:https://mingshiqiang.blog.csdn.net/ 文章目錄 一、QVariant基本用法二、自定義類型使用QVariant三、其它用法賦值修改和替換值使用`QVariant::setValue()`設置值復制構造函數和賦值操作比較使用`QVariant::swap()`交換值使…

CVE-2023-22515:Atlassian Confluence權限提升漏洞復現 [附POC]

文章目錄 Atlassian Confluence權限提升(CVE-2023-22515)漏洞復現 [附POC]0x01 前言0x02 漏洞描述0x03 影響版本0x04 漏洞環境0x05 漏洞復現1.訪問漏洞環境2.構造POC3.復現 0x06 修復建議 Atlassian Confluence權限提升(CVE-2023-22515)漏洞復現 [附POC] 0x01 前言 免責聲明&…

vue中下載文件后無法打開的坑

今天在項目開發的時候臨時要添加個導出功能我就寫了一份請求加導出得代碼&#xff0c; 代碼&#xff1a; //導出按鈕放開exportDutySummarizing (dataRangeInfo) {const params {departmentName: dataRangeInfo.name,departmentQode: dataRangeInfo.qode}//拼接所需得urlcons…

UserRole

Qt::UserRole 是 Qt::ItemDataRole 枚舉中的一個成員&#xff0c;用于表示自定義數據角色&#xff08;Data Role&#xff09;的起始值。 在 Qt 中&#xff0c;Qt::ItemDataRole 枚舉用于標識項&#xff08;Item&#xff09;中不同類型的數據。這些數據角色包括 Qt::DisplayRol…

目標檢測YOLO系列從入門到精通技術詳解100篇-【目標檢測】紅外熱成像

目錄 前言 知識儲備 紅外熱成像儀基礎知識 算法原理 紅外熱成像探測距離 紅外圖像增強

第一百七十八回 介紹一個三方包組件:SlideSwitch

文章目錄 1. 概念介紹2. 使用方法3. 代碼與效果3.1 示例代碼3.2 運行效果 4. 內容總結 我們在上一章回中介紹了"如何創建垂直方向的Switch"相關的內容&#xff0c;本章回中將 介紹SlideSwitch組件.閑話休提&#xff0c;讓我們一起Talk Flutter吧。 1. 概念介紹 我們…

多功能智能燈桿主要功能有哪些?

多功能智能燈桿這個詞相信大家都不陌生&#xff0c;最近幾年多功能智能燈桿行業發展迅速&#xff0c;迅速取代了傳統路燈&#xff0c;那么多功能智能燈桿相比傳統照明路燈好在哪里呢&#xff0c;為什么大家都選擇使用叁仟智慧多功能智能燈桿呢&#xff1f;所謂多功能智能燈桿著…

【libGDX】Mesh紋理貼圖

1 前言 紋理貼圖的本質是將圖片的紋理坐標與模型的頂點坐標建立一一映射關系。紋理坐標的 x、y 軸正方向分別朝右和朝下&#xff0c;如下。 2 紋理貼圖 本節將使用 Mesh、ShaderProgram、Shader 實現紋理貼圖&#xff0c;OpenGL ES 的實現見博客 → 紋理貼圖。 DesktopLauncher…

超級應用平臺(HAP)起航

各位明道云用戶和伙伴&#xff0c; 今天&#xff0c;我們正式發布明道云10.0版本。從這個版本開始&#xff0c;我們將產品名稱正式命名為超級應用平臺&#xff08;Hyper Application Platform, 簡稱HAP&#xff09;。我們用“超級”二字表達產品在綜合能力方面的突破&#xff…

清華系下一代 LCM

LCM LoRA模型是一種創新的深度學習模型&#xff0c;它通過特殊的技術手段&#xff0c;顯著提高了圖像生成的效率。這種模型特別適用于需要快速生成高質量圖像的場景&#xff0c;如藝術創作、實時圖像處理等。 GitHub - luosiallen/latent-consistency-model: Latent Consistenc…

視頻監控中的智能算法與計算機視覺技術

智能視頻監控是一種基于人工智能技術的監控系統&#xff0c;它能夠通過對圖像和視頻數據進行分析&#xff0c;自動識別目標物體、判斷其行為以及進行異常檢測等功能&#xff0c;從而實現對場景的智能化監管。以下是常見的一些用于智能視頻監控的算法&#xff1a; 1、人臉識別技…

RabbitMQ簡易安裝

一般來說安裝 RabbitMQ 之前要安裝 Erlang &#xff0c;可以去Erlang官網下載。接著去RabbitMQ官網下載安裝包&#xff0c;之后解壓縮即可。 Erlang官方下載地址&#xff1a;Downloads - Erlang/OTP RabbitMQ官方下載地址&#xff1a;Downloading and Installing RabbitMQ —…

org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder

密碼&#xff0c;加密&#xff0c;解密 spring-security-crypto-5.7.3.jar /** Copyright 2002-2011 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with t…

Kafka(一)

一&#xff1a;簡介 解決高吞吐量項目的需求 是一款為大數據而生的消息中間件&#xff0c;具有百億級tps的吞吐量&#xff0c;在數據采集、傳輸、存儲的過程中發揮著作用 二&#xff1a;為什么要使用消息隊列 一個普通訪問量的接口和一個大并發的接口&#xff0c;它們背后的…

C/C++---------------LeetCode第1512. 好數對的數目

好數對的數目 題目及要求暴力算法哈希算法在main內使用 題目及要求 給你一個整數數組 nums 。 如果一組數字 (i,j) 滿足 nums[i] nums[j] 且 i < j &#xff0c;就可以認為這是一組 好數對 。 返回好數對的數目。 示例 1&#xff1a; 輸入&#xff1a;nums [1,2,3,1,…

376.擺動序列

原題鏈接&#xff1a;376.擺動序列 全代碼&#xff1a; class Solution { public:int wiggleMaxLength(vector<int>& nums) {if (nums.size() < 1) return nums.size();int curDiff 0; // 當前一對差值int preDiff 0; // 前一對差值int result 1; // 記錄峰…

Android骨架圖

用法&#xff1a;在圖片上實現動畫效果 <FrameLayoutandroid:id"id/image_container"android:layout_width"match_parent"android:layout_height"wrap_content"><ImageViewandroid:id"id/ivBlank"android:layout_width"…

PostgreSQL Patroni 3.0 新功能規劃 2023年 紐約PG 大會 (音譯)

開頭還是介紹一下群&#xff0c;如果感興趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有問題&#xff0c;有需求都可以加群群內有各大數據庫行業大咖&#xff0c;CTO&#xff0c;可以解決你的問題。加群請聯系 liuaustin3 &#xff0c;&#xff08;…

React Hooks函數之useRef

useRef 是 React 中常用的 Hook 之一&#xff0c;它返回一個可變的 ref 對象&#xff0c;其 .current 屬性被初始化為傳入的參數&#xff08;initialValue&#xff09;。返回的 ref 對象在組件的整個生命周期內保持不變。 以下是一些使用 useRef 的場景和示例&#xff1a; 1、…