Colder框架硬核更新(Sharding+IOC)

目錄

  • 引言
  • 控制反轉
  • 讀寫分離分庫分表
    • 理論基礎
    • 設計目標
    • 現狀調研
    • 設計思路
    • 實現之過五關斬六將
      • 動態對象
      • 動態模型緩存
      • 數據源移植
      • 查詢表達式樹深度移植
      • 數據合并算法
      • 事務支持
    • 實際使用
  • 展望未來

引言

前方硬核警告:全文干貨11000+字,請耐心閱讀
遙想去年這個時候,差不多剛剛畢業,如今正式工作差不多一年了。Colder開源快速開發框架從上次版本發布至今差不多有三個月了,Github的星星5個版本框架總共也有近800顆,QQ群從最初的一個人發展到現在的500人(吐槽下,人數上限了,太窮開不起SVIP,所以另開了一個,群號在文章末),這都是大家共同發展的結果,本框架能夠幫助到大家鄙人就十分開心。但是,技術是不斷發展的,本框架也必須適應潮流,不斷升級才能夠與時俱進,在實際意義上提高生產力。本系列框架從原始雛形(鄙人畢業設計)=>.NET45+Easyui=>.NET Core2.1+Easyui=>.NET45+AdminLTE=>.NET Core2.1+AdminLTE,這其中都是根據實際情況不斷升級。例如鄙人最初的畢業設計搭建了框架的雛形(倉儲層不夠完善、界面較簡陋),并不適合實際的生產開發,因此使用Easyui作為前端UI框架(控件豐富,使用簡單),后又由于.NET Core的發展迅速,已經發展到2.0,其基礎類庫組件也相對比較成熟了,因此從.NET45遷移到.NET Core。后來發現Easyui的樣式比較落后,給人一種過時古老的感覺,故而又將前端UI改為基于Bootstrap的AdminLTE,比較成熟主流并且開源。
但是,新的要求又出現了:

  • 由于沒有使用IOC導致各個類通過New導致的強耦合問題
  • 數據庫大數據量如何處理的問題
    因此,本次版本更新主要就是為了解決上述的問題,即全面使用Autofac作為IOC容器實現解耦以及數據庫讀寫分離分庫分表(Sharding)支持。下面將分別介紹。
    這次更新.NET45版本與.NET Core版本同步更新:
.NET版本前端UI地址
Core2.2AdminLTEhttps://github.com/Coldairarrow/Colder.Fx.Core.AdminLTE
.NET4.52AdminLTEhttps://github.com/Coldairarrow/Colder.Fx.Net.AdminLTE

控制反轉

IOC(DI),即控制反轉(依賴注入),相關概念大家應該都知道,并且大多數人應該都已經運用于實際。我就簡單描述下,簡單講就是面向接口編程,通過接口來解除類之間的強耦合,方便開發維護測試。這個概念在JAVA開發中應該比較普遍,因為有Spring框架的正確引導,但是在.NET中可能開發人員的相關意識就沒那么強,JAVA與.NET我這里不做評價,但是作為技術人員,天生就是不斷學習的,好的東西當然要學習,畢竟技多不壓身。

在.NET 領域中IOC框架主流有兩個,即Autofac與Unity,這兩個都是優秀的開源框架,經過一番考量后我最終選擇了更加主流的(星星更多)Autofac。

關于Autofac的詳細使用教程請看官方文檔https://autofac.org/,我這里主要介紹下集成到本框架的思路以及用法。
傳統使用方法通過手動注冊具體的類實現某接口,這種做法顯然不符合實際生產需求,需要一種自動注冊的方式。本框架通過定義兩個接口類:IDependency與ICircleDependency來作為依賴注入標記,所有需要使用IOC的類只需要繼承其中一個接口就好了,其中IDependency是普通注入標記,支持屬性注入但不支持循環依賴,ICircleDependency是循環依賴注入標記,支持循環依賴,實際使用中按需選擇即可。下面代碼就是自動注冊的實現:

