如何将嵌入式PostgreSQL服务器Java组件用作单独的服务?

Aramcodez

我正在尝试为在Tomcat(7.x)中运行并依赖于Postgresql(9.x)实例的基于RESTful(服务)基于Java的应用程序创建一个全面的集成测试套件。此外,如果可能的话,我希望能够使用maven failsafe插件将此套件作为独立的进程运行,并且专门从maven 3.x运行。这样,测试可以在3个主要平台(Mac OSX,Linux和Windows)上运行。

据我了解,我相信实现这一目标的关键是执行以下步骤(按此顺序):

  1. Maven生命周期的集成前测试阶段中以某种方式启动Postgresql DB的“嵌入式”版本(和模式设置),使postgres-db-process在后台运行
  2. 启动加载我的服务应用程序的Java容器:我正在使用Jetty 9.1.5插件
  3. 在集成测试阶段从Failsafe插件运行我的(基于JUnit的)测试
  4. 在Maven的集成后测试阶段中关闭我的Jetty容器
  5. 最后,在生命周期的集成测试后阶段中,使某些机制关闭先前启动的(后台)postgres-db-process(杀死/清理该过程)

在我当前的实现中,成功完成了步骤1-3。在第2步中,它使用exec-maven-plugin,该插件调用一个使用postgresql嵌入式Java组件的Java类POM.xml的节选:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <version>1.2.1</version>
  <executions>
    <execution>
          <id>Run Postgres DB start/schema setup</id>
          <phase>pre-integration-test</phase>
            <goals>
              <goal>java</goal>
            </goals>
      </execution>
    </executions>
    <configuration>
      <mainClass>com.some.package.test.utils.DbSetup</mainClass>
      <arguments>
        <argument>setup</argument>
      </arguments>
    </configuration>
</plugin>

这是DBSetup类的摘录,该类使用嵌入postgresql的方式启动一个postgresql实例:

try {
        DownloadConfigBuilder downloadConfigBuilder = new DownloadConfigBuilder();
        downloadConfigBuilder.defaultsForCommand(Command.Postgres);
        downloadConfigBuilder.proxyFactory(new HttpProxyFactory(PROXY_ADDRESS, DEFAULT_PROXY_PORT));
        IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
                .defaults(Command.Postgres)
                .artifactStore(new ArtifactStoreBuilder()
                        .defaults(Command.Postgres)
                        .download(downloadConfigBuilder)).build();  

        PostgresStarter<PostgresExecutable, PostgresProcess> runtime = PostgresStarter.getInstance(runtimeConfig);        
        final PostgresConfig config = new PostgresConfig(Version.V9_2_4, new AbstractPostgresConfig.Net(
                    "localhost", 5432
            ), new AbstractPostgresConfig.Storage(dbName), new AbstractPostgresConfig.Timeout(),
                    new AbstractPostgresConfig.Credentials(username, password));        
        config.getAdditionalInitDbParams().addAll(Arrays.asList(
                "-E", "UTF-8",
                "--locale=en_US.UTF-8",
                "--lc-collate=en_US.UTF-8",
                "--lc-ctype=en_US.UTF-8"
            ));     

        exec = runtime.prepare(config);
        process = exec.start();
        System.out.println("embedded Postgres started");
        Thread.sleep(1200L);

    } catch (IOException e) {
        System.out.println("Something Went Wrong initializing embedded Postgres: " + e);
        e.printStackTrace();
    } 
    catch (InterruptedException e) {
        System.out.println("Something Went Wrong Pausing this thread " + e);
        e.printStackTrace();
    }

请注意,我没有process.stop();在启动Postgres实例的方法内调用因此,我目前无法关闭数据库进程。一旦退出此类DbSetup,对现有过程的所有引用都将丢失。而且Postgres进程永远不会关闭。实际上,似乎码头容器也不会关闭,并且整个Maven作业都已挂断,因此我不得不手动将其杀死(摘自我的Maven控制台输出):

