沒有J2EE容器的JNDI和JPA

我們希望通過盡可能簡單的設置來測試一些JPA代碼。 計劃僅使用Java和Maven,不使用應用程序服務器或其他J2EE容器。

我們的JPA配置需要兩件事才能成功運行:

  • 數據庫來存儲數據,
  • JNDI訪問數據庫。

這篇文章分為兩個部分。 第一部分顯示了如何在測試中使用獨立的JNDI和嵌入式內存數據庫。 其余各章說明了該解決方案的工作方式。

所有使用的代碼都可以在Github上找到 。 如果您對解決方案感興趣,但不想閱讀說明,請從Github下載項目,并僅閱讀第一章。

JPA測試

本章說明如何在測試中使用我們的代碼來啟用獨立的JNDI和嵌入式內存數據庫。 本文的其余部分將說明該解決方案的工作方式和原因。

該解決方案具有三個“ API”類:

  • JNDIUtil – JNDI初始化,清理和一些便捷方法,
  • InMemoryDBUtil –數據庫和數據源的創建/刪除,
  • AbstractTestCase –在第一次測試之前清理數據庫,在每次測試之前清理JNDI。

我們使用Liquibase維護數據庫結構。 如果您不想使用Liquibase,則必須自定義InMemoryDBUtil類。 調整方法createDatabaseStructure以執行所需的操作。

Liquibase將所有需要的數據庫更改的列表保存在名為changelog的文件中。 除非另行配置,否則每個更改僅運行一次。 即使將更改日志文件多次應用于同一數據庫。

用法

AbstractTestCase擴展的任何測試用例都將:

  • 在第一次測試之前刪除數據庫,
  • 在每次測試之前安裝獨立的JNDI或刪除其中存儲的所有數據,
  • 每次測試之前,請對數據庫運行Liquibase changelog。

JPA測試用例必須擴展AbstractTestCase并重寫getInitialChangeLog方法。 該方法應返回changelog文件位置。

public class DemoJPATest extends AbstractTestCase {private static final String CHANGELOG_LOCATION = "src/test/java/org/meri/jpa/simplest/db.changelog.xml";private static EntityManagerFactory factory;public DemoJPATest() {}@Overrideprotected String getInitialChangeLog() {return CHANGELOG_LOCATION;}@Test@SuppressWarnings("unchecked")public void testJPA() {EntityManager em = factory.createEntityManager();Query query = em.createQuery("SELECT x FROM Person x");List<Person> allUsers = query.getResultList();em.close();assertFalse(allUsers.isEmpty());}@BeforeClasspublic static void createFactory() {factory = Persistence.createEntityManagerFactory("Simplest");}@AfterClasspublic static void closeFactory() {factory.close();}}

注意:在每次測試之前刪除數據庫會更清潔。 但是,刪除和重新創建數據庫結構是昂貴的操作。 這會大大降低測試用例的速度。 僅在上課之前這樣做似乎是一種合理的妥協。

雖然數據庫僅刪除一次,但更改日志在每次測試之前運行。 可能看起來很浪費,但是此解決方案具有一些優勢。 首先, getInitialChangeLog方法不必是靜態的,并且可以在每個測試中覆蓋。 其次,配置為“ runAlways”的更改將在每次測試之前運行,因此可能包含一些廉價的清理或其他初始化操作。

日本國家發展研究院

本章說明什么是JNDI,如何使用它以及如何配置它。 如果您對理論不感興趣,請跳至下一章。 在此創建獨立的JNDI。

基本用法

JNDI允許客戶端通過名稱存儲和查找數據和對象。 通過接口Context的實現訪問數據存儲。

以下代碼顯示了如何在JNDI中存儲數據:

Context ctx = new InitialContext();
ctx.bind("jndiName", "value");
ctx.close();

第二段代碼顯示了如何在JNDI中查找內容:

Context ctx = new InitialContext();
Object result = ctx.lookup("jndiName");
ctx.close();

嘗試在沒有J2EE容器的情況下運行以上代碼,您將得到一個錯誤:

javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initialat javax.naming.spi.NamingManager.getInitialContext(Unknown Source)at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)at javax.naming.InitialContext.bind(Unknown Source)at org.meri.jpa.JNDITestCase.test(JNDITestCase.java:16)at ...

該代碼不起作用,因為InitialContext類不是真實的數據存儲。 InitialContext類只能找到Context接口的另一個實例,并將所有工作委托給它。 它既無法存儲數據也無法找到它們。