var builder = new ContainerBuilder();var baseType = typeof(IDependency);
var baseTypeCircle = typeof(ICircleDependency);//Coldairarrow相關程序集
var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>().Where(x => x.FullName.Contains("Coldairarrow")).ToList();//自動注入IDependency接口,支持AOP
builder.RegisterAssemblyTypes(assemblys.ToArray()).Where(x => baseType.IsAssignableFrom(x) && x != baseType).AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope().EnableInterfaceInterceptors().InterceptedBy(typeof(Interceptor));//自動注入ICircleDependency接口,循環依賴注入,不支持AOP
builder.RegisterAssemblyTypes(assemblys.ToArray()).Where(x => baseTypeCircle.IsAssignableFrom(x) && x != baseTypeCircle).AsImplementedInterfaces().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies).InstancePerLifetimeScope();//注冊Controller
builder.RegisterControllers(assemblys.ToArray()).PropertiesAutowired();//注冊Filter
builder.RegisterFilterProvider();//注冊View
builder.RegisterSource(new ViewRegistrationSource());//AOP
builder.RegisterType<Interceptor>();var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));AutofacHelper.Container = container;

代碼中有相關注釋,使用方法推薦使用構造函數注入:
ZP66u6.png
框架已在Business層與Web層全面使用DI,Util層、DataRepository層與Entity層不涉及業務邏輯,因此不使用DI。

讀寫分離分庫分表

前面的IOC或許沒啥可驚喜的,但是數據庫讀寫分離分庫分表應該不會讓大家失望。接下來將闡述下框架支持Sharding的設計思路以及具體使用方法。

理論基礎

數據庫讀寫分離分庫分表(以下簡稱Sharding),這并不是什么新概念,網上也有許多的相關資料。其根本就是為了解決一個問題,即數據庫大數據量如何處理的問題。

當業務規模較小時,使用一個數據庫即可滿足,但是當業務規模不斷擴大(數據量增大、用戶數增多),數據庫最終將會成為瓶頸(響應慢)。數據庫瓶頸主要有三種情況:數據量不大但是讀寫頻繁數據量大但是讀寫不頻繁以及數據量大并且讀寫頻繁

首先,為了解決數據量不大但是讀寫頻繁導致的瓶頸,需要使用讀寫分離,所謂讀寫分離就是將單一的數據庫分為多個數據庫,一些數據庫作為寫庫(主庫),一些數據庫作為讀庫(從庫),并且開啟主從復制(實時將寫入的數據同步到從庫中),這樣將數據的讀寫分離后,將原來單一數據庫用戶的讀寫操作分散到多個數據庫中,極大的降低了數據庫壓力,并且打多數情況下讀操作要遠多于寫操作,因此實際運用中大多使用一主多從的模式。

其次,為了解決數據量大但是讀寫不頻繁導致的瓶頸,需要使用分庫分表。其實思想也是一樣的,即分而治之,一切復雜系統都是通過合理的拆分從而有效的解決問題。分庫分表就是將原來的單一數據庫拆分為多個數據庫,將原來的一張表拆分為多張表,這樣表的數據量就將下來了,從而解決問題。但是,拆表并不是胡亂拆的,隨便拆到時候數據都找不到,那還怎么玩,因此拆表需要按照一定的規則來進行。最簡單的拆表規則,就是根據Id字段Hash后求余,這種方式使用簡單但是擴容很麻煩(絕大多數都需要遷移,工作量巨大,十分麻煩),因此大多用于基本無需擴容的業務場景。后來經過一番研究后,發現可以使用雪花Id(分布式自增Id)來解決問題,雪花Id中自帶了時間軸,因此在擴容時可以根據時間段來判斷具體的分片規則,從而擴容時無需數據遷移,但是存在一定程度上的數據熱點問題。最后,找到了葵花寶典-一致性哈希,關于一致性哈希的理論我這里就不獻丑了,相關資料網上一大把。一致性哈希從一定程度上解決了普通哈希的擴容問題與數據熱點問題,框架也支持使用一致性哈希分片規則。