[INFO] --- exec-maven-plugin:1.2.1:java (Run Postgres DB start/schema setup) @ BLAHBLAH ---
***START of Postgres DB Setup Process ***
Extract /Users/myUserName/.embedpostgresql/postgresql-9.2.4-1-osx-binaries.zip START
...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................Extract /Users/myUserName/.embedpostgresql/postgresql-9.2.4-1-osx-binaries.zip DONE
INFO:20161021 12:58:00: de.flapdoodle.embed.process.runtime.Executable de.flapdoodle.embed.process.runtime.Executable start AbstractPostgresConfig{storage=Storage{dbDir=/var/folders/8g/69wh31fn7nx3q81phwfdpld00000gn/T/postgresql-embed-66cfc41f-0e16-439f-a24b-6e5b6dbc683d/db-content-3bc4b9cc-dd21-43a7-9058-285767f5c53d, dbName='BLAH', isTmpDir=true}, network=Net{host='localhost', port=5432}, timeout=Timeout{startupTimeout=15000}, credentials=Credentials{BLAH, BLAH}, args=[], additionalInitDbParams=[-E, UTF-8, --locale=en_US.UTF-8, --lc-collate=en_US.UTF-8, --lc-ctype=en_US.UTF-8]}
INFO:20161021 12:58:01: de.flapdoodle.embed.process.runtime.Executable de.flapdoodle.embed.process.runtime.Executable start AbstractPostgresConfig{storage=Storage{dbDir=/var/folders/8g/69wh31fn7nx3q81phwfdpld00000gn/T/postgresql-embed-66cfc41f-0e16-439f-a24b-6e5b6dbc683d/db-content-3bc4b9cc-dd21-43a7-9058-285767f5c53d, dbName='BLAH', isTmpDir=true}, network=Net{host='localhost', port=5432}, timeout=Timeout{startupTimeout=15000}, credentials=Credentials{BLAH, BLAH}, args=[BLAH], additionalInitDbParams=[]}
INFO:20161021 12:58:04: de.flapdoodle.embed.process.runtime.Executable de.flapdoodle.embed.process.runtime.Executable start AbstractPostgresConfig{storage=Storage{dbDir=/var/folders/8g/69wh31fn7nx3q81phwfdpld00000gn/T/postgresql-embed-66cfc41f-0e16-439f-a24b-6e5b6dbc683d/db-content-3bc4b9cc-dd21-43a7-9058-285767f5c53d, dbName='BLAH', isTmpDir=true}, network=Net{host='localhost', port=5432}, timeout=Timeout{startupTimeout=15000}, credentials=Credentials{BLAH, BLAH}, args=[], additionalInitDbParams=[-E, UTF-8, --locale=en_US.UTF-8, --lc-collate=en_US.UTF-8, --lc-ctype=en_US.UTF-8]}
embedded Postgres started
***END of Postgres DB Setup Process ***

...

