精华内容
下载资源
问答
  • 2021-06-30 10:22:51

    说起JavaEE,很多人不陌生,从J2EE到JavaEE到现在的JakartaEE,可以说见证了好几个时代,作为JavaEE的核心标准之一的EJB,的从EJB2的笨重,到EJB3的轻盈,虽然一直在进步,但是因为EJB3的生不逢时,让其面对Spring再无回天之力,究其原因,个人认为主要是一是因为java及JavaEE的更新时间太过于漫长,导致无法针对使用者的痛点做出敏捷优化;二是因为SUN的陨落,导致很长一段时间经典JAVAEE诸多问题的搁置,所谓往事不可追,自从Oracle将JavaEE移交开源社区后,更名为JakartaEE后的经典JavaEE,越来越焕发新的生机。

    一、更新速度明显加快,截至目前(2021年6月30日)Jakarta EE 发布了9.1版本,而Oracle的JaveEE还是8,

    二、拥抱开源社区后,越来越多的开源产品陆续加入

    这些都是JakartaEE标准的实现产品,其中有很多都是免费开源的。

    三、极大促进了openjdk的发展,截至目前,openjdk最新版本为16,另外17、18正在开发中。

    四、拥抱云计算,诸如payara(就是上图那个很凶狠的鱼),支持微服务、嵌入式和容器(docker和k8s)

    我之前一直在使用JavaEE6和7在开发项目,使用EJB3,JSF2,JPA标准,但说实话,有一段时间看不到JavaEE的技术前途在哪里,毕竟cloud才是未来。

    直到近期仔细看了一下JakartaEE,才发现有了很多新的变化,尤其是看了payara,发现经典的JavaEE已经拥抱了云计算时代,给出了解决的方案。

    说到经典的JavaEE,不得不提一下Spring,我对Spring研究的不深,而且毕竟Spring目前占据着绝对的市场主导,这点必须承认,但也必须承认老黄历已经不适用了,之前一直说JavaEE重,Spring轻,但现在JavaEE不在重,Spring也不轻了,而且觉得技术就像人与人之间的缘分,只有合适与不合适,没有绝对的好与坏,我的文章,仅希望能够给与读者一个选择的机会而已,说说我选择经典JavaEE开发的主要原因。

    1、经典的JavaEE是委员会官方认可的标准,规范性更强。

    2、集成的开发环境支持,往往需要更少的配置就能开始。

    3、强大的管理控制台(payara)

    ​​​​​

    这个控制台光看菜单名字就知道,功能强大,GUI 界面简单直接。

    作为JakartaEE容器,payara继承自Glassfish,支持微服务、嵌入式和容器,更符合当下开发需求,个人推荐使用payara作为载体开发JakartaEE应用,下一篇文章详细讲解如何安装并开始payara。​


     

    更多相关内容
  • payara micro开发指南

    2021-09-09 22:28:43
    微服务与payara 在Java世界内部,Spring框架已成为微服务开发的事实上的标准,通过诸如Spring Boot和Spring Data之类的库,该框架易于使用,并且可以进行高效且大部分情况下轻松进行开发。 但是,近年来也出现了许多...

    微服务与payara

    在Java世界内部,Spring框架已成为微服务开发的事实上的标准,通过诸如Spring Boot和Spring Data之类的库,该框架易于使用,并且可以进行高效且大部分情况下轻松进行开发。

    但是,近年来也出现了许多其他的框架,声称可以缩短Java应用程序的启动时间并减少其内存占用。下面将进行简单介绍。

    Spring

    为了解决早期Java Enterprise的复杂性,Spring于2003年应运而生。Spring核心是依赖注入(DI)和面向切面编程(AOP),后来衍生出易于使用的Spring MVC等Web应用框架。通过其良好的文档,全面的各方面整合类库,Spring使开发人员可以有效地创建和维护应用程序,并提供平坦的学习曲线。

    Spring在运行时使用反射执行DI。因此,当启动spring应用程序时,将在类路径中扫描带注解的类。基于此,实例化并链接到具体对象。这种做法非常灵活且对开发人员很友好,但它可能使得启动过程缓慢并占用大量内存。另外,将这种机制迁移到GraalVM非常困难,因为GraalVM不支持反射。

    Micronaut

    Micronaut是比较新的全栈微服务框架,由Grails框架的创建者于2018年引入。

    Micronaut提供了构建功能全面的微服务应用程序所需的所有工具。同时,它旨在提供快速启动并减少内存占用。通过使用Java注解处理器执行DI,创建面向切面的代理(而不是运行时)配置应用程序,可以实现此目标。

    Micronaut中的许多API均受Spring和Grails的启发。这无可厚非,毕竟这样有助于快速吸引Spring及Grails的开发人员。Micronaut提供了诸如Micronaut HTTP,数据,安全性和各种其他技术的连接器之类的模块。但是,这些库的成熟度仍落后于Spring的同类库。

    Quarkus

    Quarkus是Red Hat在2019年引入的Kubernetes原生Java框架。 它基于MicroProfile,Vert.x,Netty和Hibernate等标准构建。

    Quarkus的目标是通过在容器编排平台中允许更快的启动,较低的内存消耗和近乎即时的扩展来使Java成为Kubernetes中的领先平台。Quarkus通过使用自定义的Maven插件在编译时而不是在构建时执行尽可能多的工作来达到此目的(在Quarkus中,这也称为编译时启动)。

    Quarkus使用了大多数现有的标准技术,而且还支持扩展。但是,由于该项目仅在一年之前才开始,所以这些扩展的成熟度和兼容性还不够。随着平台的发展,这种情况将来可能会改变。

    Helidon MicroProfile

    MicroProfile项目立项于2016年,与其前身JEE一样,MicroProfile实际上是一种规范,可以由各供应商自由实现。到目前为止,MicroProfile规范已经提出了多种实现方式,最著名的是Payara Micro和Helidon MP。

    Payara是从GlassFish派生的Jakarte EE服务器,而Payara Micro是其MicroProfile实现。Helidon是Oracle在2018年启动的运行时,提供了自己的MicroProfile规范实现。

    由于它们是从JEE派生的,因此MicroProfile规范已经很成熟并且有据可查。但是,它缺少用于现代技术的连接器或替代,诸如Spring Data和Spring Security之类的库的方法。

    此外,由于同时开始了Jakarta EE(也在Eclipse Foundation中)的开发,MicroProfile的未来尚不清楚。因此,似乎两个项目将来可能会合并。

    payara micro使用

    上文介绍了payara的由来,接下来将继续介绍payara的使用。

    创建Hello World

    通过idea创建一个MicroProfile新工程,Runtime选择Payara Micro。如下所示:
    在这里插入图片描述点击next生成示例代码,非常简单,主要类如下所示:
    在这里插入图片描述

    在这里插入图片描述

    idea生成的代码中有一些空的配置文件,事实上resources和webapp目录下的文件可以直接删掉,只要保留DemoRestApplication和HelloController即可。
    依赖包只有一个:

    <dependency>
         <groupId>org.eclipse.microprofile</groupId>
         <artifactId>microprofile</artifactId>
         <version>4.0.1</version>
         <type>pom</type>
         <scope>provided</scope>
    </dependency> 
    

    运行

    • 命令行运行

    从官网下载payara micro包,例如payara-micro-5.201.jar。在ternimal中通过java -jar payara-micro-5.201.jar可以将服务器启动起来。

    假设有一个web项目,打成war包为SimpleService.war, 则以下命令可以将服务部署到payara中:

    java -jar payara-micro-5.201.jar --deploy SimpleService.war
    
    • ide中运行

    以idea为例,maven的pom文件中配置打包格式为war,然后创建JAR Application启动配置。

    在Path to JAR参数中配置payara的jar包,然后在Program arguments中配置需要部署的war包和其他参数,例如:

    --deploy $ProjectFileDir$/target/SimpleService --contextroot tt
    

    表示部署生成目录下的SimpleService的war包,根路径为tt。当然还可以设置其他参数,这里不赘述。

    注意,这里不要使用5.2021.x版本来部署服务,否则会报错(原因未知):

    Unable to perform operation: resolve on fish.payara.microprofile.faulttolerance.service.FaultToleranceServiceImpl
    

    在地址栏输入http://localhost:8080/tt/data/hello,即可看到结果:

    Hello World
    

    基本功能

    请求过滤器

    通过实现ContainerRequestFilter接口可以对请求进行过滤。如下所示:

    @Provider
    public class TraceEndpointFilter implements ContainerRequestFilter {
    
        @Override
        public void filter(ContainerRequestContext requestContext) throws IOException {
            Logger.getLogger(TraceEndpoint.class.getName()).log(Level.INFO, "{0} -> {1}",
                    new Object[]{requestContext.getMethod(), requestContext.getUriInfo().getPath()});
    

    该过滤器可以对请求进行过滤,打印请求相关信息日志。

    使用过滤器类需要注意:

    • 过滤器类必须用@Provider注解修饰,这样才会被jax-rs执行。
    • 如果没有使用注解@NameBinding,则该过滤器作用域是全局的。
    • 如果实现类使用@PreMatching注解,将在请求资源(PUT,GET等方法)之前执行过滤,否则在之后执行过滤。

    对于第二点,如果想在特定方法上执行过滤,可以实现一个用@NameBinding标注的自定义注解,然后在过滤器和需要过滤的方法上用该注解进行修饰。如下所示:
    在这里插入图片描述
    在这里插入图片描述

    @Path("/hello")
    public class HelloController {
        @GET
        @TraceEndpoint
        public String sayHello() {
            return "Hello, World!";
        }
    
        @GET
        @Path("/1")
        public String sayHello1() {
            return "Hello";
        }
    }
    

    分别请求两个方法,一个会执行过滤方法,一个不执行。

    JPA

    引入jakarta依赖包:

    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-api</artifactId>
        <version>8.0.0</version>
        <scope>provided</scope>
    </dependency>
    

    通过@PersistenceContext注解引入EntityManager

    @ApplicationScoped
    public class PersonRepository {
    
        @PersistenceContext(unitName = "SAMPLE_PU")
        private EntityManager em;
    
        @Transactional(REQUIRED)
        public void create(Person person) {
            em.persist(person);
        }
    
        public Person find(Long id) {
            return em.find(Person.class, id);
        }
    }
    

    在resources的META-INFO下创建persistence.xml配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
      <persistence-unit name="SAMPLE_PU" transaction-type="JTA">
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
          <property name="javax.persistence.schema-generation.database.action" value="create"/>
        </properties>
      </persistence-unit>
    </persistence>
    

    然后通过controller进行访问:

    @Path("/api/person")
    @ApplicationScoped
    public class PersonController {
        
        private static final Logger LOG = Logger.getLogger(PersonController.class.getName());
    
        @Inject
        private PersonRepository personRepository;
    
        @POST
        public Response createPerson(Person person) {
            LOG.log(Level.FINE, "rest request to save person : {0}", person);
            personRepository.create(person);
            return Response.ok(person).build();
        }
    
        @GET
        @Path("/{id}")
        public Response getPerson(@PathParam("id") Long id) {
            LOG.log(Level.FINE, "REST request to get Person : {0}", id);
            Person person = personRepository.find(id);
            if (person == null) {
                return Response.status(Response.Status.NOT_FOUND).build();
            } else {
                return Response.ok(person).build();
            }
        }
    }
    

    这里没有指定具体的数据库,将数据保存到内存中。如果要指定实际的数据库呢?

    在persistence.xml文件中persistence-unit节点下添加一行,指定数据源:

    <jta-data-source>java:global/SIMPLE-JPA</jta-data-source>
    

    然后在webapp目录下WEB-INF文件夹下创建web.xml文件,配置数据源:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
             xmlns="http://java.sun.com/xml/ns/javaee"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    
        <data-source>
            <name>java:global/SIMPLE-JPA</name>
            <class-name>org.postgresql.ds.PGConnectionPoolDataSource</class-name>
            <server-name>localhost</server-name>
            <port-number>5432</port-number>
            <database-name>postgres</database-name>
            <user>${dababase.user}</user>
            <password>${dababase.password}</password>
        </data-source>
    </web-app>
    

    person类如下:

    @Entity
    @Table(name="person")
    public class Person {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        private String address;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "Person{" + "id=" + id + ", name= " + name + ", address=" + address + "}";
        }
    }
    

    再次调用接口之后,数据就会保存到postgres数据库了。

    Spring-data-jpa

    首先引入spring-data-jpa的依赖包:

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.3.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.4.15.Final</version>
    </dependency>
    

    创建personService和personDao如下:

    public class PersonService {
    
        @Inject
        private PersonDao personDao;
    
    
        public void save(Person person) {
            personDao.save(person);
        }
    
        public Person findById(Long id) {
            return personDao.findById(id);
        }
    }
    
    @Stateless
    public class PersonDao {
    
        @Inject
        private PersonRepository personRepository;
    
        public void save(Person person) {
            personRepository.save(person);
        }
    
        public Person findById(Long id) {
            return personRepository.findById(id).orElse(null);
        }
    }
    

    修改personRepository:

    @Eager
    public interface PersonRepository extends JpaRepository<Person, Long> {
    
    }
    

    persistence.xml配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
      <persistence-unit name="SAMPLE_PU" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jta-data-source>java:global/SPRING-DATA</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
    
        <properties>
          <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
          <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL10Dialect"/>
          <property name="hibernate.show_sql" value="false" />
          <property name="hibernate.format_sql" value="false" />
          <property name="javax.persistence.query.timeout" value="20000"/>
        </properties>
      </persistence-unit>
    </persistence>
    

    在WEB-INF文件夹下创建beans.xml配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://xmlns.jcp.org/xml/ns/javaee"
           xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
           http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
           bean-discovery-mode="all">
    </beans>
    

    新建实体管理器工厂:

    /**
     * Factory for Entity Manager.
     */
    public class EntityManagerFactory {
    
        @PersistenceContext(unitName = "SAMPLE_PU")
        private EntityManager entityManager;
    
        /**
         * Get the entity manager.
         *
         * @return The entity manager.
         */
        @Produces
        public EntityManager getEntityManager() {
            return entityManager;
        }
    }
    

    然后调用接口即可。

    API文档生成

    本节其实完全可以是独立的,但api文档管理算是一个基本功能,所以就放进来了。

    API文档就跟注释一样,自己讨厌写,但又希望别人写。相比起注释,写API文档甚至还更麻烦一点,因为随着功能的迭代,接口逻辑会发生变更,原来写好的文档可能就不适用了,需要随着代码的更新而更新。

    为了减少工作量,可以使用工具,通过代码来生成接口文档,并随着代码的变更而更新,完全自动化生成。这里要介绍的工具是maven-swagger插件。至于什么是swagger,可以看官方文档:https://swagger.io/docs/specification/about/,这里不详细介绍。

    以上文中的spring-data-jpa为例,下面介绍api生成插件的使用。由于本文使用的是jax-rs(Java API for RESTful Web Services),因此使用的是一个支持jax-rs接口的插件:https://github.com/openapi-tools/swagger-maven-plugin。

    当然,也可以使用这个插件:https://github.com/kongchen/swagger-maven-plugin,不仅支持jax-rs,还支持springMVC。

    在spring-data-jpa的pom文件下配置:

    <build>
        <plugins>
            <plugin>
                <groupId>io.openapitools.swagger</groupId>
                <artifactId>swagger-maven-plugin</artifactId>
                <version>2.1.6</version>
                <configuration>
                    <resourcePackages>
                        <resourcePackage>${project.groupId}.examples.jpa</resourcePackage>
                    </resourcePackages>
                    <outputDirectory>${basedir}/../api-management/src/main/resources/spring-data-jpa</outputDirectory>
                    <outputFilename>spring-data-jpa-1.0.0</outputFilename>
                    <outputFormats>JSON</outputFormats>
                    <prettyPrint>true</prettyPrint>
                    <!-- general properties of the Swagger mode, @see https://github.com/openapi-tools/swagger-maven-plugin -->
                    <swaggerConfig>
                        <servers>
                            <server>
                                <url>https://services.exmple.it/base/path</url>
                                <description>Endpoint URL</description>
                            </server>
                        </servers>
                        <info>
                            <title>spring-data-jpa</title>
                            <version>1.0.0</version>
                            <description>API description</description>
                            <contact>
                                <email>e@mail.com</email>
                                <name>My Name</name>
                                <url>https://google.com</url>
                            </contact>
                            <extensions>
                                <x-custom-field-1>my-custom-field-1</x-custom-field-1>
                                <x-custom-field-2>my-custom-field-2</x-custom-field-2>
                            </extensions>
                        </info>
                    </swaggerConfig>
                </configuration>
                <executions>
                    <execution>
                        <phase>generate-test-resources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    

    该插件会在spring-data-jpa的generate-test-resources阶段执行,根据配置生成api文档。

    依赖的swagger包:

    <dependency>
        <groupId>io.swagger.core.v3</groupId>
        <artifactId>swagger-annotations</artifactId>
        <version>2.1.9</version>
        <scope>provided</scope>
    </dependency>
    

    swagger标签如下:

    package org.howe.examples.jpa;
    
    import io.swagger.v3.oas.annotations.Operation;
    import io.swagger.v3.oas.annotations.Parameter;
    import io.swagger.v3.oas.annotations.tags.Tag;
    import org.howe.examples.jpa.entity.Person;
    import org.howe.examples.jpa.service.PersonService;
    import javax.enterprise.context.ApplicationScoped;
    import javax.inject.Inject;
    import javax.ws.rs.*;
    import javax.ws.rs.core.Response;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    @Path("/api/person")
    @ApplicationScoped
    @Tag(description = "Person API", name = "Person")
    public class PersonApi {
    
        private static final Logger LOG = Logger.getLogger(PersonApi.class.getName());
    
        @Inject
        private PersonService personService;
    
        @POST
        public Response createPerson(Person person) {
            LOG.log(Level.FINE, "rest request to save person : {0}", person);
            personService.save(person);
            return Response.ok(person).build();
        }
    
        @GET
        @Path("/{id}")
        @Operation(summary = "Endpoint that get person")
        public Response getPerson(
                @PathParam("id")
                @Parameter(name = "id") Long id) {
            LOG.log(Level.FINE, "REST request to get Person : {0}", id);
            Person person = personService.findById(id);
            if (person == null) {
                return Response.status(Response.Status.NOT_FOUND).build();
            } else {
                return Response.ok(person).build();
            }
        }
    }
    

    通过maven clean test -f pom.xml来构建项目,在指定的目录生成了api文档,如下所示:
    在这里插入图片描述

    API文档展示

    在上一节中介绍了通过swagger插件来生成OpenAPI文档。事实上,即使不使用swagger插件,直接访问http://localhost:8080/openapi/ 接口也可以生成OpenAPI文档。

    MicroProfile OpenAPI规范

    MicroProfile中的MicroProfile OpenAPI规范扩展了通用OpenAPI规范,并且集成到了MicroProfile应用中。这意味着任何MicroProfile规范的实现都必须拥有/openapi 这个终端,并且通过它来提供OpenAPI文档,而OpenAPI文档实际上就是通过部署的应用来生成的。当你部署一个应用时,OpenAPI文档将根据应用的内容来自动生成[2]

    以上文中的spring-data-jpa为例,启动后访问http://localhost:8080/openapi/ ,结果如下:

    在这里插入图片描述
    这种方式是有效的,但还不够有效。通常情况下,我们可能需要一些特殊的策略来完成定制化需求。有以下几种方式可以实现:

    • MicroProfile Config配置文件。通过配置文件可以做很多事情,比如禁用应用扫描,或者在文档中添加额外的服务器。
    • 实现OASModelReader,为最终输出提供一个基础的文档。
    • 静态OpenAPI文档。和OASModelReader功能一样,但是格式略有不同。
    • 方法或类上的注解。这是修改文档的最常用方法。
    • OASFilter过滤器。可以通过过滤器来访问文档中的每一个元素,对其进行编辑或者删除。

    下面是一个简单的例子:https://github.com/payara/Payara-Examples/tree/master/microprofile/openapi-example

    配置文件

    MicroProfile OpenAPI规范包括配置API的一系列属性。
    比如src/main/resources/META_INF/microprofile-config.properties 这个配置文件。示例如下:

    # 是否禁用应用类扫描
    mp.openapi.scan.disable=false
    

    OASModelReader和OASFilter

    MicroProfile OpenAPI提供了两个接口供开发者来实现:

    • org.eclipse.microprofile.openapi.OASFilter
    • org.eclipse.microprofile.openapi.OASModelReader

    这两者功能是类似的,但是在不同的时间点生效。OASModelReader实现会创建一个初始的OpenAPI文档,最终的文档会以此为基础。而OASFilter实现则是在OpenAPI文档发布之前来对其进行访问,过滤最终的文档并进行修改。

    如果实现了这两个接口,需要在配置文件中指定,通常是microprofile-config.properties中,如下所示

    # 配置处理类用于编辑OpenAPI文档
    mp.openapi.model.reader=fish.payara.examples.microprofile.openapi.ModelReader
    mp.openapi.filter=fish.payara.examples.microprofile.openapi.Filter
    

    静态OpenAPI文件

    静态OpenAPI文件可以放在src/main/resources/META-INF目录下,并且命名为openapi.yaml, openapi.yml 或者openapi.json。当有这个文件时,会优先使用这个文件。
    这意味着,你可以先获取应用程序生成的文档,然后删除现有的任何OpenAPI注释,根据需要编辑文档,然后将其放入resources文件夹中,以生成相同的输出。

    注解

    MicroProfile OpenAPI 定义了几种注解,可用于生成OpenAPI文档。详情见MicroProfile OpenAPI 规范

    openapi ui

    下面介绍通过openapi ui插件来展示OpenAPI文档。

    引入依赖包

    <dependency>
        <groupId>org.microprofile-ext.openapi-ext</groupId>
        <artifactId>openapi-ui</artifactId>
        <version>1.1.5</version>
    </dependency>
    

    <dependency>
        <groupId>org.microprofile-ext.openapi-ext</groupId>
        <artifactId>swagger-ui</artifactId>
        <version>1.0.3</version>
    </dependency>
    

    这两个包基本上可以看作是同一个东西,使用哪一个取决于你的注解包是swagger的还是microprofile的。

    注意:这里open-ui只支持java9以上的版本,不支持java8

    启动项目后,访问: http://localhost:8080/xxx/openapi-ui接口,就能看到api页面了。其本质是先访问http://localhost:8080/openapi接口,获得openAPI文档,然后通过ui插件 OpenApiUiService进行渲染展示到页面上。

    上文介绍过MicroProfile OpenAPI的规范,通过http://localhost:8080/openapi访问得到的OpenAPI实际上是通过OASModelReader,OASFilter,静态OpenAPI文档或者扫描注解生成的。

    在上一章节中介绍过通过swagger插件来扫描swagger注解生成api文档。当然,直接使用openapi注解也是可以的。这里还是以swagger插件生成api文档来举例。

    要使用swagger插件生成的api文档,也就是使用静态OpenAPI文档,需要将其放到META-INF文件夹下。可以在插件配置的地方加上一个execution:

    <plugin>
        <groupId>io.openapitools.swagger</groupId>
        <artifactId>swagger-maven-plugin</artifactId>
        <version>2.1.6</version>
        <configuration>
            <resourcePackages>
                <resourcePackage>${project.groupId}.examples.jpa</resourcePackage>
            </resourcePackages>
            <swaggerConfig>
                <servers>
                    <server>
                        <url>https://services.exmple.it/base/path</url>
                        <description>Endpoint URL</description>
                    </server>
                </servers>
                <info>
                    <title>spring-data-jpa</title>
                    <version>1.0.0</version>
                    <description>API description</description>
                    <contact>
                        <email>e@mail.com</email>
                        <name>My Name</name>
                        <url>https://google.com</url>
                    </contact>
                    <extensions>
                        <x-custom-field-1>my-custom-field-1</x-custom-field-1>
                        <x-custom-field-2>my-custom-field-2</x-custom-field-2>
                    </extensions>
                </info>
            </swaggerConfig>
        </configuration>
        <executions>
            <execution>
                <id>api-generate</id>
                <phase>generate-test-resources</phase>
                <goals>
                    <goal>generate</goal>
                </goals>
                <configuration>
                    <outputDirectory>${basedir}/../api-management/src/main/resources/spring-data-jpa</outputDirectory>
                    <outputFilename>spring-data-jpa-1.0.0</outputFilename>
                    <outputFormats>JSON</outputFormats>
                    <prettyPrint>true</prettyPrint>
                    <!-- general properties of the Swagger mode, @see https://github.com/openapi-tools/swagger-maven-plugin -->
                </configuration>
            </execution>
            <execution>
                <id>openapi</id>
                <phase>generate-test-resources</phase>
                <goals>
                    <goal>generate</goal>
                </goals>
                <configuration>
                    <outputDirectory>src/main/resources/META-INF/</outputDirectory>
                    <outputFilename>openapi</outputFilename>
                    <outputFormats>JSON</outputFormats>
                    <prettyPrint>true</prettyPrint>
                    <!-- general properties of the Swagger mode, @see https://github.com/openapi-tools/swagger-maven-plugin -->
                </configuration>
            </execution>
        </executions>
    </plugin>
    

    这样生成的OpenAPI文档实际上是静态文件加上注解扫描的结合体。这里的静态文件已经是希望对外展示的最终版本了,因此可以通过配置文件来禁用额外的注解扫描:

    mp.openapi.scan.disable=true
    

    访问http://localhost:8080/sj/jpa/openapi-ui/,可以看到静态OpenAPI渲染出的界面:
    在这里插入图片描述

    其他的一些可以对ui进行个性化设置的属性如下:

    • openapi.ui.copyrightBy:在底部设置版权名称,默认为空
    • openapi.ui.copyrightYear:在底部设置版权时间,默认为当前年
    • openapi.ui.title:标题,默认为MicroProfile - Open API
    • openapi.ui.contextRoot:上下文根路径,默认为当前值
    • openapi.ui.yamlUrl:静态OpenAPI文件路径,默认为/openapi
    • openapi.ui.swaggerUiTheme:swagger ui主题,默认为flattop
    • openapi.ui.swaggerHeaderVisibility: 显示或隐藏wagger的logo头,默认为visible
    • openapi.ui.exploreFormVisibility:显示或隐藏搜索表单,默认hidden
    • openapi.ui.serverVisibility: 显示或隐藏服务器选择框,默认hidden
    • openapi.ui.createdWithVisibility: 显示或隐藏底部栏,默认visible

    除此之外,还有一些其他的核心设置如下:
    在这里插入图片描述

    数据库部署

    同上一节一样,本节也是独立内容,在所有的maven项目中均适用。
    一般情况下,数据库的更改会提交工单交给dba去执行。但这种操作其实会存在一个问题,比如在测试环境更改了数据库,但上线的时候忘记了更改线上的数据库,就会出现线上问题。
    通常情况下,一般都会存在多套环境,如开发环境,测试环境,预发布环境,线上环境等。为了保证各个环境的数据库一致,可以使用数据库迁移插件。这里要介绍的是flyway插件。

    什么是flyway

    Flyway是一款数据库迁移(migration)工具。简单点说,就是在你部署应用的时候,帮你执行数据库脚本的工具。Flyway支持SQL和Java两种类型的脚本,你可以将脚本打包到应用程序中,在应用程序启动时,由Flyway来管理这些脚本的执行,这些脚本被Flyway称之为migration。

    在jakarta目录下创建一个子模块,名为db-migrate。在pom文件中添加build元素:

    <build>
        <plugins>
            <plugin>
                <groupId>org.flywaydb</groupId>
                <artifactId>flyway-maven-plugin</artifactId>
                <version>7.3.1</version>
                <configuration>
                    <table>schema_version</table>
                </configuration>
            </plugin>
        </plugins>
    </build>
    

    要想flyway插件生效,需要配置

    flyway.url,flyway.user,flyway.password
    

    三个属性。因此在父模块中默认生效的profile文件中添加这三个属性:

    <profiles>
        <profile>
            <id>local</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <environment>dev</environment>
                <flyway.url>jdbc:postgresql://127.0.0.1:5432/postgres?currentSchema=public</flyway.url>
                <flyway.user>postgres</flyway.user>
                <flyway.password>postgres</flyway.password>
            </properties>
        </profile>
    </profiles>
    

    默认sql文件存放目录为/resources/db/migration下,flyway对sql脚本有命名要求:V版本号__脚本描述.sql。如下图所示:
    在这里插入图片描述

    注意:脚本版本号跟脚本描述之间的__是两个横杠。

    在进行数据库部署前需要保证数据库确实存在,同时是一个空库,无已存在的数据。

    通过maven命令来部署数据库:

    mvn clean compile flyway:migrate -f db-migrate/pom.xml
    

    没有指定profile文件,因为默认激活了id为local的profile。执行完成后,数据库就会生成,同时,新增了一个schema_version表,记录了flyway执行脚本的历史版本信息。

    注意:flyway脚本执行后不能更改,但可以新增。脚本每次执行时,会比较已经执行过的脚本的md5值,如果md5发生变更,将会抛出错误。已经执行过的脚本不再执行,新增的脚本将被执行。

    单元测试

    并不是所有的项目都需要写单元测试。比如互联网行业,项目需求迭代通常都比较快,变化非常频繁,光写业务代码都需要天天加班,这种情况下,一般是没有时间留给开发去写单元测试的。开发写完代码并进行简单的自测后,就丢给测试去负责后续的验证了。

    而有些领域则不然,项目开发完成之后变更很少,但对代码的质量和稳定性要求却非常高。这种情况就需要写单元测试,并且单测的代码覆盖率要求会很高。

    本节在上文的基础上,简单介绍下单测的使用。以上文中spring-data-jpa为例,创建createPerson的测试用例。

    首先引入junit5的依赖包:

    <!-- test -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.6.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-junit-jupiter</artifactId>
        <version>3.0.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>3.7.7</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
        <version>2.22.2</version>
        <scope>test</scope>
    </dependency>
    

    测试用例如下:

    @ExtendWith(MockitoExtension.class)
    class PersonApiTest {
    
        @InjectMocks
        private PersonApi api;
    
        @Mock
        private PersonService service;
    
        @Test
        void shouldReturnResponseWithStatusOkWhenCreatePerson() {
            Person person = new Person();
            person.setName("howe");
            Response response = api.createPerson(person);
            verify(service, only()).save(person);
            assertEquals(Response.Status.OK, response.getStatusInfo());
        }
    }
    

    JUnit与另一个框架 TestNG 占据了 Java领域里单元测试框架的主要市场,其中 JUnit 有着较长的发展历史和不断演进的丰富功能,备受大多数 Java 开发者的青睐。
    JUnit 5是 JUnit 单元测试框架的一次重大升级,需要 Java 8 以上的运行环境,虽然在旧版本 JDK 也能编译运行,但要完全使用 JUnit5 的功能, JDK 8 环境是必不可少的。

    上面的单测可以直接执行,也可以右键类名,运行当前类下面的所有测试用例。或者通过maven插件来运行,引入surefire插件:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
    </plugin>
    

    执行maven命令:

    mvn clean test
    

    即可。

    当测试用例比较多时,执行起来比较耗费时间。如果想跳过测试用例执行,可以添加skipTests参数:

    mvn clean test -DskipTests 
    

    或者

    mvn clean test -Dmaven.test.skip=true
    

    skipTests和maven.test.skip的区别是:前者只是不执行测试用例,但还是会编译测试用例的类,而后者都不编译类文件。

    代码质量检测

    本节仍然是独立章节,与具体的开发框架无关。
    通常情况下,代码质量除了通过开发人员自己把控之外,还可以通过自动化工具来进行检测,比如sonarqube。

    先安装sonarqube,启动后通过http://localhost:9000/访问首页。

    接下来以上文中的单元测试为例。首先引入jacoco插件,用来生成代码分析报告:

    <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.5</version>
        <executions>
            <execution>
                <id>prepare-agent</id>
                <goals>
                    <goal>prepare-agent</goal>
                </goals>
            </execution>
            <execution>
                <id>report</id>
                <goals>
                    <goal>report</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    

    执行maven命令,进行sonarqube分析:

    mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:3.4.0.905:sonar -Dsonar.buildbreaker.skip=false
    

    jacoco report目标说明
    jacoco:report

    完整命令:org.jacoco:jacoco-maven-plugin:0.8.9-SNAPSHOT:report
    描述:
    Creates a code coverage report for tests of a single project in multiple formats (HTML,XML and CSV).
    Attributes:

    • Requires a Maven project to be executed.
    • Since version: 0.5.3.
    • Binds by default to the lifecycle phase: verify.

    这里默认用的是本地sonarqube。如果是远程的,则需要在命令行中指定host,如:-Dsonar.host.url="http://127.0.0.1:9000"

    分析完成后,可看到结果如下:
    在这里插入图片描述

    注意,这里实际上涉及到了3个插件。

    代码分析中一个很重要的功能是单元测试覆盖率,因此需要执行单元测试用的插件maven-surefire-plugin,该插件在上一节中已经引入。第二个就是sonar-maven-plugin插件,如果只有这两个插件,还是可以通过sonarqube进行代码分析的,可以显示Unit Tests的数量,但是覆盖率是不显示的,始终为0。

    要想正确显示单测覆盖率,则还需要上面的jacoco-maven-plugin插件。

    sonar

    可以在pom文件properties中配置不经过sonar扫描的文件。

    • sonar.exclusions 排除文件,如 **/gen/**.java
    • sonar.coverage.exclusions 排除不统计覆盖率的文件。
    • sonar.coverage.jacoco.xmlReportPaths 指定统计报告声称路径。

    参考资料

    [1]. https://blog.csdn.net/chenleiking/article/details/80691750
    [2]. https://blog.payara.fish/microprofile-openapi-in-the-payara-platform
    [3]. https://download.eclipse.org/microprofile/microprofile-open-api-1.0/microprofile-openapi-spec.html

    展开全文
  • payara 创建 集群 抽象 在研究如何创建高可用性(HA)时,我发现了会话复制,多机处理的Payara / GlassFish群集,无法在单个参考中找到所需的一切。 我认为这将是一个普遍的需求并且很容易找到。 不幸的是,我的...

    payara 创建 集群

    抽象

    在研究如何创建高可用性(HA)时,我发现了会话复制,多机处理的Payara / GlassFish群集,无法在单个参考中找到所需的一切。 我认为这将是一个普遍的需求并且很容易找到。 不幸的是,我的假设是错误的。 因此,本文的目的是给出一个完整的端到端示例,说明高可用性(HA),会话复制,多机Payara群集。 但我也(几乎)说,因为与任何技术一样,我敢肯定还有其他方法可以做到这一点。 这篇文章中描述的方式来自我的研究。

    要求

    我使用以下主要技术完成了本文的所有工作。 您可能可以使用不同的技术或版本来做相同的事情,但不能保证。

    • Java SE 8 – OpenJDK 1.8.0_91
    • Java EE 7 – Payara 4.1.1.163
    • VirtualBox 5.1.6
    • 鲁本图16.04
    • Nginx 1.10.0
    • NetBeans 8.2
    • Maven 3.0.5(与NetBeans捆绑在一起)

    定义

    在这篇文章中,以下词语将具有这些特定含义。 这里不需要律师,但最好确定定义。

    机器 :机器一词指的是正在运行其自己的操作系统的东西。 它可以是真正的硬件,例如笔记本电脑,台式机,服务器或树莓派。 也可以是运行在VirtualBox或VMWare之类的VM。 也可以是看起来像Docker容器之类的机器的东西。

    群集 :群集是GlassFish Server实例的集合,这些实例作为一个逻辑实体一起工作。 群集为一个或多个Java平台企业版(Java EE)应用程序提供了运行时环境(管理GlassFish Server群集,nd)

    群集节点 :群集节点代表安装了GlassFish Server软件的主机。 GlassFish Server实例所在的每个主机必须存在一个节点(管理GlassFish Server节点,nd)

    群集节点实例 :GlassFish Server实例是运行GlassFish Server的单个节点上Java平台(Java虚拟机或JVM机器)的单个虚拟机。 JVM计算机必须与Java平台企业版(Java EE)兼容。 (管理GlassFish服务器实例,nd)

    建筑

    由于这篇文章描述了跨多台计算机的Payara集群,因此了解每台计算机在集群中将扮演什么角色非常重要。 没有计划就开始在多台计算机上安装软件是不明智的。 本节将概述:

    1. 架构图
    2. 机器角色
    3. 机器网络配置
    4. 机器用户配置
    5. 机器软件安装

    这篇文章不会介绍机器的实际启动和运行方式。 这是您的任务。 一些选项是:真实硬件(Raspberry Pi),虚拟机(Virtual Box),容器(Docker)或云(AWS)。 如果您已经有启动,运行,配置并准备就绪的计算机,则可以跳过本节,直接跳至“ 集群创建”

    架构图

    图1显示了为本文构建的简单示例应用程序的简单架构图。 但是,即使很简单 ,拥有它也很重要。 它可以防止在机器上随机安装软件,直到您“正确安装”为止。 另外,这里使用的重要单词很简单 。 该体系结构包含此示例所需的最少内容。 它绝不是全面的或生产就绪的。 因此,考虑到这一点,下一步是更详细地研究此体系结构的各个部分。

    图1 –“ Z区”图

    图1 –“ Z区”图

    区域:S应该为网络中的所有计算机分配一个区域。 区域将执行相似功能的计算机组合在一起,还定义了区域之间的计算机如何相互通信。 本示例显示了Zone S 该区域将用于支持应用程序服务的机器。

    srv [N] .internal.dev蓝色框表示该区域中的计算机。 区域中的每台计算机都应明确定义角色,并且最好不要让计算机承担太多角色。 该区域的计算机名为srv[N].internal.devsrv表示该机器是Zone S的服务机器部分。 [N]唯一标识机器。 最后,域.internal.dev表示这是在开发环境中内部访问的计算机。 在“ 计算机角色”部分中介绍了每台计算机的角色

    群集橙色框代表区域内的群集。 该集群将使用Payara构建。 框中应包含所有参与群集的计算机。

    群集管理器,群集实例,负载平衡器黄色框代表计算机上正在运行的内容。 机器的角色决定了机器上运行的东西。 接下来,您可以查看计算机的角色。

    机器角色

    那么, Zone S每台计算机上正在运行什么? 再次参考图1,机器角色如下:

    1. srv01.internal.dev这台机器有两个角色。 第一个角色是用于管理集群的Payara DAS。 DAS严格仅供开发人员使用,并且仅供内部使用。 在区域外不应访问它。 另外,作为DAS,不应将Java EE应用程序部署到DAS。 第二个角色是NGINX负载平衡器。 当应用程序需要访问部署到该区域中的群集的服务时,负载平衡器是进入Zone S的入口点。
    2. srv02.internal.dev此计算机是Payara群集中的节点。 如图所示,该节点包含2个实例。
    3. srv03.internal.dev此计算机是Payara群集中的节点。 如图所示,该节点包含2个实例。

    现在已经清楚了每台机器的作用,接下来要看的是机器之间的通信。

    机器网络配置

    名称srv01srv02srv03将是计算机的简短主机名。 每台计算机上/etc/hostname的内容将具有此名称。 这是srv01的主机名:

    $ cat /etc/hostname 
    srv01

    .internal.dev是这些计算机的域。 机器应能够通过短主机名或完全合格的主机名相互通信。

    注意此域– .internal.dev –稍后对于在群集中正确配置WAR以实现高可用性会话复制至关重要。

    最简单的方法是通过/etc/hosts 。 (在区域中的所有计算机上)将/etc/hosts配置为包含短主机名和标准主机名。

    $ cat /etc/hosts
    127.0.0.1  localhost
    10.0.2.16  srv01.internal.dev srv01
    10.0.2.17  srv02.internal.dev srv02
    10.0.2.18  srv03.internal.dev srv03

    应该使用简单的ssh测试来验证所有计算机之间的通信。 不要跳过此验证。 Payara将使用SSH进行通信,因此最好在Payara尝试使用它之前对其进行验证和故障排除。 我将把进行此测试的详细信息留给您。

    现在所有机器都可以相互通信,接下来要看的是机器上的Linux用户帐户。 不太令人兴奋,但非常重要。

    机器用户配置

    每台机器都需要一个payara用户,该用户的主目录位于/home/payarapayara用户用于运行Payara。 没有任何内容应以root身份运行。 很简单。

    现在您已经掌握了机器配置的基础知识,现在该开始创建Payara集群了。

    集群创建

    使用Payara可以轻松创建集群。 当使用单独的机器时(相反,典型的示例使用同一台机器来完成所有操作)有一些其他步骤。 本节将概述:

    1. Payara安装
    2. Payara域名启动
    3. Payara DAS安全配置
    4. Payara网络验证
    5. 集群创建
    6. 集群节点创建
    7. 群集节点实例创建
    8. 集群启动
    9. 集群多播验证

    本节严格专注于创建和配置集群。 这意味着在阅读本节之后,您将拥有一个群集,但这并不意味着您的应用程序已准备就绪,可以进行高可用性和会话复制。 下一节将讨论WAR配置 。 现在该开始构建集群了。

    Payara安装

    Payara的安装无非就是下载ZIP文件并将其解压缩。 当然,请转到Payara并找到下载页面。 这篇文章使用Payara 4.1.1.163。 现在该在该区域中的所有计算机上安装Payara了。

    • 下载Payara 4.1.1.163
    • 将Payara解压缩到/home/payara 。 这将创建/home/payara/payara41
    • 创建一个符号链接$ln -s payara41 active
    • 将Payara bin目录放在payara Linux用户的$PATH/home/payara/.bashrc添加到/home/payara/.bashrc
    export PATH=/home/payara/active/bin:/home/payara/active/glassfish/bin:$PATH

    做完了! 很简单。 接下来查看Payara域是否可以启动。

    Payara域名启动

    使用asadmin工具启动Payara域。 在srv01.internal.dev上执行以下命令。

    payara$ asadmin start-domain domain1

    如果一切顺利,该域将启动。 通过浏览到http:// localhost:4848来验证它是否已启动并正在运行。 Payara的默认配置没有保护DAS的用户名/密码,因此您应该立即登录。现在DAS正在运行,接下来要做的就是一些安全性配置。

    Payara DAS安全配置

    现在是时候配置集群中机器之间通信所需的一些安全性了。 所有这些命令都在srv01.internal.dev上执行。

    注意所有这些配置也可以通过Payara GUI管理员应用程序http:// localhost:4848来完成,但这并不好玩! 命令行很有趣,希望可以实现自动化。

    asadmin密码更改默认的Payara asadmin密码。 第一次执行此命令时,请记住Payara没有默认的用户名/密码,因此当提示输入密码时,请将其留空。 在srv01.internal.dev上执行以下命令:

    payara@srv01$ asadmin change-admin-password
    Enter admin user name [default: admin]>admin
    Enter the admin password>        // Keep this blank when executing this for the first time
    Enter the new admin password>        // Create a new password
    Enter the new admin password again>  // Enter new password again

    重新启动域,以确保所做的更改。 在srv01.internal.dev上执行以下命令:

    payara@srv01$ asadmin restart-domain domain1

    现在,使用asadmin登录到DAS,以验证用户名/密码。 以下命令将登录DAS,并且在登录后可以执行asadmin命令, 无需每次都输入用户名/密码。 这是一种便利,但当然会带来安全风险。 要登录,请在srv01.internal.dev上执行以下命令:

    payara@srv01$ asadmin login
    Enter admin user name [Enter to accept default]> admin
    Enter admin password> *******
    
    Login information relevant to admin user name [admin] for host [localhost] and admin port [4848] stored at [/home/payara/.gfclient/pass] successfully. Make sure that this file remains protected. Information stored in this file will be used by administration commands to manage associated domain.
    
    Command login executed successfully.

    安全管理员现在,您要在群集内启用安全通信。 这基本上意味着Payara DAS将与群集实例安全地通信。 此步骤不是必需的,但是几乎总是很高兴。 在srv01.internal.dev上执行以下命令:

    payara@srv01$ asadmin enable-secure-admin

    重新启动域,以确保所做的更改。 在srv01.internal.dev上执行以下命令:

    payara@srv01$ asadmin restart-domain domain1

    安全配置就是这样。 下一步是在尝试开始创建集群之前,验证从区域中的计算机到DAS的通信。

    Payara DAS通信验证

    尝试不跳过此步骤。 大多数人希望正确地进行集群构建并跳过验证步骤。 这样可以节省一些时间,但是,如果某些操作不正常,则在验证步骤中更容易解决问题。 到目前为止,启动和配置DAS的所有工作都在srv01 。 现在验证机srv02srv03能够与在DAS沟通srv01

    srv02.internal.dev上执行以下操作,并验证结果,如图所示。

    payara@srv02$ asadmin --host srv01 --port 4848 list-configs
    Enter admin user name>  admin
    Enter admin password for user "admin"> 
    server-config
    default-config
    Command list-configs executed successfully.

    srv03.internal.dev上执行以下操作,并验证结果,如图所示。

    payara@srv03$ asadmin --host srv01 --port 4848 list-configs
    Enter admin user name>  admin
    Enter admin password for user "admin"> 
    server-config
    default-config
    Command list-configs executed successfully.

    srv02srv03上成功执行将验证那些机器可以与srv01上的DAS成功通信。 现在已经验证了这一点,是时候创建集群了。

    集群创建

    现在将要创建集群。 对于此示例,该群集将被巧妙地命名为c1 。 通常,应该适当地命名集群,但是,对于此示例, c1可以很好地工作。 在srv01.internal.dev上执行以下srv01.internal.dev

    payara@srv01$ asadmin create-cluster c1
    Command create-cluster executed successfully.

    而已! 很抗气候吧? 集群在那里,但是里面什么也没有。 现在是时候用节点填充集群了。 没有节点,集群不是很有用。

    集群节点创建

    群集节点将位于机器srv02srv03 。 但是,创建节点的命令在srv01上执行。 在srv01执行时, asadmin工具将使用ssh将必需的文件传输到srv02srv03 。 为了方便起见,首先创建一个临时密码文件以使SSH更容易。

    临时密码文件记得在每台计算机上都创建了payara Linux用户。 这是运行Payara以避免以root用户运行Payara的普通Linux用户。 临时密码文件包含srv02srv03上的payara Linux用户的未加密密码。 假定payara用户的Linux密码在所有计算机上都相同。 如果不是这种情况,则在尝试在srv[N]上创建节点之前,将需要使用机器srv[N]上的payara用户的正确密码来更新临时密码文件。

    注意也可以使用RSA / DSA密钥文件。 有关更多信息,请参考create-node-ssh文档。 http://docs.oracle.com/cd/E18930_01/html/821-2433/create-node-ssh-1.html#scrolltoc

    上创建集群节点srv02要在创建节点srv02 ,上执行以下命令srv01.internal.dev

    payara@srv01$ echo "AS_ADMIN_SSHPASSWORD=[clear_text_password_of_payara_usr_on_srv02]" > /home/payara/password
    
    payara@srv01$ asadmin create-node-ssh --nodehost **srv02.internal.dev** --sshuser payara --passwordfile /home/payara/password srv02-node

    上创建集群节点srv03要在创建节点srv03 ,上执行以下命令srv01.internal.dev

    payara@srv01$ echo "AS_ADMIN_SSHPASSWORD=[clear_text_password_of_payara_usr_on_srv03]" > /home/payara/password
    
    payara@srv01$ asadmin create-node-ssh --nodehost **srv03.internal.dev** --sshuser payara --passwordfile /home/payara/password srv03-node

    删除临时密码文件创建所有节点后,不再需要临时密码文件。 此时可以将其删除。 当然,如果将更多计算机添加到群集中,并且需要更多节点,则可以轻松创建另一个临时密码文件。

    Payara@srv01$ rm /home/payara/password

    因此,现在您有了一个群集和节点。 节点很棒。 但是,没有实例,节点无法做任何事情。 能够运行应用程序的是节点上的实例。 这是实际的Payara实例。 因此,现在该制作一些集群节点实例了。

    群集节点实例创建

    创建节点实例基本上是在节点上创建Payara实例。 一个节点上可以有许多实例。 这完全取决于机器的资源。 节点实例将在srv02srv03的节点中创建。 但是,用于创建节点实例的命令在srv01上执行。 在srv01执行时, asadmin工具将在srv02srv03上创建节点实例。

    创建节点实例srv02上创建2个节点实例srv02 。 节点实例将称为srv02-instance-01srv02-instance-02 。 在srv01.internal.dev上执行以下命令:

    payara@srv01&$ asadmin create-instance --cluster c1 --node srv02-node srv02-instance-01
    
    Command _create-instance-filesystem executed successfully.
    Port Assignments for server instance srv02-instance-01: 
    .....
    The instance, srv02-instance-01, was created on host srv02
    Command create-instance executed successfully.
    payara@srv01$ asadmin create-instance --cluster c1 --node srv02-node srv02-instance-02
    
    Command _create-instance-filesystem executed successfully.
    Port Assignments for server instance srv02-instance-02: 
    .....
    The instance, srv02-instance-02, was created on host srv02
    Command create-instance executed successfully.

    如果在执行完这些命令后,在控制台上显示了“成功执行命令创建实例”消息,那么可以确信一切正常。 但是,您应该验证以确保。 验证过程在srv02srv03 。 成功的验证意味着找到/nodes目录。 在srv02.internal.dev上执行以下srv02.internal.dev

    payara@srv02$ cd /home/payara/active/glassfish
    payara@srv02$ ls
    bin  common  config  domains  legal  lib  modules  nodes  osgi

    创建节点实例srv03上创建2个节点实例srv03 。 进行与上一个标题完全相同的所有操作,但使用srv03而不是srv02

    现在有4个Payara实例…

    1. srv02-instance-01
    2. srv02-instance-02
    3. srv03-instance-01
    4. srv03-instance-02

    分布在2个节点上...

    1. srv02-node
    2. srv03-node

    在2台不同的机器上…

    1. srv02
    2. srv03

    在1个逻辑Payara群集上

    1. c1

    现在,开始一切!

    集群启动

    启动集群c1确实非常容易。 这是通过srv01计算机完成的,当DAS启动所有群集实例时,请注意控制台以确保所有4个实例都已启动。 在srv01.internal.dev上执行以下命令。

    payara@srv01$ asadmin start-cluster c1
    0%: start-cluster: Executing start-instance on 4 instances.
    Command start-cluster executed successfully.

    集群运行后,通过在DAS中列出正在运行的集群来验证集群是否正在运行。 通过在DAS中列出实例来验证节点实例是否正在运行。在srv01.internal.dev上执行以下命令。

    payara@srv01$ asadmin list-clusters
    c1 running
    Command list-clusters executed successfully.
    payara@srv01$ asadmin list-instances
    srv02-instance-01   running
    srv02-instance-02   running
    srv03-instance-01   running
    srv03-instance-02   running
    Command list-instances executed successfully.

    恭喜你! 您现在有了一个不错的4实例集群。 现在是时候部署应用程序了吗? 错误! 在部署应用程序之前,重要的是要验证节点之间的多播网络通信是否正常工作,以允许HttpSession在整个集群中复制。 接下来验证多播网络通信。

    集群多播验证

    拥有集群的全部目的是拥有一个高可用性,会话复制的应用程序。 如果一个实例有问题,群集中的另一个实例(可能在另一个节点上)将无缝接管。 但是,为了使这种情况真正发生,群集实例必须能够彼此成功通信。 Payara有validate-multicast工具对此进行了测试。 但是,诀窍在于如何运行validate-multicast 。 为了成功运行, validate-multicast ,必须在两个运行srv02srv03 AT同一时间 ! 执行以下的srv02.internal.dev srv03.internal.dev 在同一时间 (哈夫纳,2011)!

    srv02.internal.devsrv02.internal.dev上执行以下srv02.internal.dev

    payara@srv02$ asadmin validate-multicast
    Will use port 2048
    Will use address 228.9.3.1
    Will use bind interface null
    Will use wait period 2,000 (in milliseconds)
    
    Listening for data...
    Sending message with content "srv02" every 2,000 milliseconds
    Received data from srv02 (loopback)
    Received data from srv03
    Exiting after 20 seconds. To change this timeout, use the --timeout command line option.
    Command validate-multicast executed successfully.

    srv03.internal.dev同时为srv02.internal.dev ,还执行以下srv03.internal.dev

    payara@srv03$ asadmin validate-multicast
    Will use port 2048
    Will use address 228.9.3.1
    Will use bind interface null
    Will use wait period 2,000 (in milliseconds)
    
    Listening for data...
    Sending message with content "srv03" every 2,000 milliseconds
    Received data from srv03 (loopback)
    Received data from srv02
    Exiting after 20 seconds. To change this timeout, use the --timeout command line option.
    Command validate-multicast executed successfully.

    同一时间运行这两个命令时,实例之间的通信应该成功。 在srv02机器上,您应该看到“从srv03接收到的数据”,在srv03机器上,您应该看到“从srv02接收到的数据”。 这验证了用于HttpSession复制的节点实例之间使用的多播网络通信是否正常运行。

    就是这样! 现在,群集已完全配置,并且可以在多台计算机上运行。 我确定您急于将应用程序部署到集群中。 因此,请深入了解如何为高可用性(HA),会话复制的环境配置WAR。

    WAR配置

    一旦配置了Payara集群并使其正常运行,大多数人认为部署到该集群的任何应用程序都将利用该集群的高可用性(HA)和会话复制。 不幸的是,这种情况并非如此。 您的应用程序必须针对集群进行开发和配置。 本节将概述:

    1. HttpSession序列化
    2. web.xml <distributable />
    3. glassfish-web.xml cookieDomain

    注意所有这些配置都是必需的。 如果仅跳过1,则跨群集的会话复制将无法进行。

    应用程序所需的第一件事是会话序列化。 接下来将简要介绍这一点。

    会话序列化

    HttpSession序列化是一件简单的事情,但是大多数开发团队对此却很少关注。 通常,应用程序服务器使用序列化在整个群集中复制会话。 如果HttpSession中的对象无法序列化,则会话复制将失败。 因此,请确保放入HttpSession 所有对象都可以序列化。

    会话序列化是关键配置。 如果跳过它,则跨群集的会话复制将无法进行。

    注意在开发环境中,请使用javax.servlet.Filter运行您的应用程序,该程序尝试序列化HttpSession所有对象。 如果您进行了适当的测试,则应该可以解决任何序列化问题。

    现在HttpSession中的所有对象都可以序列化了,接下来要看的是web.xml配置。

    web.xml <distributable />

    Servlet 3.1规范的第157页将web.xml的<distributable />元素定义为“ <distributable />表示此Web应用程序已适当编程,可以部署到分布式Servlet容器中。” 这意味着必须将<distributable />添加到web.xml以便Payara知道该应用程序将在集群中运行,并且应该这样处理。 清单1显示了一个示例。

    清单1 –可分发

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
      <display-name>clusterjsp</display-name>
      <distributable/>
      <servlet>
        <display-name>HaJsp</display-name>
        <servlet-name>HaJsp</servlet-name>    
        <jsp-file>/HaJsp.jsp</jsp-file>
      </servlet>
      <servlet>
        <display-name>ClearSession</display-name>
        <servlet-name>ClearSession</servlet-name>    
        <jsp-file>/ClearSession.jsp</jsp-file>
      </servlet>
      <session-config>
        <session-timeout>30</session-timeout>
      </session-config>
      <welcome-file-list>
        <welcome-file>HaJsp.jsp</welcome-file>
      </welcome-file-list>
    </web-app>

    <distributable />元素是关键配置。 如果丢失,则跨群集的会话复制将无法进行。

    <distributable />元素是所有Java EE服务器所需的配置。 Payara也有一些自己的自定义配置。 接下来要看的是此服务器特定的配置。

    glassfish-web.xml cookieDomain

    glassfish-web.xml文件是Web应用程序特定于Payara的配置文件。 不同web.xml这是适用于所有的Java EE服务器, glassfish-web.xml仅适用于GlassFish的或似鲭水狼牙鱼EE服务器。 这意味着,如果要部署到其他EE服务器,则可能需要找到该服务器的等效配置,也可能不需要。

    对于Payara,必须更新glassfish-web.xml以添加cookieDomain属性。 清单2显示了正确设置cookieDomain值的标记层次结构。 如清单2所示,该值设置为.internal.dev (Hafner,2011年)。 您还记得吗,这是您用于群集体系结构的域。

    清单2 – cookieDomain

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
    <glassfish-web-app error-url="">
      <session-config>
        **<cookie-properties>
          <property name="cookieDomain" value=".internal.dev"/>
        </cookie-properties>**
      </session-config>
    </glassfish-web-app>

    cookieDomain属性配置很重要,因为它允许JSESSIONID cookie(用于跟踪群集节点实例之间的用户会话)在每个Web浏览器请求中传递给任何群集节点实例。 了解此处发生情况的最简单方法是解释缺少cookieDomain属性配置时发生的情况。

    注意这是即将发生的事情的预览,但这没关系。

    假设缺少cookieDomain属性配置。 然后,Web浏览器使用URL http://srv02.internal.dev:28080/ferris-clusterjsp向在一个群集节点实例上运行的应用程序发出请求。 当应用程序处理请求时,它将创建一个JSESSIONID cookie,并且该cookie的域值将(默认情况下)为用于访问应用程序的主机名,在本例中为srv02.internal.dev 。 现在,另一个请求发送到URL http://srv03.internal.dev:28080/ferris-clusterjsp 。 它是集群的一个实例,因此您希望该实例找到已经创建的会话。 但这不会发生。 因为JSESSIONID Cookie是使用域值**srv02**.internal.dev创建的,所以不会发生,因此Web浏览器不会根据对http://**srv03**.internal.dev的请求发送此Cookie。因为cookie属于srv02而不是srv03

    现在假设如清单2所示配置cookieDomain属性配置。现在会发生什么? 嗯,Web浏览器使用URL http://srv02.internal.dev:28080/ferris-clusterjsp向在一个集群节点实例上运行的应用程序发出请求。 但是,这一次,当应用程序处理请求时,它将创建一个JSESSIONID cookie,并且该cookie的域值将是您在清单2中将其配置为.internal.dev 。 现在,另一个请求发送到URL http://srv03.internal.dev:28080/ferris-clusterjsp 。 Web浏览器将随此请求一起发送JSESSIONID,因为cookie属于.internal.dev并且该请求将发送到http://srv03**.internal.dev**

    cookieDomain属性是关键配置。 如果缺少该域,或者所使用的域与cookieDomain值不匹配,则跨群集的会话复制将无法进行。

    恭喜你 您的Web应用程序已配置完毕,可以部署到集群中。 部署很容易完成,接下来您将要做。

    战争部署

    至此,您终于可以部署WAR了。 好吧,不完全是。 你有战争吗? 没有? 好吧,你很幸运。 clusterjsp应用程序在测试集群和会话复制中很受欢迎。 我在我的GitHub帐户上拥有自己的clusterjsp分支,该分支已经配置并可以部署到此示例集群。 您可以在https://github.com/mjremijan/ferris-clusterjsp/releases下载我的clusterjsp分支。 在本节中,您将看到:

    1. Payara asadmin deploy命令
    2. 验证应用程序是否在整个群集中正确部署。

    部署命令

    首先,您必须从我的GitHub帐户下载 ferris-clusterjsp-1.1.0.0.war 。 接下来,使用asadmin命令将其部署到集群。 在srv01.internal.dev上执行以下srv01.internal.dev

    $ asadmin deploy --force true --precompilejsp=true --enabled=true --availabilityenabled=true --asyncreplication=true --target c1 --contextroot=ferris-clusterjsp --name=ferris-clusterjsp:1.1.0.0 ferris-clusterjsp-1.1.0.0.war
    
    Application deployed with name ferris-clusterjsp:1.1.0.0.
    Command deploy executed successfully.

    –force true强制重新部署该Web应用程序,即使该Web应用程序已被部署。

    –precompilejsp = true ferris-clusterjsp应用程序使用一些简单的JSP文件,因此请在部署时对其进行预编译。

    –enabled = true允许在应用程序部署后对其进行访问。

    –availabilityenabled = true允许通过会话复制和钝化实现高可用性。 该方法也适用于有状态会话Bean,尽管通常不再使用它们了。

    –asyncreplication = true与处理用户请求的线程相比,在单独的异步线程中跨群集执行会话复制。

    –target c1将应用程序部署到群集c1

    –contextroot = ferris-clusterjsp将应用程序的上下文根设置为ferris-clusterjsp 。 这也可以在glassfish-web.xml定义。

    –name = ferris-clusterjsp:1.1.0.0设置应用程序在Payara管理控制台中的显示名称。 通常,最好在显示名称中包含版本号。

    ferris-clusterjsp–1.1.0.0.war要部署的WAR文件的名称。

    现在已经部署了WAR,接下来要做的是验证应用程序是否已成功部署并在所有群集节点实例上运行。

    部署验证

    当您执行上面的asadmin deploy命令时,短时间后,您应该会看到“命令部署成功执行”消息。 如果是这样,那就太好了! 该应用程序已成功部署到群集。 要验证它是否已成功部署,请在srv01.internal.dev上执行以下srv01.internal.dev

    $ asadmin list-applications --long true --type web c1
    
    NAME                       TYPE   STATUS   
    ferris-clusterjsp:1.1.0.0  <web>  enabled  
    Command list-applications executed successfully.

    asadmin命令要求Payara在群集c1上列出类型为web的所有应用程序。 应该有1个结果,即ferris-clusterjsp:1.1.0.0应用程序,并且其状态应为enabled 。 为了确保一切正常,请通过在srv01.internal.dev上执行以下操作来srv01.internal.dev节点实例的状态。

    $ asadmin list-instances c1
    
    srv02-instance-01   running  
    srv02-instance-02   running  
    srv03-instance-01   running  
    srv03-instance-02   running

    asadmin命令告诉您c1集群中有4个实例,并且所有4个实例都在运行。 ferris-clusterjsp应用程序已在集群上成功运行。 接下来要做的就是测试!

    WAR会话复制测试

    现在是时候查看集群中的会话复制是否正在运行。 这样做并不困难,但是,您将需要离开命令行世界,现在开始使用浏览器。 要测试会话复制是否正常工作,您需要:

    1. 确定到运行该应用程序的每个单独群集节点实例的链接URL。
    2. 使用网络浏览器访问每个链接。

    链接到每个实例

    您需要做的第一件事是找到URL,以访问每个集群节点实例上的ferris-clusterjsp应用程序。 这是您的操作方式。 ferris-clusterjsp应用程序在4个群集节点实例上运行,并且每个实例都有自己的URL。 请按照以下步骤获取链接列表:

    1. srv01.internal.dev上打开Web浏览器。
    2. 浏览到http://localhost:4848的Payara管理控制台。
    3. 登录(请记住,您已在Payara DAS安全配置中更改了管理员密码)。
    4. 单击“ 应用程序”树节点。

    单击“ 应用程序”树节点后,您将看到列出的ferris-clusterjsp:1.1.0.0应用程序。 图2显示在表的Action列中有一个名为Launch的超链接。 点击它!

    图2 –

    图2 –
    启动链接

    单击启动链接后,将出现一个新的浏览器窗口,其中包含指向群集中应用程序的所有链接。 图3显示了8个链接。 可以通过HTTP或HTTPS访问4个群集节点实例中的每一个。

    图3 –所有链接

    图3 –所有链接

    现在,您已经了解了所有链接,可以直接在4个实例中的每个实例上访问ferris-clusterjsp应用程序。 这将允许您测试会话复制是否正常。 如果您的第一个请求是实例srv02-instance–01 ,那么您将能够在其他3个实例上查看您的会话。 希望它会起作用!

    测试复制

    要测试会话复制是否正常工作,您需要做的就是在一个群集节点实例上访问应用程序,记下会话ID值,然后在另一个节点实例上访问该应用程序,然后查看会话是否已复制。 首先从srv02-instance–01开始 。 打开Web浏览器,然后浏览至http://srv02.internal.dev:28080/ferris-clusterjsp 。 该应用程序将显示有关群集节点实例和您的会话的信息。 您的浏览器将类似于图4a。

    图4a – srv02-instance-01上的ferris-custerjsp

    图4a – srv02-instance-01上的ferris-custerjsp

    图4a突出显示了您需要确认会话复制正常工作的一些信息。 首先,Web浏览器URL为http://srv02.internal.dev:28080/ferris-clusterjsp并且URL的主机名与页面上的“ 从服务器提供服务”信息匹配。 此外,页面还会显示为您创建的会话ID –在本例中为7ec99da15ef5c79d7c4bc3149d6b

    现在,您在应用程序上有一个会话,并且,如果一切正常,则应在整个集群中复制该会话。 要测试这一点,唯一要做的就是选择另一个群集节点实例,看看是否获得相同的会话。 选择srv03-instance–02进行下一步测试。 该群集节点实例不仅位于完全不同的物理计算机上,而且还将协议从HTTP切换到HTTPS。 打开Web浏览器并浏览到https://srv03.internal.dev:28182/ferris-clusterjsp 。 图4b显示了应该发生的情况。

    图4b – srv03-instance-02上的ferris-custerjsp

    图4b – srv03-instance-02上的ferris-custerjsp

    图4b显示了结果,它们看起来非常好! 突出显示,您可以看到从HTTP到HTTPS的切换(您的Web浏览器还应该强制您接受证书)。 Web浏览器URL为https://srv03.internal.dev:28182/ferris-clusterjsp的主机名与页面上的“ 从服务器提供服务”信息匹配。 但最重要的是,您将获得相同的会话ID –在本例中为7ec99da15ef5c79d7c4bc3149d6b

    现在,您可以享受一些乐趣,并进行更多的复制测试。 使用该页面添加一些会话属性数据,并查看它是否在集群中复制。 您首先使用哪个群集节点实例都没有关系。 选一个。 然后转到页面的Enter session attribute data:部分,并添加会话数据,如图5所示。

    图5 –添加会话属性数据

    图5 –添加会话属性数据

    单击添加会话数据按钮。 图6显示页面将刷新,并且已添加会话属性数据。

    图6 –添加的会话属性数据

    图6 –添加的会话属性数据

    添加会话属性数据后,转到其他浏览器并刷新页面。 您会看到数据已被复制。 图7并排显示了具有相同的复制会话属性数据的Web浏览器。

    图7 –浏览器并排使用相同的数据

    图7 –浏览器并排使用相同的数据

    恭喜你! 您现在拥有了一个功能齐全的多VM会话复制群集。 但是仍然缺少一些东西:高可用性(HA)。 对于高可用性,您将需要一个负载均衡器。 因此,接下来要看的是负载均衡器配置。

    负载均衡器配置

    现在,您有一个很棒的多虚拟机,会话复制集群,但它是无用的,因为它尚不可访问。 您具有访问每个单独的群集节点实例的链接,但是拥有1个实例的URL不会给您带来高可用性(HA)。 现在,您需要的是一个负载平衡器,它可以将请求发送到通用URL(例如http://srv.internal.dev然后将请求代理到集群中的任何活动实例。 And, thanks to successfully setting up session replication across the cluster, it doesn't matter which instance the load balancer proxies your request to because your session data will be the same across the cluster. For this post, you are going to use NGINX as the the load balancer. This section will look at:

    1. NGINX Installation
    2. NGINX Configuration
    3. NGINX Testing

    NGINX Installation

    Installing NGINX is simple. You should be able to use apt-get to do this. Execute the following command on srv01.internal.dev . Remember in the architecture diagram for the zone, srv01.internal.dev is the machine in the zone which will run the load balancer.

    $ apt-get install nginx

    而已。 NGINX is now installed. To get it working with your cluster node instances you will need to do a little configuration, which is what you will do next.

    NGINX Configuration

    This NGINX configuration is very simple. There are 2 things you need to do. The first is you need to setup an upstream configuration that contains the host names and port numbers of all the cluster node instances. The second is to update the location to proxy requests to the upstream .

    upsteam First, look at the upstream configuration. Assuming you installed NGINX on srv01.internal.dev , open the /etc/nginx/nginx.conf file for editing. Edit the file and add an upstream configuration as shown in the following example. The upstream configuration goes inside of the http configuration.

    http { 
      upstream cluster_c1 {
        server srv02.internal.dev:28080;
        server srv02.internal.dev:28081;
        server srv03.internal.dev:28080;
        server srv03.internal.dev:28081;
      }
    }

    Restart NGINX to pick up the changes.

    $ /etc/init.d/nginx restart

    location Next, look at the location configuration. Assuming you installed NGINX on srv01.internal.dev , open the /etc/nginx/sites-available/default file for editing. Edit the file and update the location configuration to MATCH the following example. The location configuration goes inside of the server configuration.

    server { 
      listen  80;
      server_name  localhost;
      
      upstream cluster_c1 {
      location / {
        root  html;
        index index.html index.htm;
        proxy_connect_timeout   10;
        proxy_send_timeout  15;
        proxy_read_timeout  20;
        proxy_pass http://cluster_c1;
      }
    }

    Restart NGINX to pick up the changes.

    $ /etc/init.d/nginx restart

    NGINX Testing

    By default, NGINX is configured to listen on port 80. You saw this in the previous section when you did the location configuration. If both NGINX and the Payara are up and running, here's the easiest way to test.

    1. Open a web browser on srv01.internal.dev .
    2. Browse to http://localhost

    Because NGINX is configured as a proxy in front of Payara, the browser will show the Payara-is-now-running page as in Figure 8.

    Figure 8 – Payara with localhost proxied through NGINX

    Figure 8 – Payara with localhost proxied through NGINX

    而已。 NGINX is now configured and working. That means you have the High Availability (HA) piece of the architecture ready to test. You can do that next.

    WAR High Availablity (HA) Testing

    You're in the home stretch now. Here are all the pieces of the architecture so far:

    1. A Payara cluster able to support session replication.
    2. An application coded and configured to take advantage of session replication.
    3. A Payara cluster running multiple node instances.
    4. An NGINX load balancer configured to proxy requests to the cluster node instances.

    Now it's time to see if all the pieces work together. For these final tests, you need to have a web browser capable of sending requests through the NGINX load balancer. Remember 2 very important things:

    1. The load balancer is running on srv01.internal.dev on port 80.
    2. The URL you use must end with .internal.dev .

    The easiest way to do this is to edit your testing machine's hosts file and add a host to test the cluster. Assume the test hostname will be srv.internal.dev . Then add the following to your testing machine's hosts file:

    $ cat /etc/hosts
    127.0.0.1  localhost
    10.0.2.16  srv01.internal.dev srv01
    10.0.2.17  srv02.internal.dev srv02
    10.0.2.18  srv03.internal.dev srv03
    10.0.2.16  srv.internal.dev

    The first test you should do is to repeat the simple NGINX test. Only this time use the hostname you just saved in the hosts file. Perform the test by doing the following:

    1. Open a web browser on the testing machine.
    2. Browse to http://srv.internal.dev

    Because NGINX is configured as a proxy in front of Payara, the browser will show the Payara-is-now-running page as in Figure 9. The difference this time is the URL uses the hostname saved in the hosts file.

    Figure 9 – Payara with srv.internal.dev proxied through NGINX

    Figure 9 – Payara with srv.internal.dev proxied through NGINX

    Now here comes the final test to make sure everything is working. Open a web browse to the ferris-clusterjsp application and see what happens. Perform the test by doing the following:

    1. Open a web browser on the testing machine.
    2. Browse to http://srv.internal.dev/ferris-clusterjsp .

    If everything goes OK, you will see the HA JSP Sample page handled by one of the cluster node instances. Figure 10 shows that srv03-instance-01 handled the first request.

    Figure 10 – Payara with ferris-clusterjsp proxied through NGINX

    Now the exciting part. Keep testing! Keep reloading the page. As seen in Figure 11, you will see the Served From Server instance: and Executed Server IP Address: change as the NGINX load balancer proxies requests to different cluster node instances, but the Session ID will remain the same. 凉!

    Figure 11 – Payara with ferris-clusterjsp proxied through NGINX Figure 11 – Payara with ferris-clusterjsp proxied through NGINX

    Now for an even more fun test. High Availability (HA) means if a cluster node instance goes down the application still keeps running and your users are not impacted. 试试吧! Shut down one of the cluster node instances and see what happens. Execute the following command on srv01.internal.dev :

    bash $ asadmin stop-instance srv03-instance-01

    This will stop the 1 instance of the cluster. Now go back to your browser and start reloading the page. While you are reloading, watch the Served From Server instance: value. Because srv03-instance-01 is now shut down, you'll notice this instance will be skipped as the load balancer round-robins through the cluster instances. One instance of your cluster is stopped, but your application is still working fine. If you want to start the instance again, Execute the following command on srv01.internal.dev :

    $ asadmin start-instance srv03-instance-01

    This will restart the instance. Now go back to your browser and start reloading the page again. While you are reloading, watch the Served From Server instance: value. You'll eventually notice srv03-instance-01 will come back! :)

    摘要

    My goal for this post was to consolidate in one place the instructions to create a high availability (HA), session replicated, multi-machined Payara/GlassFish cluster. Hopefully I accomplished that goal by giving instructions for the following:

    1. Creating a multi-machine architecture for a cluster
    2. Installing Payara
    3. Configuring the DAS for cluster communication
    4. Creating the cluster
    5. Creating the cluster nodes
    6. Creating the cluster node instances
    7. Configuring a WAR to use session-replication
    8. Configuring NGINX for load balancing & proxying.
    9. Testing everything at every step of the way to make sure it's all working.

    I hope you have found this post useful. And also please note the title of this post says “(almost)” for a good reason: this is not the only way to create a high availability (HA), session replicated, multi-machined Payara/GlassFish cluster. But it is A way.

    参考资料

    Java Servlet 3.1 Specification (2013, May 28). Java Servlet 3.1 Specification for Evaluation [PDF]. Retrieved from http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html

    Hafner, S. (2011, May 12). Glassfish 3.1 – Clustering Tutorial Part2 (sessions) [Web log post]. Retrieved from https://javadude.wordpress.com/2011/05/12/glassfish-3-1-%E2%80%93-clustering-tutorial-part2-sessions/ .

    Hafner, S. (2011, April 25). Glassfish 3.1 – Clustering Tutorial [Web log post]. Retrieved from https://javadude.wordpress.com/2011/04/25/glassfish-3-1-clustering-tutorial/

    Mason, R. (2013, September 03). Load Balancing Apache Tomcat with Nginx [Web log post]. Retrieved from https://dzone.com/articles/load-balancing-apache-tomcat

    Fasoli, U. (2013, August 17). Glassfish Cluster SSH – Tutorial : How to create and configure a glassfish cluster with SSH (Part 2) [Web log post]. Retrieved from http://ufasoli.blogspot.com/2013/08/

    Fasoli, U. (2013, July 17). Glassfish asadmin without password [Web log post]. Retrieved from http://ufasoli.blogspot.fr/2013/07/glassfish-asadmin-without-password.html

    Oracle GlassFish Server 3.1 Section 1: asadmin Utility Subcommands. (nd)。 Retrieved from https://docs.oracle.com/cd/E18930_01/html/821-2433/gentextid-110.html#scrolltoc

    Camarero, RM (2012, January 21). clusterjsp.war [WAR]. Retrieved from http://blogs.nologin.es/rickyepoderi/uploads/SimplebutFullGlassfishHAUsingDebian/clusterjsp.war

    Croft, M. (2016, June 30). Creating a Simple Cluster with Payara Server [Web log post]. Retrieved from http://blog.payara.fish/creating-a-simple-cluster-with-payara-server

    Administering GlassFish Server Clusters. (nd) Retrieved from https://docs.oracle.com/cd/E26576_01/doc.312/e24934/clusters.htm#GSHAG00005

    Administering GlassFish Server Nodes. (nd)。 Retrieved from https://docs.oracle.com/cd/E26576_01/doc.312/e24934/nodes.htm#GSHAG00004

    Administering GlassFish Server Instances. (nd)。 Retrieved from https://docs.oracle.com/cd/E26576_01/doc.312/e24934/instances.htm#GSHAG00006

    翻译自: https://www.javacodegeeks.com/2017/06/high-availability-ha-session-replicated-multi-vm-payara-cluster.html

    payara 创建 集群

    展开全文
  • Payara Micro 5上的Jakarta EE 8的Microj模板 一个Microj模板,用于在Payara Micro 5上运行带有Java 11的Jakarta EE 8微服务。 维护者 M.-Leander Reimer(@lreimer), -leander.reimer 执照 该软件是根据MIT开源...
  • 步骤1:在Payara 5中添加Connector / J(JDBC MySQL Connector) 为了与MySQL通信,似鲭水狼牙鱼需要连接器/ J。下载并解压缩Connector / J的存档后,找到名为mysql-connector-java-5.1.47.jar的JAR文件 。应该在{...

    步骤1:在Payara 5中添加Connector / J(JDBC MySQL Connector)

    为了与MySQL通信,似鲭水狼牙鱼需要连接器/ J。下载并解压缩Connector / J的存档后,找到名为mysql-connector-java-5.1.47.jar的JAR文件  。应该在{PAYARA_HOME | / glassfish / lib文件夹中手动复制此文件,如下面的屏幕截图所示:

    图片标题

    第2步:从CLI 启动Payara domain1

    打开控制台/终端,导航到{PAYARA_HOME} / bin文件夹,然后键入asadmin start-domain命令:

    图片标题

    命令成功执行后(这可能需要几秒钟),您应该看到消息:“ 命令start-domain已成功执行。”

    但是,有一种可能性,而不是这个好消息获得NullPointerException,如下所示:

    图片标题

    最有可能的是,您获得此错误是因为您安装并默认为Payara不支持的Java(JDK)版本。我们必须通过设置AS_JAVA支持的JDK发行版来取悦Payara 。JDK 8是最安全的。在同一台机器上安装多个JDK没有任何错误或不寻常,所以不要担心这个方面。只是指示Payara使用兼容的。

    要设置  AS_JAVA,请编辑文件{PAYARA_HOME} /glassfish/config/asenv.bat(在Windows计算机上)或{PAYARA_HOME} /glassfish/config/asenv.conf(在Linux计算机上)并添加到底部它是一行,set AS_JAVA=C:\Program Files\Java\jdk1.8.0_111(在Windows机器上)或AS_JAVA="/usr/lib/jvm/jdk1.8.0_111"(对于Linux机器):

    图片标题

    完成此编辑后,asadmin start-domain再次运行该命令。这一次,它应该按预期工作。

    此外,打开您最喜欢的浏览器并导航到  localhost:4848。不久,您应该看到Payara Server Console,如下所示:

    图片标题

    步骤3:通过Payara界面创建新的JDBC连接池

    在左侧面板中,找到JDBC | “JDBC连接池”节点,然后单击它。这将打开包含当前配置的连接池的JDBC连接池向导:

    图片标题

    在此向导中,单击“ 新建”按钮,然后开始为MySQL配置新的连接池。将池名称填充为MySqlPool(或任何其他名称),将资源类型填充为javax.sql.DataSource,将数据库驱动程序供应商填充为MySql

    图片标题

    完成后,只需单击右上角的“ 下一步”按钮。这将带您进入此配置过程的第二步。

    在第二步中,我们有一个由几个部分组成的向导。第一部分名为  常规设置,它应包含已设置的正确设置。因此,向下滚动到第二部分,池设置

    图片标题

    我们将保留默认设置,但是,从这里,您可以轻松自定义连接池设置,例如最大池大小。 

    再次向下滚动,您将找到“ 交易”部分。我们也不会修改此部分,但如果您希望事务在特定的隔离级别(例如,可重复读取)中执行,那么这是在其他配置旁边执行此操作的地方。

    图片标题

    在此向导下方,我们有Additional Properties表。此面板包含特定属性,具体取决于数据库供应商。在这种情况下,此表包含特定于MySQL的全面属性列表:

    图片标题

    您可以随意调整这些属性的值以满足您的需求。目前,我们处理以下属性:UserPasswordDatabaseNameServerNameURLurl CreateDatabaseIfNotExist

    图片标题

    所以,我们在连接本地主机到数据库命名的玩家,将如果不存在则自动创建。用户和密码的凭据是  rootroot (如果您愿意,请使用其他帐户凭据)。默认的MySQL端口是3306.找到并编辑其中的每个属性后,只需单击“  完成”按钮(位于右上角)。 

    创建了新的连接池,现在,您应该在连接池列表中看到它,如下图所示:

    图片标题

    但是,我们怎么知道我们的连接池工作正常?好吧,Payara提供了一个很酷的  Ping设施。对于初学者,单击连接池名称并等待其加载。

    图片标题

    你应该看到一个Ping按钮。在单击此按钮之前,请确保MySQL正在运行符合您的设置。在这种情况下,它应该在localhost:3306上运行。单击此按钮后,您应收到Ping成功消息或错误消息,说明出现了什么问题。

    图片标题

    好的,到目前为止一切顺利!

    第4步:通过Payara界面创建JDBC资源

    现在,我们必须创建一个利用我们的连接池的JDBC资源。为此,在左侧面板中,单击JDBC | JDBC资源节点。不久,您应该看到可用JDBC资源的列表:

    图片标题

    单击“ 新建”按钮以启动用于创建JDBC资源的向导。对于标识JDBC资源的唯一JNDI名称,请键入  jdbc / players。对于池名称,从下拉列表中选择MySqlPool连接池。 

    图片标题

    最后,单击右上角的“ 确定”按钮。您应该看到列出的新JDBC资源如下:

    图片标题

    完成!现在,只需关闭Payara Server Console即可。此外,我们专注于Spring Boot应用程序。

    第5步:获取Spring Boot Kickoff应用程序

    为了开发将使用上述JDBC资源的应用程序,我们选择了一个基于Maven的Spring Boot启动应用程序,其中包含以下启动程序:  starter-data-jpa,  starter-jdbc,  starter-web,  starter-test

    一种简单快捷的方法是使用Spring Initializr向导。

    第6步:准备Payara的pom.xml

    为了在Payara下部署我们的Spring Boot应用程序,我们需要调整pom.xml文件,如下所示:

    - 通常,Spring Boot应用程序打包为JAR,但我们需要一个WAR,所以准备  <packaging>相应的:

    < 包装>战争</ packaging >
    

    - 默认情况下,在Tomcat上部署Spring Boot应用程序,因此我们需要排除Tomcat:

    < 依赖>
    
        < groupId > org.springframework.boot </ groupId >
    
        < artifactId > spring-boot-starter-web </ artifactId >
    
        < exclusions >
    
            < 排除>
    
                < groupId > org.springframework.boot </ groupId >
    
                < artifactId > spring-boot-starter-tomcat </ artifactId >
    
            </ exclusion >
    
        </ exclusions >
    
    </ dependency >
    

    - 一旦我们删除了Tomcat,由于缺少Servlet API,我们无法编译代码,因此我们需要以明确的方式提供Servlet API依赖:

    < 依赖>
    
        < groupId > javax.servlet </ groupId >
    
        < artifactId > javax.servlet-api </ artifactId >
    
        < scope >提供</ scope >
    
    </ dependency >
    

    - 这里提供完整的pom.xml 。

    步骤7:通过JNDI,JDBC / Players配置数据源

    请记住,我们已经创建了一个JDBC资源和一个连接池,它具有JNDI名称jdbc / players的入口点  。现在,我们指示我们的应用程序javax.sql.DataSource 通过此JNDI名称公开。为此,我们依赖Spring,JndiDataSourceLookupAPI如下:

    @组态
    
    公共 类 DataSourceConfigurer {
    
     
        private  static  final  String  JNDI  =  “jdbc / players” ;
    
     
        @Bean(destroyMethod  =  “”)//禁止将潜在的close()方法推断为驱逐舰
    
        public  DataSource  dataSource()抛出 DataSourceLookupFailureException {
    
            JndiDataSourceLookup  dataSourceLookup  =  new  JndiDataSourceLookup();
    
            return  dataSourceLookup。getDataSource(JNDI);
    
        }
    
    }
    

    此类的完整源代码可在此处获得。

    第8步:创建模型

    此外,我们创建了一个名为的简单JPA实体Player

    @实体
    
    @Table(name = “player”)
    
    public  class  Player  实现 Serializable {
    
     
        private  static  final  long  serialVersionUID  =  1L ;
    
     
        @ID    
    
        私人 长 身份 ;
    
     
        私有 字符串 名称 ;
    
        私人 弦 城 ;
    
        私人 INT  年龄 ;
    
        ...
    
    }
    

    这个类的完整源代码在这里。

    步骤9:定义典型的Spring存储库

    接下来,我们定义一个典型的Spring存储库  Player

    @Repository
    
    public  interface  PlayerRepository  扩展 JpaRepository < Player,Long > {        
    
    }
    

    这个类的完整源代码在这里。

    第10步:创建一个典型的Spring服务

    此外,我们定义了一个典型的Spring服务,它将公开两种方法:一种用于持久化id为1的单个玩家的方法,另一种用于通过id查找此玩家的方法:

    @服务
    
    公共 类 PlayerService {
    
     
        private  final  PlayerRepository  playerRepository ;
    
     
        public  PlayerService(PlayerRepository  playerRepository){
    
            这个。playerRepository  =  playerRepository ;
    
        }
    
     
        public  Player  newPlayerWithIdOne(){
    
           ...
    
        }
    
     
        public  Player  findFirstPlayer(){
    
           ...
    
        }
    
    }
    

    这个类的完整源代码在这里。

    步骤11:通过@RestController公开此服务

    接下来,我们创建一个公共Spring控制器,公开两个端点,一个GET端点(/ fetch)和一个POST端点(/ new):

    @RestController
    
    public  class  PlayerController {
    
     
        私人 最终的 PlayerService  playerService ;
    
     
        public  PlayerController(PlayerService  playerService){
    
            这个。playerService  =  playerService ;
    
        }
    
     
        @GetMapping(“/ fetch”)
    
        public  Player  fetchPlayer(){
    
     
            返回 playerService。findFirstPlayer();
    
        }
    
     
        @PostMapping(“/ new”)
    
        public  Player  newPlayer(){
    
     
            返回 playerService。newPlayerWithIdOne();
    
        }
    
     
    }
    

    这个类的完整源代码在这里。

    第12步:定义主类

    我们的应用程序的主要类依赖于SpringBootServletInitializerAPI:

    @SpringBootApplication
    
    @EntityScan(“com.jpa.model”)   
    
    @ComponentScan({ “com.http.requests”,“com.services” })
    
    @EnableJpaRepositories(“com.jpa.queries”)
    
    公共 类 SpringBootPayaraMySqlKickoffApplication  扩展 SpringBootServletInitializer {
    
     
        @覆盖
    
        protected  SpringApplicationBuilder  configure(SpringApplicationBuilder  应用程序){
    
            退货 申请。来源(SpringBootPayaraMySqlKickoffApplication。类);
    
        }
    
     
        public  static  void  main(String [] args){
    
            SpringApplication。运行(SpringBootPayaraMySqlKickoffApplication。类,ARGS);
    
        }
    
    }
    

    这个类的完整源代码在这里。

    步骤13:从简单的HTML页面使用端点

    您可以通过curl,ARC Rest Client,Postman等轻松测试端点(/ fetch/ new),但我们更喜欢基于普通AJAX的简单HTML页面:

    < script >
    
        function  newPlayer(){
    
            var  xhttp  =  new  XMLHttpRequest();
    
            ...
    
        }
    
     
        function  fetchPlayer(){
    
            var  xhttp  =  new  XMLHttpRequest();
    
            ...
    
        }
    
    ...
    
    < 按钮 类型= “按钮”  的onclick = “newPlayer()” > 插入 一个 单一的 播放器 与 ID  1 < /按钮>
    
    < 按钮 类型= “按钮”  的onclick = “fetchPlayer()” > 获取 播放机 与 ID  1 < /按钮>
    

    这个页面的完整源代码在这里。

    步骤14:提供众所周知的Application.Properties

    如您所知,Spring Boot依赖application.properties文件作为主配置文件。我们为这个文件提供了一些有用的Hibernate设置:

    #创建架构,销毁以前的数据
    
    小号p - [R 我Ñ 克。Ĵ p 一个。ħ 我b Ë ř Ñ 一吨ë 。d d 升- 一个Ù 吨Ô = C ^ - [R Ë 一吨ë
    
     
    #显示已执行的SQL 
    
    小号p - [R 我Ñ 克。Ĵ p 一个。小号ħ ö 瓦特- 小号q 升 = 吨- [R ù ë
    
     
    #display statistics
    
    小号p - [R 我Ñ 克。Ĵ p 一个。p - [R ø p é ř 吨我Ë 小号。ħ 我b Ë ř Ñ 一吨ë 。克Ë Ñ Ë ř 一吨ë _ 小号吨一吨我小号吨我Ç 小号 = 吨- [R ù ë
    

    步骤15:添加web.xml和glassfish-web.xml描述符

    为了以防万一,您将需要标准部署描述符(web.xml)。我们提供了一个空的:

    <?xml  version =“1.0”encoding =“UTF-8”?>
    
    < web-app  metadata-complete = “true”
    
             xmlns = “http://xmlns.jcp.org/xml/ns/javaee”
    
             xmlns:xsi = “http://www.w3.org/2001/XMLSchema-instance”
    
             xsi:schemaLocation = “http://xmlns.jcp.org/xml/ns/javaee
    
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd”
    
             version = “3.1” >
    
     
    </ web-app >
    

    此外,如果您需要Glassfish Descriptor(glassfish-web.xml),那么它(我们已经用它来自定义根上下文):

    <?xml  version =“1.0”encoding =“UTF-8”?>
    
    <!DOCTYPE glassfish-web-app PUBLIC ...>
    
       < glassfish-web-app  error-url = “” >
    
       ...
    
       <! - 设置友好的上下文根 - >
    
       < context-root > / players </ context-root >
    
     
       <! - 将默认字符编码从ISO-8859-1更改为UTF-8  - >
    
       < parameter-encoding  default-charset = “UTF-8” />
    
    </ glassfish-web-app >
    

    这个文件的完整源代码在这里。

    步骤16:编译应用程序并找到WAR

    好吧,是时候编译应用程序了。当然,我们可以通过不同的方式(例如,从我们最喜欢的IDE等)执行此操作,但是我们只需mvn clean install从项目文件夹中运行  命令:

    图片标题

    现在,您应该有一个包含应用程序WAR 的/ target文件夹。

    步骤17:在Payara上部署WAR

    只有一个重要步骤将我们与运行应用程序(部署步骤)区分开来。同样,我们可以从我们最喜欢的IDE部署应用程序(例如,从NetBeans很容易实现),或者通过Maven,但这次,我们可以通过Payara界面进行部署。

    启动Payara Server Console并导航到Applications节点。单击Deploy按钮:

    图片标题

    此外,我们需要在Payara(部署)上传WAR文件。只需单击Choose File按钮,然后选择我们应用程序的WAR。此外,选择Web Application作为应用程序类型

    图片标题

    单击右上角的“ 确定”按钮,等待Payara完成部署。最后,您将自动重定向到包含已部署应用程序的表。

    第18步:启动应用程序

    在此表中,找到我们的应用程序并单击“ 启动”按钮:

    图片标题

    此时,您将看到两个可用链接,一个在端口8080(http)上,另一个在端口8181(https)上。点击8080链接:

    图片标题

    该应用程序应该启动,如下所示:

    图片标题

    现在,我们可以尝试持久并获取ID为1的播放器。例如,您可以尝试以下三个步骤的顺序:

    图片标题

    完成!要停止Payara,只需在命令行运行:asadmin stop-domain

    展开全文
  • Payara-k8s-operator

    2021-03-29 01:54:59
    Payara Kubernetes运营商 Payara Kubernetes运营商的POC。 Payara不支持,目前欢迎在此存储库上发表评论,评论和反馈。 演示 目录demo包含一个测试应用程序,将在操作员示例/ POC中使用。 您需要使用以下内容构建...
  • 上一篇介绍了有关payara(似鲭水狼脂鲤,一种鱼,很凶狠)的一些背景,这次我们来看下如何开始一个标准的JakartaEE项目(包含JPA配置),包括下载必要的工具、安装、配置及启动。 一、需要的工具: openjdk(zulu...
  • Payara-micro-on-heroku Heroku上的示例Payara Micro应用程序。
  • payara /home/payara/.bashrc 还需要一个系统单元: echo '[Unit] Description = Payara Server v5 After = syslog.target network.target [Service] User=payara ExecStart = /usr/bin/java -jar /opt/payara5/...
  • payara.micro抽象 在研究如何创建高可用性(HA)时,我发现了会话复制的多机Payara / GlassFish群集,无法在一个参考中找到所需的一切。 我认为这将是一个普遍的需求并且很容易找到。 不幸的是,我的假设是错误的。 ...
  • 我在这里回答的问题之一是如何在docker容器中更改Payara Server主密码 。 显然,在标准服务器安装中,这很简单–只需使用asadmin change-master-password命令,然后在控制台中输入旧密码和新密码即可。 但是不在...
  • 雅加达测试项目 Java 11,Payara服务器
  • payara-5.2021.4.zip

    2021-07-01 17:25:05
    payara-5.2021.4.zip
  • payara.micro 想知道如何开始使用Java EE Microservices? 使用Java EE API只需很少的步骤即可部署微服务。 许多人认为Java EE对于与微服务一起使用而言过于繁重,但事实并非如此……尤其是如果您仅利用服务所需的...
  • payara 创建 集群 想知道如何开始使用Java EE Microservices? 使用Java EE API部署微服务只需要几个快速步骤。 许多人认为Java EE对于与微服务一起使用而言过于繁重,但事实并非如此……尤其是如果您仅利用服务所...
  • payara 创建 集群 回答Stackoverflow问题可以为我发现我最喜欢的开源工具的正式文档中的空白提供很好的反馈。 我在这里回答的问题之一是如何在docker容器中更改Payara Server主密码 。 显然,在标准服务器安装中,...
  • 但是,我熟悉Payara Micro,并且非常喜欢Payara Micro环境,因此在本示例中,我将绕过Jetty的使用并部署到Payara Micro。 首先,通过阅读文档熟悉Jib Maven流程很重要。 在此示例中,我利用了我在2018年为《 Java ...
  • payara 创建 集群 前一段时间,我写了一个小教程 ,介绍如何生成“让我们加密SSL”证书并将其安装在Glassfish Java EE平台上。 这个技巧对我来说是一个奇迹,但是每三个月必须手动更新和重新安装证书变得很烦人。 ...
  • 想知道如何开始使用Java EE Microservices? 使用Java EE API只需很少的步骤即可... 在这篇简短的文章中,我将演示如何使用Java EE快速开发微服务,然后将其部署到Payara Micro。 要下载示例项目,请转到GitHub...
  • Payara基金会最近发布了5.183版Payara Server和Payara Micro,其中包含大量新功能、升级和Bug修复,并开始全面支持MicroProfile2.0和Java EE 8。该版本提供的新功能包括:有关MicroProfile API和Admin Console的更新...
  • 先查看命令行输入是否正确 在命令行中输入java -version查看java版本是否为1.8 如不是则下载相应1.8版本并在环境变量中更改为java路径 环境变量设置指路 java环境变量设置

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 559
精华内容 223
关键字:

Payara