日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

在任何无法理解的情况下,请编写脚本

發布時間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在任何无法理解的情况下,请编写脚本 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

腳本編寫是使您的應用程序在運行時就可以根據客戶需求進行調整的最流行的方法之一。 與往常一樣,此方法不僅帶來好處,例如,在靈活性和可管理性之間存在眾所周知的折衷方案。 本文不是從理論上討論優缺點的文章之一,而是從實踐上展示了如何采用腳本的不同方法,并介紹了一個Spring庫,該庫提供了方便的腳本基礎結構和有用的功能。

介紹

腳本(也稱為插件體系結構)是使應用程序在運行時可自定義的最直接方法。 通常,腳本不是偶然進入設計的,而是偶然進入應用程序的。 說,您在功能規范中有一個非常不清楚的部分,因此為了避免浪費一天來進行額外的業務分析,我們決定創建一個擴展點并調用一個實現存根的腳本-將闡明以后的工作方式。

使用這種方法有很多眾所周知的利弊:例如,在運行時定義業務邏輯的靈活性非常大,可以節省大量的重新部署時間,而無法進行全面的測試,因此,安全性,性能問題是無法預測的問題等等。

對于已經決定在其Java應用程序中堅持使用腳本插件的人,或者只是考慮將其添加到代碼中的人,進一步討論的腳本編寫方法可能會有所幫助。

沒什么特別的,只是腳本

使用Java的JSR-233 API,用Java評估腳本是一項簡單的任務。 為此API實現了許多生產級評估引擎(Nashorn,JRuby,Jython等),因此向Java代碼中添加一些腳本魔術不是問題,如下所示:

Map parameters = createParametersMap();ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine scriptEngine = manager.getEngineByName("groovy");Object result = scriptEngine.eval(script.getScriptAsString("discount.groovy"), new SimpleBindings(parameters));

顯然,當代碼庫中有多個腳本文件和一個調用時,將這樣的代碼散布在您的所有應用程序上并不是一個好主意,因此您可以將此代碼段提取到放置到實用程序類的單獨方法中。 有時,您甚至可以走得更遠:您可以創建一個特殊的類(或類集),以基于業務域將腳本化的業務邏輯分組,例如PricingScriptService類。 這將使我們將對validateGroovy ()的調用包裝到一個不錯的強類型方法中,但是仍然有一些樣板代碼,所有方法都將包含參數映射,腳本文本加載邏輯和腳本評估引擎調用,類似于:

public BigDecimal applyCustomerDiscount(Customer customer, BigDecimal orderAmount) {Map params = new HashMap<>();params.put("cust", customer);params.put("amount", orderAmount);return (BigDecimal)scripting.evalGroovy(getScriptSrc("discount.groovy"), params); }

這種方法在了解參數類型和返回值類型方面帶來了更大的透明度。 并且不要忘記在您的編碼標準文檔中添加禁止“未包裝”腳本引擎調用的規則!

類固醇腳本

盡管使用腳本引擎非常簡單,但是如果代碼庫中有很多腳本,您可能會遇到一些性能問題。 舉個例子–您使用Groovy模板進行報告并同時運行許多報告。 遲早您會發現“簡單”腳本正在成為性能瓶頸。

這就是為什么某些框架在現有API上構建自己的腳本引擎的原因,并添加了一些不錯的功能以提高性能,執行監視,多語言腳本等。