最后,就是大BOSS,大數據量與大訪問量,很簡單只需要結合讀寫分離與分庫分表即可,下表是具體業務場景與采用方案的關系
| 數據量\訪問量 | | |
|-|-|-|
|| 無| 讀寫分離 |
| | 分庫分表 |讀寫分離分庫分表|

設計目標

首先定一個小目標(先賺他一個億):支持多種數據庫,使用簡單,業務升級改動小。
有了目標就需要調查業界情況,實現Sharding,市面上主要分為兩種,即使用中間件與客戶端實現。

現狀調研

中間件的優點是對客戶端透明,即對于客戶端來講中間件就是數據庫,因此對于業務改動影響幾乎沒有,但是對中間件的要求就很高,目前市面上比較主流成熟的就是mycat,其對MySQL支持比較好,但是對于其他數據庫支持就比較無力(個人測試,沒有深入研究,若有不妥請不要糾結),并且不支持EF,此方案行不通。其它類型數據庫也有對應的中間件,但是都并不如意,自己開發更不現實,因此使用中間件方案行不通。

既然中間件行不通,那就只能選擇客戶端方案了。目前在JAVA中有大名鼎鼎的Sharding-JDBC,了解了下貌似很牛逼,可惜.NET中并沒有Sharding-NET,但是有FreeSql,粗略了解了下是一個比較強大ORM框架,但我的框架原來底層是使用EF的,并且EF是.NET中主流的ORM框架,整體遷移到FreeSql不現實,因此最終沒找到成熟的解決方案。

設計思路

最后終于到了最壞的情況,既沒有完美的中間件方案,又沒有現成的客戶端方案,怎么辦呢?放棄是不可能的,這輩子都不可能放棄的,終于,內心受到了黨的啟發,決定另起爐灶(既然沒有現成的那就自己早造)、打掃干凈屋子再請客(重構數據倉儲層,實現Sharding)、一邊倒(堅定目標不改變,不妥協),由于EF支持多種數據庫,已經對底層SQL進行了抽象封裝,因此決定基于EF打造一套讀寫分離分庫分表方案。

數據庫讀寫分離實現:讀寫分離比較簡單,在倉儲接口中已經明確定義了CRUD操作接口,其中增、刪、改就是指寫操作,寫的時候按照具體的讀寫規則找到具體的寫庫進行寫操作即可,讀操作(查數據)按照具體的讀規則找到具體的讀庫進行讀即可。

數據庫分庫分表:分庫還好說,使用不同的數據庫即可,分表就比較麻煩了。首先實現分表的寫操作,可以根據分片規則能夠找到具體的物理表然后進行操作即可,實現比較容易。然后實現分表的讀操作,這個就比較麻煩了,就好比前面的都是斗皇以下的在小打小鬧,而這個卻是斗帝(騎馬),但是,作為一名合格的攻城獅是不怕斗帝的,遇到了困難不要慌,需要冷靜思考處理。前面提到過,解決復雜問題就是一個字“”,首先聯表查詢就直接不考慮支持了(大數據量進行笛卡爾積就是一種愚蠢的做法,怎么優化都沒用,物理數據庫隔絕聯表不現實,實現難度太大放棄)。接下來考慮最常用的方法:分頁查詢、數據篩選、最大值、最小值、平均值、數據量統計,EF中查詢都是通過IQueryable接口實現的,IQueryable中主要包括了數據源(特定表)與關聯的表達式樹Expression,通過考慮將數據源與關聯的表達式樹移植到分表的IQueryable即可實現與抽象表相同的查詢語句,最后將并發多線程查詢分表的數據通過合并算法即可得到最終的實際數據。想法很美好,現實很殘酷,下面為大家簡單闡述下實現過程,可以說是過五關斬六將