上下文工廠

真正的上下文,即完成所有工作并能夠存儲/查找數據的上下文,必須由上下文工廠創建。 本節說明如何創建上下文工廠以及如何配置InitialContext以使用它。

每個上下文工廠必須實現InitialContextFactory接口,并且必須具有無參數構造函數:

package org.meri.jpa.jndi;public class MyContextFactory implements InitialContextFactory {@Overridepublic Context getInitialContext(Hashtable environment) throws NamingException {return new MyContext();}}

我們的工廠返回一個簡單的上下文,稱為MyContext 。 其lookup方法始終返回字符串“存儲值”:

class MyContext implements Context {@Overridepublic Object lookup(Name name) throws NamingException {return "stored value";}@Overridepublic Object lookup(String name) throws NamingException {return "stored value";}.. the rest ...
}

JNDI配置在哈希表中的類之間傳遞。 鍵始終包含屬性名稱,而值包含屬性值。 由于初始上下文構造函數InitialContext()沒有參數,因此假定為空哈希表。 該類還有一個替代構造函數,該構造函數將配置屬性哈希表作為參數。

使用屬性"java.naming.factory.initial"來指定上下文工廠類名稱。 該屬性在Context.INITIAL_CONTEXT_FACTORY常量中定義。

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "className");Context ctx = new InitialContext(environnement);

下一步測試配置MyContextFactory并檢查創建的初始上下文是否返回“存儲值”,無論如何:

@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void testDummyContext() throws NamingException {Hashtable environnement = new Hashtable();environnement.put(Context.INITIAL_CONTEXT_FACTORY, "org.meri.jpa.jndi.MyContextFactory");Context ctx = new InitialContext(environnement);Object value = ctx.lookup("jndiName");ctx.close();assertEquals("stored value", value);
}

當然,僅當您可以將具有自定義屬性的哈希表提供給初始上下文構造函數時,此方法才有效。 這通常是不可能的。 大多數庫使用開頭所示的無參數構造函數。 他們假定初始上下文類具有可用的默認上下文工廠,并且無參數構造函數將使用該默認工廠。

命名經理

初始上下文使用NamingManager創建真實上下文。 命名管理器具有靜態方法getInitialContext(Hashtable env) ,該方法返回上下文的實例。 參數env包含用于構建上下文的配置屬性。

默認情況下,命名管理器從env哈希表中讀取Context.INITIAL_CONTEXT_FACTORY并創建指定的初始上下文工廠的實例。 然后,工廠方法將創建一個新的上下文實例。 如果未設置該屬性,則命名管理器將引發異常。

可以自定義命名管理員的行為。 NamingManager類具有setInitialContextFactoryBuilder方法。 如果設置了初始上下文工廠構建器,則命名管理器將使用它來創建上下文工廠。

您只能使用此方法一次。 已安裝的上下文工廠生成器無法更改。

try {MyContextFactoryBuilder builder = new MyContextFactoryBuilder();NamingManager.setInitialContextFactoryBuilder(builder);
} catch (NamingException e) {// handle exception
}

初始上下文工廠構建器必須實現InitialContextFactoryBuilder接口。 界面很簡單。 它只有一個方法InitialContextFactory createInitialContextFactory(Hashtable env)

摘要

簡而言之,初始上下文將實際的上下文初始化委托給命名管理器,命名管理器將其委托給上下文工廠。 上下文工廠由初始上下文工廠構建器的實例創建。


獨立JNDI

我們將創建并安裝獨立的JNDI實現。 我們的獨立JNDI實現的入口點是JNDIUtil類。

在沒有應用程序服務器的情況下啟用JNDI需要三件事:

  • ContextInitialContextFactory接口的實現,
  • InitialContextFactoryBuilder接口的實現,
  • 初始上下文工廠構建器的安裝以及清除所有存儲數據的能力。

上下文和工廠

我們從osjava項目中獲取了SimpleJNDI實現,并對其進行了修改以更好地滿足我們的需求。 該項目使用了新的BSD許可證 。

將SimpleJNDI maven依賴項添加到pom.xml中:

simple-jndisimple-jndi0.11.4.1

SimpleJNDI帶有一個MemoryContext上下文,該上下文僅位于內存中。 它幾乎不需要任何配置,并且其狀態永遠不會保存下來。 它幾乎滿足了我們的需求,除了兩件事:

  • 它的close()方法刪除所有存儲的數據,
  • 每個實例默認使用其自己的存儲。