例如,在CUBA框架中,有一個相當復雜的腳本引擎,該引擎實現了一些功能來改善腳本的實現和執行,例如:

  • 類緩存以避免重復的腳本編譯。
  • 能夠使用Groovy和Java語言編寫腳本。
  • 用于腳本引擎管理的JMX bean。
  • 所有這些都提高了性能和可用性,但是它們仍然是用于創建參數映射,獲取腳本文本等的低級API,因此,我們仍然需要將它們分組為高階模塊,以在應用程序中有效地使用腳本。

    而且,不提及新的實驗性GraalVM引擎及其允許使用其他語言擴展Java應用程序的多語言API,這是不公平的。 因此,也許我們會看到Nashorn早晚退休,并能夠在同一源文件中以不同的編程語言編寫,但是將來仍然如此。

    Spring框架:很難拒絕的提議?

    在Spring Framework中,我們對JDK的API提供了內置的腳本支持,您可以在org.springframework.scripting。*包中找到很多有用的類。 這里有評估人員,工廠等。所有構建您自己的腳本支持所需的工具。

    除了底層API之外,Spring Framework的實現還應簡化應用程序中腳本的處理-您可以按照文檔中的描述定義以動態語言實現的bean。

    您需要做的就是使用動態語言(例如Groovy)實現一個類,并在配置XML中描述一個bean,如下所示:

    <lang:groovy id="messenger" script-source="classpath:Messenger.groovy"><lang:property name="message" value="I Can Do The Frug" /> </lang:groovy>

    之后,您可以使用XML config將Messenger Bean注入到應用程序類中。 可以在基礎腳本更改的情況下自動“刷新”該bean,并與AOP等一起使用。

    這種方法看起來不錯,但是作為開發人員,如果您想利用動態語言支持的所有功能,則應為您的bean實現成熟的類。 在現實生活中,腳本可能是純函數,因此您需要向腳本中添加一些額外的代碼,以使其與Spring兼容。 如今也有一些開發人員認為XML配置與注解相比已“過時”,并試圖避免使用它,因為bean定義和注入在Java代碼和XML代碼之間進行了劃分。 盡管這更多是關于品味的問題,而不是性能/兼容性/可讀性等問題,但我們可以考慮到它。

    腳本:挑戰和想法

    因此,一切都有其代價,當您向應用程序中添加腳本時,您可能會遇到一些挑戰:

  • 可管理性–通常,腳本分散在應用程序中,因此很難管理大量的valuateGroovy (或類似)調用。
  • 可發現性–如果調用腳本中出現問題,則很難在源代碼中找到實際要點。 我們應該能夠在我們的IDE中輕松找到所有腳本調用點。
  • 透明度–編寫腳本擴展不是一件容易的事,因為沒有有關發送到腳本的變量的信息,也沒有有關應返回的結果的信息。 最后,腳本只能由開發人員完成并且只能查看源代碼。
  • 測試和更新–部署(更新)新腳本總是很危險的,沒有回滾的方法,也沒有工具可以在生產前對其進行測試。
  • 似乎在常規Java方法下隱藏腳本化方法調用可以解決其中的大多數難題。 首選方式–注入“腳本化” bean并使用有意義的名稱調用其方法,而不是僅從實用工具類中調用另一個“ eval”方法。 因此,我們的代碼正變得自我記錄,開發人員無需查看文件“ disc_10_cl.groovy”即可確定參數名稱,類型等。

    另一個優勢–如果所有腳本都有與之關聯的唯一Java方法,則可以使用IDE中的“查找用法”功能輕松找到應用程序中的所有擴展點,以及了解該腳本的參數及其含義。返回。

    這種執行腳本的方式也使測試變得更加簡單–我們不僅能夠“照常”測試這些類,而且還可以在需要時使用模擬框架。

    所有這些都使我們想起了本文開頭提到的方法–腳本方法的“特殊”類。 而且,如果我們更進一步,并隱藏開發人員對腳本引擎,參數創建等的所有調用,該怎么辦?

    腳本存儲庫概念

    這個想法非常簡單,并且所有使用Spring Framework的開發人員都應該熟悉。 我們只是創建一個Java接口并將其方法以某種方式鏈接到腳本。 例如,Spring Data JPA使用類似的方法,其中接口方法根據方法名稱轉換為SQL查詢,然后由ORM引擎執行。

    我們可能需要執行什么概念?

    可能是一個類級別的注釋,它將幫助我們檢測腳本存儲庫接口并為其構造一個特殊的Spring bean。

    方法級別的注釋將幫助我們將方法鏈接到其腳本實現。

    最好為該方法提供一個默認實現,它不是簡單的存根,而是業務邏輯的有效部分。 在我們實現由業務分析師開發的算法之前,該方法將一直有效。 或者我們可以讓他/她編寫此腳本:-)

    假設您需要創建一個服務來根據用戶個人資料計算折扣。 而且業務分析師說,我們可以放心地假設默認情況下可以為所有注冊客戶提供10%的折扣。 對于這種情況,我們可能會考慮以下代碼概念:

    @ScriptRepository public interface PricingRepository {@ScriptMethoddefault BigDecimal applyCustomerDiscount(Customer customer,BigDecimal orderAmount) {return orderAmount.multiply(new BigDecimal("0.9"));} }

    當涉及適當的折扣算法實現時,groovy腳本將如下所示:

    -------- file discount.groovy -------- def age = 50 if ((Calendar.YEAR - cust.birthday.year) >= age) {return amount.multiply(0.75) } --------

    這一切的最終目標–讓開發人員僅實現唯一的接口和折扣算法腳本,而不要對所有這些“ getEngine”和“ eval”調用感到困惑。 腳本解決方案應該發揮所有魔力:當方法被調用時,攔截調用,查找并加載腳本文本,對其進行評估并返回結果(或者,如果找不到腳本文本,則執行默認方法)。 理想用法應與此類似:

    @Service public class CustomerServiceBean implements CustomerService {@Injectprivate PricingRepository pricingRepository;//Other injected beans here@Overridepublic BigDecimal applyCustomerDiscount(Customer cust, BigDecimal orderAmnt) {if (customer.isRegistered()) {return pricingRepository.applyCustomerDiscount(cust, orderAmnt);} else {return orderAmnt;}//Other service methods here}

    腳本調用是可讀的,我猜想任何Java開發人員都熟悉腳本的調用方式。

    這些就是想法,它們被用來為使用Spring Framework的腳本存儲庫實現創建一個庫。 該庫具有用于從不同來源加載和評估腳本文本的功能,以及一些API,允許開發人員在需要時實現庫的擴展。

    怎么運行的

    該庫引入了一些注釋(以及那些喜歡它的人的XML配置),這些注釋在上下文初始化期間為所有標記有@ScriptRepository注釋的存儲庫接口啟動動態代理構建。 這些代理以實現存儲庫接口的單例Bean的形式發布,這意味著您可以使用@Autowired或@Inject將這些代理完全注入到Bean中,如上一節中的代碼片段所示。

    在應用程序配置類之一上使用@EnableSpringRepositories批注可激活腳本存儲庫。 這種方法類似于其他熟悉的Spring注釋,例如@EnableJpaRepositories或@EnableMongoRepositories。 并且對于此批注,您需要指定應類似于JPA存儲庫進行掃描的軟件包名稱數組。

    @Configuration @EnableScriptRepositories(basePackages = {"com.example", "com.sample"}) public class CoreConfig { //More configuration here. }

    如前所示,我們需要使用@ScriptMethod標記腳本存儲庫中的每個方法(庫也提供@GroovyScript和@JavaScript ),以將元數據添加到這些調用中并指示這些方法已編寫腳本。 當然,還支持腳本方法的默認實現。 解決方案的所有組件都顯示在下圖中。 藍色形狀與應用程序代碼相關,白色形狀與庫相關。 Spring Bean標記有春天徽標。

    調用接口的腳本化方法時,該代理類將攔截該代理方法,該代理類將對兩個bean進行查找-一個提供程序以實現腳本文本,以及一個評估程序以獲取結果。 腳本評估后,結果將返回到調用服務。 提供程序和評估程序都可以在@ScriptMethod批注屬性以及執行超時中指定(盡管庫為這些屬性提供了默認值):

    @ScriptRepository public interface PricingRepository {@ScriptMethod (providerBeanName = "resourceProvider",evaluatorBeanName = "groovyEvaluator",timeout = 100) default BigDecimal applyCustomerDiscount(@ScriptParam("cust") Customer customer,@ScriptParam("amount") BigDecimal orderAmount) {return orderAmount.multiply(new BigDecimal("0.9")); } }

    您可能會注意到@ScriptParam批注-我們需要它們為方法的參數提供名稱。 這些名稱應在腳本中使用,因為Java編譯器會在編譯時刪除實際的參數名稱。 您可以省略這些注釋,在這種情況下,您需要將腳本的參數命名為“ arg0”,“ arg1”等,這會影響代碼的可讀性。

    默認情況下,該庫具有提供程序,可以從兩種腳本語言的文件系統和基于JSR-233的評估器讀取groovy和javascript文件。 但是,您可以為不同的腳本存儲和執行引擎創建自定義提供程序和評估程序。 所有這些功能都基于Spring框架接口( org.springframework.scripting.ScriptSource和org.springframework.scripting.ScriptEvaluator ),因此您可以重用所有基于Spring的類,例如StandardScriptEvaluator而不是默認類。

    提供程序(以及評估程序)以Spring Bean的形式發布,因為腳本存儲庫代理為了靈活性而按名稱解析它們-您可以用新的executor代替默認執行程序,而無需更改應用程序代碼,而是在應用程序上下文中替換一個Bean。

    測試和版本控制

    由于可以輕松更改腳本,因此我們需要確保在更改腳本時不會破壞生產服務器。 該庫與JUnit測試框架兼容,沒有什么特別的。 由于您在基于Spring的應用程序中使用腳本,因此可以將單元測試和集成測試作為應用程序的一部分來測試腳本,然后再將其上傳到生產環境,因此還支持模擬。

    另外,您可以創建一個腳本提供程序,以從數據庫甚至Git或其他源代碼控制系統中讀取不同的腳本文本版本。 在這種情況下,如果生產中出現問題,則很容易切換到較新的腳本版本或回滾到以前的腳本版本。

    結論

    該庫將幫助您安排代碼中的腳本,提供以下內容:

  • 通過引入Java接口,開發人員始終可以獲得有關腳本參數及其類型的信息。
  • 提供程序和評估程序可幫助您擺脫分散在應用程序代碼中的腳本引擎調用。
  • 通過使用“查找用法(引用)” IDE命令或僅通過方法名稱進行簡單的文本搜索,我們可以輕松地在應用程序代碼中找到所有腳本用法。
  • 在此Spring Boot的基礎上,還支持自動配置,并且您還可以使用熟悉的單元測試和模擬技術,在將腳本部署到生產之前測試腳本。

    該庫具有用于在運行時獲取腳本元數據(方法名稱,參數等)的API,如果您希望避免編寫try..catch塊來處理腳本拋出的異常,則可以獲取包裝的執行結果,它還支持XML配置,如果您希望以這種格式存儲配置。

    同樣,可以通過注釋中的超時參數來限制腳本執行時間。

    可以在https://github.com/cuba-rnd/spring-script-repositories找到庫資源。

    翻譯自: https://www.javacodegeeks.com/2018/11/incomprehensible-situation-scripting.html

    總結

    以上是生活随笔為你收集整理的在任何无法理解的情况下,请编写脚本的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。