實現之過五關斬六將

動態對象

首先考慮分表的寫操作,傳統用法都有具體的實體類型進行操作,但是分表時,例如Base_UnitTest_0、Base_UnitTest_1、Base_UnitTest_2,這些表全部保存為實體類不現實,因此需要一種非泛型方法,后來在EF的關鍵類DbContext中找到DbEntityEntry Entry(object entity)方法,通過DbEntityEntry可以實現數據的增刪改操作,又注意到傳入參數是object,由此猜測EF支持非泛型操作,即只需要傳入特定類型的object對象也行。例如抽象表是Base_UnitTest,實際需要映射到表Base_UnitTest_0,那么怎樣將Base_UnitTest類型的對象轉換成Base_UnitTest_0類型的對象?經過查閱資料,可以通過System.Reflection.Emit命名空間下的TypeBuilder在運行時創建動態類型,即可以在運行時創建Base_UnitTest_0類型,該類型擁有與Base_UnitTest完全一樣的屬性(因為表結構完全一樣),創建了需要的類型,接下來只需要通過Json.NET將Base_UnitTest對象轉為Base_UnitTest_0即可。實現到這里,原以為會順利成功,但是并沒有那么簡單,EF直接報錯“上下文不包含模型Base_UnitTest_0”,這明顯就是模型的問題了,接下來進入下一關:EF動態模型緩存

動態模型緩存

通常都是通過繼承DbContext重寫OnModelCreating方法來注冊實體模型,這里有個坑就是OnModelCreating只會執行一次,并最終生成DbCompiledModel然后將其緩存,后續創建的DbContext就會直接使用緩存的DbCompiledModel,由于最初注冊實體模型的時候只有抽象類型Base_UnitTest,所有后續在使用Base_UnitTest_0對象的時候會報錯。為了解決這個問題,需要自己管理DbCompiledModel緩存,實現過程比較麻煩,這里就不詳細分析了,有興趣的直接看源碼即可。將緩存問題解決后,終于成功的實現了Base_UnitTest_0的增刪改,這時,心里一喜(有戲)。實現了寫操作(增、刪、改)之后,接下來就是實現查詢了,那么如何實現查詢呢?EF中查詢操作都是通過IQueryable接口實現的,IQueryable中包括了具體數據表的數據源和關聯的查詢表達式樹,那么如何將IQueryable < Base_UnitTest >轉換為IQueryable < Base_UnitTest_0 > 并且保留原始查詢語句就成了關鍵問題。

數據源移植

根據經驗,想一舉同時移植數據源與表達式樹應該不現實,實際情況也是如此,移植數據源,通過使用ExpressionVisitor可以找到根數據源,其實是一個ObjectQuery類型,并且在表達式樹中是以ConstantExpression存在,同樣通過ExpressionVisitor則可將原ObjectQuery替換為新的,實現過程省略10000字。

查詢表達式樹深度移植

數據源移植后,別以為就大功告成了,接下來進入一個深坑(最難點),表達式樹移植,經過一番踩坑后發現,表達式樹中的所有節點都是樹狀結構,任何一個查詢(Where、OrderBy、Skip、Take等)在表達式樹中都是以一個節點存在,并且一級扣一級,也就是說你改了數據源沒用,因為數據源只是表達式樹的根節點,下面的所有子節點還都是原來的根節點發的牙,并不能使用,那怎樣才能用新數據源構建與原數據源一樣的表達式樹呢?經過如下分析:IQuryable中的所有操作都是MethodCallExpression一層一層包裹,那么我從外到內剝開方法,然后再從內到外包裹新的數據源,那不就模擬得一模一樣了嗎?(貌似有戲),想到先進后出腦子里直接就蹦出了數據結構中的,強大的.NET當然支持棧了,經過一番操作(奮斗幾個晚上),此處省略10000字,最終完成IQueryable的移植,即從IQueryable < Base_UnitTest >轉換為IQueryable < Base_UnitTest_0 > 并且保留原始查詢語句。有了分表的IQueryable就能夠獲取分表的數據了,最后需要將獲取的分表數據進行合并。