大多數庫都假定close方法優化了資源。 他們傾向于在每次加載或存儲數據時調用它。 如果close方法在存儲完所有數據后立即刪除它們,則上下文將無用。 我們必須擴展MemoryContext類并重寫close方法:

@SuppressWarnings({"rawtypes"}) 
public class CloseSafeMemoryContext extends MemoryContext {public CloseSafeMemoryContext(Hashtable env) {super(env);}@Overridepublic void close() throws NamingException {// Original context lost all data on close();// That made it unusable for my tests. }}

按照約定,建造者/工廠系統會為每次使用創建新的上下文實例。 如果它們不共享數據,則不能使用JNDI在不同庫之間傳輸數據。

幸運的是,這個問題也很容易解決。 如果環境哈希表包含值為"true"屬性"org.osjava.sj.jndi.shared" "true" ,則創建的內存上下文將使用公共靜態存儲。 因此,我們的初始上下文工廠將創建CloseSafeMemoryContext實例,并將其配置為使用公共存儲:

public class CloseSafeMemoryContextFactory implements InitialContextFactory {private static final String SHARE_DATA_PROPERTY = "org.osjava.sj.jndi.shared";public Context getInitialContext(Hashtable environment) throws NamingException {// clone the environnementHashtable sharingEnv = (Hashtable) environment.clone();// all instances will share stored dataif (!sharingEnv.containsKey(SHARE_DATA_PROPERTY)) {sharingEnv.put(SHARE_DATA_PROPERTY, "true");}return new CloseSafeMemoryContext(sharingEnv);;}}

初始上下文工廠生成器

我們的構建器的行為幾乎與原始命名管理器實現相同。 如果傳入環境中存在屬性Context.INITIAL_CONTEXT_FACTORY ,則將創建指定的工廠。

但是,如果缺少此屬性,則構建器將創建CloseSafeMemoryContextFactory的實例。 原始的命名管理器將引發異常。

我們對InitialContextFactoryBuilder接口的實現:

public InitialContextFactory createInitialContextFactory(Hashtable env) throws NamingException {String requestedFactory = null;if (env!=null) {requestedFactory = (String) env.get(Context.INITIAL_CONTEXT_FACTORY);}if (requestedFactory != null) {return simulateBuilderlessNamingManager(requestedFactory);}return new CloseSafeMemoryContextFactory();
}

方法simulateBuilderlessNamingManager使用類加載器加載請求的上下文工廠:

private InitialContextFactory simulateBuilderlessNamingManager(String requestedFactory) throws NoInitialContextException {try {ClassLoader cl = getContextClassLoader();Class requestedClass = Class.forName(className, true, cl);return (InitialContextFactory) requestedClass.newInstance();} catch (Exception e) {NoInitialContextException ne = new NoInitialContextException(...);ne.setRootCause(e);throw ne;}
}private ClassLoader getContextClassLoader() {return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {public Object run() {return Thread.currentThread().getContextClassLoader();}});
}

構建器安裝和上下文清理

最后,我們必須安裝上下文工廠生成器。 當我們想在測試中使用獨立的JNDI時,我們還需要一種方法來清除測試之間的所有存儲數據。 兩者都在initializeJNDI方法內部完成,該方法將在每次測試之前運行:

public class JNDIUtil {public void initializeJNDI() {if (jndiInitialized()) {cleanAllInMemoryData();} else {installDefaultContextFactoryBuilder();}}}

如果已經設置了默認上下文工廠生成器,那么將初始化JNDI:

private boolean jndiInitialized() {return NamingManager.hasInitialContextFactoryBuilder();}

安裝默認上下文工廠生成器:

private void installDefaultContextFactoryBuilder() {try {NamingManager.setInitialContextFactoryBuilder(new ImMemoryDefaultContextFactoryBuilder());} catch (NamingException e) {//We can not solve the problem. We will let it go up without//having to declare the exception every time.throw new ConfigurationException(e);}
}

使用原始的方法實現closeMemoryContext類清理存儲數據:

private void cleanAllInMemoryData() {CleanerContext cleaner = new CleanerContext();try {cleaner.close();} catch (NamingException e) {throw new RuntimeException("Memory context cleaning failed:", e);}
}class CleanerContext extends MemoryContext {private static Hashtable environnement = new Hashtable();static {environnement.put("org.osjava.sj.jndi.shared", "true");}public CleanerContext() {super(environnement);}}


內存數據庫

Apache Derby是用Java實現的開源關系數據庫。 根據Apache許可證2.0版提供。 Derby能夠以嵌入式模式運行。 嵌入式數據庫數據存儲在文件系統或內存中。

對Derby的Maven依賴關系:

org.apache.derbyderby10.8.2.2

創建數據源

使用EmbeddedDatasource類的實例連接到數據庫。 每當數據庫名稱以“ memory:”開頭時,數據源將使用一個內存中實例。

以下代碼創建指向內存數據庫實例的數據源。 如果數據庫尚不存在,將創建它:

private EmbeddedDataSource createDataSource() {EmbeddedDataSource dataSource = new EmbeddedDataSource();dataSource.setDataSourceName(dataSourceJndiName);dataSource.setDatabaseName("memory:" + databaseName);dataSource.setCreateDatabase("create");return dataSource;
}

刪除數據庫

清理數據庫的最簡單方法是刪除并重新創建它。 創建嵌入式數據源的實例,將連接屬性“ drop”設置為“ true”,并調用其getConnection方法。 它將刪除數據庫并引發異常。

private static final String DATABASE_NOT_FOUND = "XJ004";private void dropDatabase() {EmbeddedDataSource dataSource = createDataSource();dataSource.setCreateDatabase(null);dataSource.setConnectionAttributes("drop=true");try {//drop the database; not the nicest solution, but worksdataSource.getConnection();} catch (SQLNonTransientConnectionException e) {//this is OK, database was dropped} catch (SQLException e) {if (DATABASE_NOT_FOUND.equals(e.getSQLState())) {//attempt to drop non-existend database//we will ignore this errorreturn ; }throw new ConfigurationException("Could not drop database.", e);}}


數據庫結構

我們使用Liquibase創建數據庫結構和測試數據。 數據庫結構保存在所謂的變更日志文件中。 它是一個xml文件,但是如果您不想學習另一種xml語言,則可以包含DDL或SQL代碼。

Liquibase及其優點不在本文討論范圍之內。 此演示最相關的優勢是它能夠對同一數據庫多次運行同一變更日志。 每次運行僅將新更改應用于數據庫。 如果文件未更改,則什么都不會發生。

您可以將更改日志添加到jar或war中,并在每次啟動應用程序時運行它。 這樣可以確保數據庫始終更新為最新版本。 無需配置或安裝腳本。

將Liquibase依賴項添加到pom.xml:

org.liquibaseliquibase-core2.0.3

在更新日志之后,將創建一個名為Person的表,并將一個條目“斜杠– Simon Worth”放入其中:

<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd"><changeSet id="1" author="meri"><comment>Create table structure for users and shared items.</comment><createTable tableName="person"><column name="user_id" type="integer"><constraints primaryKey="true" nullable="false" /></column><column name="username" type="varchar(1500)"><constraints unique="true" nullable="false" /></column><column name="firstname" type="varchar(1500)"/><column name="lastname" type="varchar(1500)"/><column name="homepage" type="varchar(1500)"/><column name="about" type="varchar(1500)"/></createTable></changeSet><changeSet id="2" author="meri" context="test"><comment>Add some test data.</comment><insert tableName="person"><column name="user_id" valueNumeric="1" /><column name="userName" value="slash" /><column name="firstName" value="Simon" /><column name="lastName" value="Worth" /><column name="homePage" value="http://www.slash.blogs.net" /><column name="about" value="I like nature and writing my blog. The blog contains my opinions about everything." /></insert></changeSet></databaseChangeLog>

Liquibase的使用非常簡單。 使用數據源創建新的Liquibase實例,運行其update方法并處理所有聲明的異常:

private void initializeDatabase(String changelogPath, DataSource dataSource) {try {//create new liquibase instanceConnection sqlConnection = dataSource.getConnection();DatabaseConnection db = new DerbyConnection(sqlConnection);Liquibase liquibase = new Liquibase(changelogPath, new FileSystemResourceAccessor(), db);//update the databaseliquibase.update("test");} catch (SQLException e) {// We can not solve the problem. We will let it go up without// having to declare the exception every time.throw new ConfigurationException(DB_INITIALIZATION_ERROR, e);} catch (LiquibaseException e) {// We can not solve the problem. We will let it go up without// having to declare the exception every time.throw new ConfigurationException(DB_INITIALIZATION_ERROR, e);}}


結束

每次我們運行測試時,獨立的JNDI數據庫和嵌入式內存數據庫都已啟動并正在運行。 盡管JNDI設置可能是通用的,但數據庫的構建可能需要對項目進行特定的修改。

可以從Github上免費下載示例項目,并使用/修改任何有用的內容。

參考: This is Stuff博客上的JCG合作伙伴 Maria Jurcovicova的JNDI和JPA Without J2EE Con??tainer運行 。


翻譯自: https://www.javacodegeeks.com/2012/04/jndi-and-jpa-without-j2ee-container.html

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

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

相關文章

string 大小寫轉換

STL的algorithm庫確實給我們提供了這樣的便利&#xff0c;使用模板函數transform可以輕松解決這個問題&#xff0c;開發人員只需要提供一個函數對象&#xff0c;例如將char轉成大寫的toupper函數或者小寫的函數tolower函數。 transform原型&#xff1a; 1 #include <string&…

linux服務器上svn的log_如何在 Centos 8 / RHEL 8 上安裝和配置 VNC 服務器 | Linux 中國...

在 Centos 8 和 RHEL 8 系統中&#xff0c;默認未安裝 VNC 服務器&#xff0c;它需要手動安裝。在本文中&#xff0c;我們將通過簡單的分步指南&#xff0c;介紹如何在 Centos 8 / RHEL 8 上安裝 VNC 服務器。-- Pradeep KumarVNC(虛擬網絡計算Virtual Network Computing)服務器…

怎么把網頁保存到本地計算機,在IE瀏覽器中,將網頁保存到本地計算機中,若只需保存其中的文字、超鏈接和表格信息,應該選擇的保存類型為( )...

2.(2017高一上東臺月考)閱讀下面一段資料&#xff0c;判斷在給出的幾種說法中不正確的是( )資料&#xff1a;IP電話與傳統電話IP電話是按國際互聯網協議規定的網絡技術內容開通的電話業務&#xff0c;中文翻譯為網絡電話或互聯網電話&#xff0c;它是利用國際互聯網Inetrnet為…

html_博客博主

csdn: 工匠若水 http://blog.csdn.net/yanbober yunama: IT藍豹&#xff1a;http://www.itlanbao.com/&#xff1b; http://ask.dcloud.net.cn/docs/; 博客園&#xff1a; https://www.cnblogs.com/guweiwei/category/965437.html轉載于:https://www.cnblogs.com/awkflf11/p/55…

Windows上的Java線程CPU分析

本文將為您提供一個教程&#xff0c;介紹如何在Windows OS上快速查明Java線程貢獻者與CPU嚴重問題有關。 Windows與Linux&#xff0c;Solaris和AIX等其他操作系統一樣&#xff0c;使您可以在進程級別監視CPU利用率&#xff0c;還可以監視在進程中執行任務的單個線程。 在本教程…

flask 繼承模版的基本使用1

轉載于:https://www.cnblogs.com/wanghaonull/p/6399492.html

東芝2303am維護清零_東芝打印機2303A怎樣清零

展開全部東芝e68a843231313335323631343130323136353331333365653137打印機是按照相關要求生產的正規產品&#xff0c;其清零方式與正規產品相同。因此此處將介紹常用的打印機清零方法。打印機清零一般分兩種&#xff1a;一種是手工清零&#xff0c;另一種是軟件清零。一、手工…

計算機日期函數公式大全,Excel技巧: 根據日期匯總月份的計算公式

在許多情況下&#xff0c;Excel記錄的數據將按照發生的日期進行記錄&#xff0c;但是根據日期記錄的數據將非常分散&#xff0c;通常需要每月匯總相應的數據. 在這種情況下&#xff0c;您需要將日期轉換為月份. 本文介紹了如何使用SUMPRODUCT函數按月匯總數據.公式提示在SUMPRO…

Java陷阱:內部類中的字段訪問

這本身不是一個“陷阱”&#xff0c;而是一個值得了解的實現細節。 假設我有一個帶有字段的內部類。 這樣的字段對于封閉的類是可見的&#xff0c;但是以下哪種方法是訪問它的最快方法&#xff1f; 注意&#xff01; 我只在這里查看生成的字節碼&#xff0c;而不考慮任何JIT優化…

coverity代碼檢測工具介紹_微服務測試之靜態代碼掃描

靜態代碼掃描為整個發展組織增加價值。無論您在開發組織中發揮的作用如何&#xff0c;靜態代碼掃描解決方案都具有附加價值&#xff0c;擁有軟件開發中所需要的尖端功能&#xff0c;最大限度地提高質量并管理軟件產品中的風險。背景微服務架構模式具有服務間獨立&#xff0c;可…

XML引入以及與html的區別

1.1 引入HTML: 負責網頁的結構 CSS&#xff1a; 負責網頁的樣式&#xff08;美觀&#xff09;Javascript&#xff1a; 負責在瀏覽器端與用戶進行交互。負責靜態的網頁制作的語言HTML語言特點&#xff1a;1&#xff09;由標簽組成。 <title> <p> <hr/> <br…

ADF:在任務流終結器中支持bean作用域

介紹 當我們需要在任務流消失之前完成一些最終工作&#xff08;干凈的資源&#xff0c;緊密的連接等&#xff09;時&#xff0c;這是使用任務流終結器的非常普遍的推薦做法。 和往常一樣&#xff0c;我們使用在任務流中聲明的托管bean。 托管Bean可以具有不同的范圍-請求&#…

Python 異常處理--raise函數用法

在Python中&#xff0c;要想引發異常&#xff0c;最簡單的形式就是輸入關鍵字raise&#xff0c;后跟要引發的異常的名稱。異常名稱標識出具體的類&#xff1a; Python異常處理是那些類的對象。執行raise語句時&#xff0c;Python會創建指定的異常類的一個對象。raise語句還可指…

大學計算機教學ppt數制,大學計算機基礎 第3講 數制及其相互轉換 國家精品課程課件(可編輯)...

大學計算機基礎第3講數制及其相互轉換國家精品課程課件PPT第1 章計算機基礎知識第3 講數制及其相互轉換主要教學內容數制的基本概念1 數制轉換2 小結3 學習目標1 理解數制的基本概念。2 掌握數制間的轉換。3 能夠靈活應用轉換關系完成數制之間的轉換。重點與難點不同數制之間的…

linux中匿名用戶怎么登陸_南京課工場IT培訓:Linux中vsftpd服務配置(匿名,用戶,虛擬用戶)...

vsftpd概述vsftpd 是“very secure FTP daemon”的縮寫&#xff0c;安全性是它的一個最大的特點。vsftpd 是一個 UNIX 類操作系統上運行的服務器的名字&#xff0c;它可以運行在諸如 Linux、BSD、Solaris、 HP-UNIX等系統上面&#xff0c;是一個完全免費的、開放源代碼的ftp服務…

Java _ JDK _ Arrays, LinkedList, ArrayList, Vector 及Stack

(最近在看JDK源碼&#xff0c;只是拿著它的繼承圖在看&#xff0c;但很多東西不記錄仍然印象不深&#xff0c;所以開始記錄JDK閱讀系列。) &#xff08;一&#xff09;Arrays Arrays比較特殊&#xff0c;直接繼承自Arrays -》List(Interface) -》Collection(Interface)。(Maybe…

server2016做文件服務器,『配置』服務器搭建 Office Online Server2016 實現文檔預覽 番外 錯誤篇...

安裝一個或多個角色、角色服務或功能失敗。找不到源文件。請再次嘗試在新的“添加角色和功能”向導會話中安裝角色、角色服務或功能&#xff0c;然后在向導的“確認”頁中單擊“指定備用源路徑”以指定安裝所需的源文件的有效位置。目標服務器的計算機帳戶必須能夠訪問該位置。…

Java High CPU故障排除指南–第1部分

本文是該系列的第1部分&#xff0c;它將為您提供有關如何進行故障排除和識別Java高CPU問題根本原因的綜合指南。 該指南也適用于獨立的Java程序&#xff0c;但旨在幫助涉及Java EE企業日常生產支持的個人。 它還將包括最常見的高級CPU問題列表以及高級解決方案。 生產問題解決…

PHP數據結構之三 線性表中的單鏈表的PHP實現

線性表的鏈式存儲&#xff1a;用一組任意的存儲單元存儲線性表中的數據元素。用這種方法存儲的線性表簡稱線性鏈表。 鏈式存儲線性表的特點&#xff1a;存儲鏈表中結點的一組任意的存儲單元可以是連續的&#xff0c;也可以是不連續的&#xff0c;甚至是零散分布在內存中的任意位…

php進程間通信 yoc_swoole的process模塊創建和使用子進程

swoole中為我們提供了一個進程管理模塊 Process&#xff0c;替換PHP的 pcntl 擴展&#xff0c;方便我們創建進程&#xff0c;管理進程&#xff0c;和進程間的通信。swoole提供了2種進程間的通信&#xff1a;1、基于 unix socket 的管道 pipe。2、基于 sysvmsg 的消息隊列。我們…