[INFO] --- jetty-maven-plugin:9.1.2.v20140210:run-war (start-jetty) @ BLAH ---
[INFO] Configuring Jetty for project: BlahProject
[INFO] Context path = /
[INFO] Tmp directory = some/path/to/my/webapp/target/tmp
[INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
[INFO] Web overrides =  none
[INFO] jetty-9.1.2.v20140210
[INFO] Scanned 1 container path jars, 133 WEB-INF/lib jars, 1 WEB-INF/classes dirs in 1887ms for context o.e.j.m.p.JettyWebAppContext@444942b0{/,file:/some/path/to/my/webapp/,STARTING}{/some/path/to/my/Application-2.3.33+46be96b464dc5b57b2e2e04ce31718a01360e5fb.war}
[INFO] Initializing Spring root WebApplicationContext
INFO:20161021 12:58:27: org.springframework.web.context.ContextLoader org.springframework.web.context.ContextLoader Root WebApplicationContext: initialization started
INFO:20161021 12:58:27: org.springframework.web.context.support.XmlWebApplicationContext org.springframework.context.support.AbstractApplicationContext Refreshing Root WebApplicationContext: startup date [Fri Oct 21 12:58:27 EDT 2016]; root of context hierarchy
INFO:20161021 12:58:27: org.springframework.beans.factory.xml.XmlBeanDefinitionReader org.springframework.beans.factory.xml.XmlBeanDefinitionReader Loading XML bean definitions from class path resource [spring/app-config.xml]
INFO:20161021 12:58:27: org.springframework.beans.factory.xml.XmlBeanDefinitionReader org.springframework.beans.factory.xml.XmlBeanDefinitionReader Loading XML bean definitions from class path resource [spring/db-config.xml]
INFO:20161021 12:58:28: org.springframework.beans.factory.support.DefaultListableBeanFactory org.springframework.beans.factory.support.DefaultListableBeanFactory Overriding bean definition for bean 'endpointLTERepository': replacing [Root bean: class [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Root bean: class [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]

[INFO] Started ServerConnector@3a8f9130{HTTP/1.1}{0.0.0.0:8080}
[INFO] Started Jetty Server

/ Maven控制台输出结束

我认识到,PostgreSQL嵌入式组件旨在在同一单元测试中全部启动和关闭Postgres数据库实例。我试图找到一种使用它的方法,它的使用范围比最初预期的用例还要大。本质上,我想要某种可以通过Maven插件启动的Postgresql嵌入式服务,然后可以将其用于关闭该Postgres进程。

关于如何创建/构建这样的服务和/或插件的任何建议?

Tunaki

这里的核心问题是能够在插件的两个不同目标之间共享某些状态:一个start目标将启动一个进程,然后一个stop目标将杀死该进程做到这一点的一个好方法是利用ContextEnabled所有mojos实现接口。它提供了getPluginContext()一种返回(原始)地图方法,您可以在其中存储要在mojo之间共享的对象。

使用这种方法,您可以将在start插件目标中创建的内容存储在目标中,然后将其恢复到stop目标中。这是一个简单的示例,用于演示此操作,其中在mojo之间共享一个简单的String值。

设置一个Maven插件项目基本上,这归结为一个具有以下POM的项目,该项目是使用Java 8和注释进行配置的Maven插件的标准POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample.plugin</groupId>
  <artifactId>test-maven-plugin</artifactId>
  <version>1.0.0</version>
  <packaging>maven-plugin</packaging>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-plugin-plugin</artifactId>
        <version>3.5</version>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>3.3.9</version>
    </dependency>

    <!-- dependencies to annotations -->
    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.4</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
</project>

注意类型的包装,该包装maven-plugin向Maven声明这是一个插件项目。在这个新项目中,请考虑以下事项StartMojo

@Mojo(name = "start", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST)
public class StartMojo extends AbstractMojo {

    @SuppressWarnings("unchecked")
    @Override
    public void execute() throws MojoExecutionException {
        getPluginContext().put("myService", new MyService("foo"));
    }

}

这是在声明默认情况下绑定到该阶段的新startmojopre-integration-test它检索插件上下文并在其中放置一个新对象。在上面,这是一个简单的自定义POJO,它MyService在其构造函数中采用一个值。该对象映射到的键"myService",用作查找。

然后,我们可以得到:

@Mojo(name = "stop", defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST)
public class StopMojo extends AbstractMojo {

    @Override
    public void execute() throws MojoExecutionException {
        MyService service = (MyService) getPluginContext().get("myService");
        getLog().info(service.getValue());
    }

}

这是在声明stop默认情况下绑定到该post-integration-test阶段的新mojo 它检索插件上下文,提取键下的对象"myService",最后获取其值并记录下来。

将这个Maven插件(带有mvn clean install打包并安装到本地存储库中之后,您可以在带有

<plugin>
  <groupId>sample.plugin</groupId>
  <artifactId>test-maven-plugin</artifactId>
  <executions>
    <execution>
      <id>sample</id>
      <goals>
        <goal>start</goal>
        <goal>stop</goal>
      </goals>
    </execution>
  </executions>
</plugin>

如果您mvn clean verify在该示例项目上运行,最终"foo"将在该post-integration-test阶段的日志中进行打印这表明该值已由startmojo正确设置,然后由stopmojo正确检索

当然,您可以在此映射中存储复杂的对象,而不仅仅是String(可能有更简单的解决方案)。值得注意的是,它可能是process您要停止的实例的主机您可以摆脱exec-maven-plugin,创建一个新的Maven插件,其中包含在一个start目标中已设置嵌入式数据库所需的代码,将该流程实例存储在此目标的插件上下文中,最后stop通过另一个mojo通过以下方式停止该流程:从插件上下文中检索它。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用嵌入式码头,如何将ServerConnector链接到服务器?

如何将简单的Spring Boot(带有Gradle构建系统)部署到Apache Tomcat(真实服务器,而不是嵌入式服务器)?

嵌入式Jetty服务器

如何关闭Spring Boot嵌入式服务器

嵌入式与非嵌入式Java服务器

如何找到嵌入式Redis端口并杀死嵌入式Redis服务器

使用Grizzly的嵌入式Java服务器:如何启用http2

Azure云服务嵌入式FTP服务器

如何将Gmail用作Youtrack的SMTP服务器?

在嵌入式设备上安装SSH服务器

使用FastCGI的嵌入式Web服务器

无法启动嵌入式Jetty服务器

启动嵌入式Jetty服务器的最短代码

Micronaut嵌入式服务器与本地主机

以编程方式配置嵌入式Underwow服务器

嵌入式码头服务器发生爆炸

尝试通过嵌入式Jetty服务器运行Ktor应用时如何避免java.lang.ExceptionInInitializerError?

将RouterFunction与嵌入式Eureka服务器一起使用

Java中的嵌入式NIO http客户端/服务器

嵌入式Java HTTPS服务器进行集成测试

是否有可以在Java进程中嵌入式运行的MQ服务器?

Swing应用程序中嵌入式HTTP服务器的Java类

在Docker上使用嵌入式Jetty服务器运行Java应用程序

嵌入式Java Web服务器隐藏应用程序界面

如何在嵌入式板上检查/调整SSH服务器

如何配置嵌入式码头服务器记录所有请求?

如何在Undertow嵌入式服务器中登录文件?

如何防止嵌入式网状服务器从弹簧引导起动webflux开始?

如何创建Ktor嵌入式服务器的.jar(创建可执行文件)