數據合并算法

分表后的數據合并算法主要參考了網上的一些資料,雖然分庫分表的實現方式各不相同,但是思想都是差不多的,例如需要獲取Count,只需要將各個分表的Count求和即可,最大值只需要所有分表的最大值的最大值即可,最小值只需要所有分表最小值的最小值即可,平均值需要所有分表的和然后除以所有分表的數據條數即可。最后比較麻煩的就是分頁查詢,分頁查詢需要分表排序后獲取前N頁的所有數據(不能直接獲取某一頁的數據,因為不一定就是那一頁),最后將所有表的數據再進行分頁即可。實現到這里,已經實現了增、刪、改、查了,看似革命已經成功,其實還有最后的大BOSS:事務支持

事務支持

因為分表很可能不在同一個數據庫中,因為普通的單庫事務顯然不能滿足需求,原本框架中已經有分布式事務支持(多庫事務),這里需要集成到Sharding中,實現過程省略10000字,最終黃天不負有心人終于實現了。

到這里,肯定有暴躁老哥坐不住了:你前面BBB那么多,說得那么牛逼,到底怎么用啊???,若文章到此為止,估計就是下圖:

ZFHYN9.jpg

鄙人則回復如下:

Z9hrdK.jpg

深夜12點了,放松一下,最后介紹如何使用

實際使用

本框架支持數據庫讀寫分離分庫分表(即Sharding),并且支持主流關系型數據庫(SQLServer、Oracle、MySQL、PostgreSQL),理論上只要EF支持那么本框架支持。
由于技術原因以及結合實際情況,目前本框架僅支持單表的Sharding,即支持單表的CRUD、分頁、統計(數量、最大值、最小值、平均值),支持跨庫(表分散在不同的數據庫中,不同類型數據庫也支持)。具體如何使用如下:

  • Sharding配置
    首先、要進行分庫分表操作,那么必要的配置必不可少。配置代碼如下:
ShardingConfigBootstrapper.Bootstrap()//添加數據源.AddDataSource("BaseDb", DatabaseType.SqlServer, dbBuilder =>{//添加物理數據庫dbBuilder.AddPhsicDb("BaseDb", ReadWriteType.ReadAndWrite);})//添加抽象數據庫.AddAbsDb("BaseDb", absTableBuilder =>{//添加抽象數據表absTableBuilder.AddAbsTable("Base_UnitTest", tableBuilder =>{//添加物理數據表tableBuilder.AddPhsicTable("Base_UnitTest_0", "BaseDb");tableBuilder.AddPhsicTable("Base_UnitTest_1", "BaseDb");tableBuilder.AddPhsicTable("Base_UnitTest_2", "BaseDb");}, new ModShardingRule("Base_UnitTest", "Id", 3));});

上述代碼中完成了Sharding的配置:
ShardingConfigBootstrapper.Bootstrap()在一個項目中只能執行一次,所以建議放到Application_Start中(ASP.NET Core中的Startup)
AddDataSource是指添加數據源,數據源可以看做抽象數據庫,一個數據源包含了一組同類型的物理數據庫,即實際的數據庫。一個數據源至少包含一個物理數據庫,多個物理數據庫需要開啟主從復制或主主復制,通過ReadWriteType(寫、讀、寫和讀)參數來指定數據庫的操作類型,通常將寫庫作為主庫,讀庫作為從庫。同一個數據源中的物理數據庫類型相同,表結構也相同。
配置好數據源后就可以通過AddAbsDb來添加抽象數據庫,抽象數據庫中需要添加抽象數據表。如上抽象表Base_UnitTest對應的物理表就是Base_UnitTest_0、Base_UnitTest_1與Base_UnitTest_2,并且這三張表都屬于數據源BaseDb。分表配置當然需要分表規則(即通過一種規則找到具體數據在哪張表中)。
上述代碼中使用了最簡單的取模分片規則
源碼如下:
Z9MT6f.png
可以看到其使用方式及優缺點。
另外還有一致性HASH分片規則
Z9QF74.png
雪花Id的mod分片規則
Z9Qe91.png

上述的分片規則各有優劣,都實現IShardingRule接口,實際上只需要實現FindTable方法即可實現自定義分片規則。
實際使用中個人推薦使用雪花Id的mod分片規,這也是為什么前面數據庫設計規范中默認使用雪花Id作為數據庫主鍵的原因(PS,之前版本使用GUID作為主鍵被各種嫌棄,這次看你們怎么說)Z9hrdK.jpg

  • 使用方式
    配置完成,下面開始使用,使用方式非常簡單,與平常使用基本一致
    首先獲取分片倉儲接口IShardingRepository
IShardingRepository _db = DbFactory.GetRepository().ToSharding();

然后即可進行數據操作:

Base_UnitTest _newData  = new Base_UnitTest
{Id = Guid.NewGuid().ToString(),UserId = "Admin",UserName = "超級管理員",Age = 22
};
List<Base_UnitTest> _insertList = new List<Base_UnitTest>
{new Base_UnitTest{Id = Guid.NewGuid().ToString(),UserId = "Admin1",UserName = "超級管理員1",Age = 22},new Base_UnitTest{Id = Guid.NewGuid().ToString(),UserId = "Admin2",UserName = "超級管理員2",Age = 22}
};
//添加單條數據
_db.Insert(_newData);
//添加多條數據
_db.Insert(_insertList);
//清空表
_db.DeleteAll<Base_UnitTest>();
//刪除單條數據
_db.Delete(_newData);
//刪除多條數據
_db.Delete(_insertList);
//刪除指定數據
_db.Delete<Base_UnitTest>(x => x.UserId == "Admin2");
//更新單條數據
_db.Update(_newData);
//更新多條數據
_db.Update(_insertList);
//更新單條數據指定屬性
_db.UpdateAny(_newData, new List<string> { "UserName", "Age" });
//更新多條數據指定屬性
_db.UpdateAny(_insertList, new List<string> { "UserName", "Age" });
//更新指定條件數據
_db.UpdateWhere<Base_UnitTest>(x => x.UserId == "Admin", x =>
{x.UserId = "Admin2";
});
//GetList獲取表的所有數據
var list=_db.GetList<Base_UnitTest>();
//GetIQPagination獲取分頁后的數據
var list=_db.GetIShardingQueryable<Base_UnitTest>().GetPagination(pagination);
//Max
var max=_db.GetIShardingQueryable<Base_UnitTest>().Max(x => x.Age);
//Min
var min=_db.GetIShardingQueryable<Base_UnitTest>().Min(x => x.Age);
//Average
var min=_db.GetIShardingQueryable<Base_UnitTest>().Average(x => x.Age);
//Count
var min=_db.GetIShardingQueryable<Base_UnitTest>().Count();
//事務,使用方式與普通事務一致
using (var transaction = _db.BeginTransaction())
{_db.Insert(_newData);var newData2 = _newData.DeepClone();_db.Insert(newData2);bool succcess = _db.EndTransaction().Success;
}

上述操作中表面上是操作Base_UnitTest表,實際上卻在按照一定規則使用Base_UnitTest_0~2三張表,使分片對業務操作透明,極大提高開發效率,基本達成了最初定制的小目標。
具體使用方式請參考單元測試源碼:
"\src\Coldairarrow.UnitTests\DataRepository\ShardingTest.cs"

最后放上簡單的測試圖:300W的表分成三張100W的表后效果
ZFbkgx.png
ZFbF81.png
看來功夫沒白費,效果明顯(還不快點贊

展望未來

結束也是是新的開始,版本后續計劃采用前后端完全分離方案,前端使用vue-element-admin,后端以.NET Core為主,傳統的.NET將逐步停止更新,敬請期待!
文章雖然結束了,但是技術永無止境,希望我的文檔能夠幫助到大家。
深夜碼字,實屬不易,文章中難免會出現一些紕漏,一些觀點也不一定完全正確,還望各位大哥不吝賜教。
最后覺得文檔不錯,請點贊,Github請星星,若有各種疑問歡迎進群交流:
QQ群1(已滿)
QQ群2:579202910

See You

轉載于:https://www.cnblogs.com/coldairarrow/p/11075037.html

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

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

相關文章

python:小心類實例的屬性動態綁定機制

為什么80%的碼農都做不了架構師&#xff1f;>>> class Test:def __init__(self):self.__keyinitdef get_key(self):return self.__keydef set_key(self,key):self.__keykeyif __name__ __main__:obj Test()print(obj.get_key())#輸出初始值initobj.set_key(通過s…

java 獲取手機歸屬地_java 獲取手機歸屬地

java 獲取手機歸屬地[2021-01-30 20:46:44] 簡介:php去除nbsp的方法&#xff1a;首先創建一個PHP代碼示例文件&#xff1b;然后通過“preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/", " ", strip_tags($val));”方法去除所有nbsp即可。推薦&#xff1a;…

Atom常用功能插件

minimap代碼縮略圖插件 代碼粒子效果activate-power-mode 代碼格式化插件atom-beautify packages-->Atom Beautify-->Beautify進行格式化 標簽折疊 autoclose-html 轉載于:https://www.cnblogs.com/chenxi-hxl/p/9464120.html

mui aniShow 動畫屬性

aniShow: animationType //mui切換窗口的動畫效果&#xff1b;&#xff08;默認為slide-in-right&#xff09;&#xff1b;1."auto": (String 類型 )自動選擇動畫效果&#xff0c;使用上次顯示窗口設置的動畫效果&#xff0c;如果是第一次顯示則默認動畫效果。 2.&qu…

java中和char功能相反的是_JAVA基礎語法

java的基礎語法Java中的程序可分為結構定義語句和功能執行語句.結構定義語句&#xff1a;用于聲明一個類或方法&#xff0c;功能執行語句用于實現具體的功能。功能執行語句&#xff1a;每條功能執行語句的結尾都必須用英文分號(;)結束。public修飾的類名必須和文件名一致(如果沒…

P1357 花園 (矩陣快速冪+ DP)

題意:一個只含字母C和P的環形串 求長度為n且每m個連續字符不含有超過k個C的方案數 m < 5 n < 1e15 題解:用一個m位二進制表示狀態 轉移很好想 但是這個題是用矩陣快速冪加速dp的 因為每一位的轉移都是一樣的 用一個矩陣表示狀態i能否轉移到狀態j 然后跑一遍 統計答案特…

IDEA設置類、方法注釋模板

類注釋模板 File -> Other Setting -> Default Setting打開默認設置 Editor -> File and Code Templates -> Files -> Class 找到類注釋模板&#xff0c;在public class前面添加模板注釋 /** * program: ${PROJECT_NAME}->${NAME} * description: ${descript…

Element.shadowRoot

Element.shadowRoot轉載于:https://www.cnblogs.com/yishenweilv/p/11083278.html

netty源碼分析之服務端啟動全解析

background netty 是一個異步事件驅動的網絡通信層框架&#xff0c;其官方文檔的解釋為 Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and stream…

捕魚達人java源代碼解析_捕魚達人源碼Java

【實例簡介】捕魚達人源碼Java實現的完整代碼,對應的源碼分析文章http://write.blog.csdn.net/postedit【實例截圖】【核心代碼】Fishlord├── bin│ ├── fishlord│ │ ├── Fish.class│ │ ├── Fishlord.class│ │ ├── Net.class│ │ ├─…

Android-一張圖理解MVP的用法

M和V通過P交互&#xff0c;M做了兩件事&#xff0c;開啟子線程做耗時操作&#xff0c;然后使用原生的Hander方式切回主線程回調結果給P。 M做的兩件事也可以使用比較流行的rxjava實現&#xff1a; 備注&#xff1a;圖片不清晰可以看這里 轉載于:https://www.cnblogs.com/develo…

Android 使用jtds遠程訪問數據庫

最近老師讓我用jtds這個jar包遠程訪問數據庫中的數據&#xff0c;雖然不難&#xff0c;但有幾個點還是要注意一下的。 1、jtds的jar包我使用的是1.2.7這個版本的&#xff0c;如果是Java工程使用的是1.3.1這個版本&#xff0c;Android工程不能使用1.3.1否則連接不上數據庫 2、遠…

java乘以2的位計算符號_java編程之:按位與運算,等運算規則

按位與運算符(&)參加運算的兩個數據&#xff0c;按二進制位進行“與”運算。運算規則&#xff1a;0&00; 0&10; 1&00; 1&11;即&#xff1a;兩位同時為“1”&#xff0c;結果才為“1”&#xff0c;否則為0例如&#xff1a;3&5 即 0000 0011 &a…

C語言文字加密程序的實現

前言&#xff1a;當今社會是一個信息社會&#xff0c;你的個人信息和聊天記錄極有可能被別有用心的人時時刻刻監視著&#xff0c;那么你想不想實現專屬于兩個人或一個小圈子的人在社交軟件上的交流不被任何其他人讀懂呢&#xff1f;下面就給大家提供一個原理極其簡單程序極其容…

菜鳥-es6

這里就不在嘮叨瀏覽器對es6的支持跟轉碼器了&#xff0c;稍微百度一下就ok let and const 變量 and 常量 什么是變量,什么是常量 - 都是存儲數據的容器, - 變量》即意思就是程序運行中可以發生變化的,- 常量》即程序運行中不可以發生改變&#xff0c;- 注意&#xff1a;常量…

阿帕奇退出java_java+tomcat+apache安裝整合,啟動/關閉,添加開機啟動服務

安裝java1.8#yum update 服務器更新源碼包#rpm -qa |grep -E ^open[jre|jdk]|j[re|dk] 搜索任何版本的已安裝JDK組件java-1.8.0-openjdk-headless-1.8.0.60-2.b27.el7_1.x86_64pygobject2-2.28.6-11.el7.x86_64pygobject3-base-3.8.2-6.el7.x86_64java-1.8.0-openjdk-1.8.0…

Spring Boot中如何干掉if else

Spring Boot中如何干掉if elsehttp://www.ciphermagic.cn/spring-boot-without-if-else.html 轉載于:https://www.cnblogs.com/tyk766564616/p/11089133.html

java 抽象類與接口理解

2019獨角獸企業重金招聘Python工程師標準>>> 在java 中抽象類是implements [等有時間了補充] 轉載于:https://my.oschina.net/kuchawyz/blog/1929094

dreambackend.java_【AndroidTV】如何自定義屏保、更改屏保時長

目錄目錄系統屏保源碼有哪些在設置中顯示的屏保選項有哪些屏保選項是如何獲得的多久出現屏保修改方法我的應用項目需求處理方式遇到一個詭異的問題系統屏保源碼有哪些如果要自定義屏保可以參考這里的源碼&#xff0c;清晰易懂&#xff0c;比網上教程好屏保源碼位置BasicDreampa…

模塊初識

1.模塊 模塊的定義與分類 一個模塊就是一個py文件.這個魔鎧存儲很多相似的功能,相似的函數集合體分類 內置模塊,標準庫,Python自帶的,times,os,sys,等等200多種第三方庫(模塊),各種大神寫的一些模塊,通過pip install....安裝,有6000多種自己寫的模塊,自定義模塊2.import # impo…