应用服务器到底是个啥?| 从开发角度看应用架构2:对Java EE应用进行打包和部署!

一、前言

本文仅代表作者的个人观点;

本文在书写过程中,得到了同事kylin和shuli的指导,在此表示感谢;

本文的内容仅限于技术探讨,不能作为指导生产环境的素材;

本文素材是红帽公司产品技术和手册;

本文分为系列文章,将会有多篇,初步预计将会有9篇。

一.上篇回顾

在上一篇中,我们介绍了Java的基础,并通过maven编译和运行一个Java应用。具体而言:

  • 企业应用程序的特点是能够处理事务性工作负载、多组件集成、安全性、分布式体系结构和可伸缩性。
  • Java企业版(Java EE)是使用Java开发企业应用程序的规范。它是一个独立于平台的标准,是在Java Community Process(JCP)的支持下开发的。实现Java EE规范的软件系统称为应用程序服务器。
  • Java SE API为实现Java应用程序提供了丰富的模块化可重用组件。 Java EE构建于Java SE之上,并提供一组专注于开发企业应用程序的API。
  • Java EE应用程序设计为多层结构,并可根据用例适应各种体系结构。
  • 红帽JBoss Developer Studio是红帽提供的基于Eclipse™的IDE,包含一组集成插件和工具,可简化Java EE企业应用程序的开发。它支持许多应用程序服务器,您可以从IDE内部管理应用程序服务器的生命周期。
  • Apache Maven是构建,打包和部署Java SE和Java EE应用程序的首选工具。 JBDS内置了对Maven的支持。项目可以使用Maven插件构建、测试、打包并部署到应用程序服务器。

三.应用服务器到底是个啥?

应用程序服务器是一个软件组件,提供必要的运行时环境和基础结构来托管和管理Java EE企业应用程序。 应用程序服务器提供诸如并发性、分布式组件架构、多平台可移植性、事务管理、Web服务、数据库对象关系映射(ORM)、异步消息传递以及企业应用程序安全性等功能。

在Java SE应用程序中,这些功能必须由开发人员手动实现,这很耗时且难以正确实现。

下图展示的就是JavaSE和Java EE应用部署的区别。简单而言,JavaSE应用,我们可以通过java -jar直接运行;而Java EE应用,需要部署到app server上去运行。

JBoss企业应用平台7,JBoss EAP 7或简称EAP,是一个用于托管和管理Java EE应用程序的应用程序服务器。EAP 7建立在基于Wildfly开源软件的开放标准上,并提供以下功能:

  • 用于部署应用程序的可靠,符合标准,轻量且受支持的基础架构。
  • 一种模块化结构,只有在需要时才允许用户启用服务。这可以提高性能和安全性,并减少启动和重启时间。
  • 基于Web的管理控制台和管理命令行界面(CLI),用于配置服务器并提供脚本和自动执行任务的功能。
  • 它已通过Java EE 7完整认证和Web配置文件认证。
  • 集中管理多个服务器实例和物理主机。
  • 提供了用于高可用性群集,消息传递和分布式缓存等功能的预配置选项。
  • EAP 7使开发企业应用程序变得更加简单,因为它提供了用于访问数据库,身份验证和消息传递的Java EE API。 Java EE API和框架(由EAP提供)还支持常见的应用程序功能,用于开发Web用户界面,公开Web服务,实现加密和其他功能。 JBoss EAP还通过提供运行时指标,集群服务和自动化使管理变得更加简单。
  • EAP采用模块化架构,具有简单的核心基础架构,可控制基本的应用服务器生命周期并提供管理功能。核心基础设施负责装载和卸载模块。模块实现了大量的Java EE 7 API。每个Java EE组件API模块都作为子系统实现,可以根据需要通过EAP的配置文件或管理界面来配置,添加或删除它们。例如,要配置对EAP中的数据库的访问权限,请配置数据源子系统中的数据库连接详细信息。

EAP体系结构的一个重要概念是模块的概念。模块提供了由EAP服务或应用程序使用的代码(Java Classes)。

其实这点也好理解,我们写个java程序,很多时候需要import类来做一些事情。举个简单的代码。

代码要实现的效果:

A:键盘录入月份的值,所以我们要使用Scanner。

B:我们应该判断这个月份在那个季节

我们看一下源码:

我们可以看到,第一行是import java.util.Scanner,这其实就是导入键盘录入功能的包。这个包是在SDK中。

成功编译:

运行应用,我们看到,import的包起作用了:

在EAP中,模块被加载到独立的类加载器中,并且只有在明确请求时才能看到来自其他模块的类。这意味着可以实现一个模块,而不用担心与其他模块的实施可能产生冲突。在EAP中运行的所有代码(包括由核心提供的代码)都在模块内部运行。这包括应用程序代码,这意味着应用程序彼此隔离并且来自EAP服务。

这种模块化体系结构允许对代码可视性进行非常细致的控制。应用程序可以看到一个暴露特定版本的API的模块,而另一个应用程序可能会看到另一个暴露不同版本的相同API的模块。

应用程序开发人员可以手动控制此可见性,并且在某些情况下它可能非常有用。但是对于大多数常见情况,EAP 7会根据其对Java EE API的使用情况自动决定向应用程序公开哪些模块。

四. 两种容器

我们在中间件中说的容器,指的不是时下很火的lxc、Docker等。这里的容器是指:应用程序服务器中的逻辑组件,为应用程序服务器上部署的应用程序提供运行时上下文。容器充当应用程序组件与应用程序服务器提供的低级基础架构服务之间的接口。

应用程序中的不同类型的组件有不同的容器。应用程序组件部署到容器并可用于其他部署。部署基于部署描述符(与代码一起打包的XML配置文件)或代码级别注释,指示应该如何部署和配置组件。

Java EE应用程序服务器中有两种主要的容器类型(我们可以简单地把容器理解成线程池):

  • Web容器:部署和配置Web组件,例如Servlets,JSP,JSF和其他Web相关资产。
  • EJB容器:部署和配置与EJB,JPA和JMS相关的组件。这些类型的部署将在后面的章节中详细介绍。

容器负责安全性、事务处理、JNDI查找和远程连接等。容器还可以管理运行时服务,例如EJB和Web组件生命周期,数据源池,数据持久性和JMS消息传递。例如,Java EE规范允许您声明性地配置安全性,以便只有授权用户才能调用应用程序组件提供的功能。此限制使用XML部署描述符或代码中的注释进行配置。此元数据在部署时由容器读取,并相应地配置组件。

五、Java EE 7配置文件

Java EE应用程序服务器上下文中的配置文件,是一组针对特定应用程序类型的组件API。配置文件是Java EE 6中引入的一个新概念。目前在Java EE 7中定义了两个配置文件,而JBoss EAP应用程序服务器完全支持这两个配置文件:

  • 完整配置文件:包含所有Java EE技术,包括Web配置文件中的所有API以及其他。
  • Web Profile:包含用于开发动态Web应用程序的完整Java EE API。

有超过30种不同的技术构成了Java EE的完整配置文件。每种技术都有自己的JSR规范和版本号。通常是结合使用:它们允许Java EE应用程序连接到数据库、发布和使用Web服务、提供Web应用程序、执行事务、实施安全策略以及连接到大量外部资源,以执行诸如消息传递,命名,发送电子邮件以及与非Java应用程序通信。

Web配置文件包含Web开发人员常用的Java EE的基于Web的技术,如Servlet、Java Server Pages、Java Server Faces、CDI、JPA、JAX-RS、WebSockets和Enterprise Java Beans的限制版本(EJB),称为EJB Lite。

六、识别JNDI资源

在跨多个服务器、运行不同组件的分布式多层应用程序中,组件需要相互通信。例如,Java客户端可能调用部署在单独机器上的EJB上的方法,并且EJB组件与数据库通信以检索数据。 Java命名和目录接口(JNDI)是目录服务(用于查找资源)的Java API,允许组件通过逻辑名称发现和查找对象。

资源是一个逻辑对象,可以被Java EE应用程序中的组件查找和使用。每个资源都由唯一名称标识,称为JNDI名称或JNDI资源绑定。例如,JBoss EAP默认提供的Java Database Connectivity(JDBC)数据源的JNDI名称(指向嵌入式H2数据库)为java:jboss /datasources / ExampleDS。

JNDI资源不仅限于JDBC数据源。可以配置多种类型的资源,例如JMS ConnectionFactory对象,消息传递队列和主题,电子邮件服务器,线程池等。

每个不同的JNDI绑定都是在逻辑名称空间下组织的,通常称为JNDI树。以下是JBoss EAP应用程序服务器中最常见的一些命名空间:

JDBC数据源在java:jboss/datasources / *名称空间下注册。

JMS相关资源在java:jboss / jms / *命名空间下注册(在java下的JMS队列:jboss / jms / queue / *和java下的主题:jboss / jms / topic / *)。

与电子邮件相关的资源在java:jboss / mail / *命名空间下注册。

线程和并发相关资源在java:jboss / ee / concurrency / *名称空间下注册。

七、使用CDI进行资源注入

Java EE 7提供上下文和依赖注入(CDI),使组件无需手动实例化服务器资源或组件对象,即可获取对其他组件对象的引用以及应用程序服务器资源。 这使得松散耦合的架构成为可能,客户端不需要知道被调用对象的所有底层实现细节。

在应用程序服务器级别配置所需的JNDI资源绑定后,可以使用@Resource注释将资源注入到需要资源的应用程序中。 应用程序服务器在运行时实例化资源并提供对资源的引用。

例如,我们已在EAP配置文件中配置了如下的JDBC数据源绑定:

<subsystem xmlns="urn:jboss:domain:datasources:4.0">
<datasources>
   <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
       <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
       <driver>h2</driver>
       <security>
           <user-name>sa</user-name>
           <password>sa</password>
       </security>
   </datasource>
</datasources>
...

我们可以将java:jboss / datasources / ExampleDS数据源注入到应用程序中,如下所示:

public class TestDS {    
@Resource(name="java:jboss/datasources/ExampleDS")
    private javax.sql.DataSource ds;

    // Use the DataSource reference to create a Connection etc..

如果我们在EAP中设置了类似以下的JMS队列资源:

<jms-queue name="helloWorldQueue" entries="java:jboss/jms/queue/helloWorldQueue"/>

我们可以通过将资源注入到JMS客户端类来将消息发送到此队列:

@Resource(mappedName = "java:jboss/jms/queue/helloWorldQueue")private Queue helloWorldQueue;

@Inject
JMSContext context;

    // Use the Queue object to send messages...
        try {
            context.createProducer().send(helloWorldQueue, "Hello World!");
            ...
        }

接下来,我们实验验证JNDI

在实验环境启动JBoss EAP:

EAP启动成功以后,我们接下来看JNDI。

应用程序服务器维护一个JNDI资源绑定列表。 应用程序需要的资源(例如邮件,JDBC数据源和JMS连接工厂和队列)绑定到各自名称空间下的唯一可识别名称。

JDBC数据源绑定到java:jboss / datasources / *名称空间。 在/opt/jboss-eap-7.0/standalone/log/server.log文件中,确认您可以看到以下两个数据源绑定:

ExampleDS绑定指向EAP附带的嵌入式H2数据库。MySQLDS绑定指向一个MySQL数据库,该数据库将将会被下面一小节的JavaEE应用使用。。

八、打包并部署一个Java EE应用

Java EE应用程序可以以不同的方式打包,以部署到兼容的应用程序服务器。 根据应用程序类型及其包含的组件,可以将应用程序打包到不同的部署类型(包含类,应用程序资产和XML部署描述符的压缩存档文件)中。 三种最常见的部署类型是:

JAR文件:JAR文件可以包含Plain Old Java Object(POJO)类,JPA Entity Beans、实用程序Java类、EJB和MDB。 部署到应用程序服务器时,根据JAR文件内部组件的类型,应用程序服务器会查找XML部署描述符或代码级别注释,并相应地部署每个组件。

WAR文件:WAR文件用于打包Web应用程序。 它可以包含一个或多个JAR文件,以及WEB-INF或WEB-INF / classes / META-INF文件夹下的XML部署描述符文件。

EAR文件:EAR文件包含多个JAR和WAR文件,以及META-INF文件夹中的XML部署描述符。

XML部署描述符(如果存在)会覆盖代码级别注释。 对于给定的组件,避免在两个地方重复配置。

Maven提供了几个有用的插件来简化在开发生命周期中对EAP的打包和部署(这些插件都是widfly的,就觉定了war包默认后续会部署到EAP上)。

如果遵循Maven标准源代码布局,maven-war-plugin会从应用程序创建WAR文件。 maven-war-plugin可以在Maven pom.xml文件的<build>部分中声明:

<build>
<finalName>todo</finalName>
 <plugins>
     <plugin>
         <groupId>org.apache.maven.plugins</groupId>         
         <artifactId>maven-war-plugin</artifactId>
         <version>${version.war.plugin}</version>
         <extensions>false</extensions>
         <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
     </plugin>
 </plugins>
</build>

同样,maven-ear-plugin从应用程序源代码创建EAR文件。 它在Maven pom.xml文件的<build>部分中声明。 您需要使用<webModule>标记指示应该打包在EAR文件内的WAR文件:

<build>
<finalName>todo</finalName>
 <plugins>
     <plugin>
          <groupId>org.apache.maven.plugins</groupId>         
          <artifactId>maven-ear-plugin</artifactId>
          <version>${version.ear.plugin}</version>
          <configuration>
           <version>6</version>
           <defaultLibBundleDir>lib</defaultLibBundleDir>
           <modules>               
          <webModule>
                 <groupId>com.redhat.training</groupId>
                 <artifactId>todojee-web</artifactId>
                 <contextRoot>/todo-ear</contextRoot>
               </webModule>
           </modules>
           <fileNameMapping>no-version</fileNameMapping>
         </configuration>
     </plugin>
 </plugins>
</build>

可以使用Maven通过wildfly-maven插件将应用程序部署到JBoss EAP,该插件提供了部署和取消部署应用程序到EAP的功能。 它支持部署所有三种部署格式:JAR,WAR和EAR。 您可以在项目的Maven pom.xml文件中声明插件:

<plugin>
  <groupId>org.wildfly.plugins</groupId>
  <artifactId>wildfly-maven-plugin</artifactId>
  <version>${version.wildfly.maven.plugin}</version>
</plugin>

要将应用程序构建,打包并部署到EAP,请从项目根文件夹运行以下命令:

$ mvn clean package wildfly:deploy

要从EAP取消部署应用程序,请从项目根文件夹运行以下命令:

$ mvn wildfly:undeploy

九、实验验证:打包和部署一个J2EE应用

通过JBDS,导入一个已经存在的maven项目,并加载:

接下来,增加应用服务器:

选择启动EAP:

接下来,通过maven编译应用,并直接部署到EAP上:

应用部署完毕以后,通过浏览器可以进行访问:

部署成功!

我们在web上增加一条任务:Earn lots of money:

然后查看EAP的日志,可以看到增加任务的操作,并且把增加的内容通过调用JNDI写入到了后端数据库。

魏新宇

  • "大魏分享"运营者、红帽资深解决方案架构师
  • 专注开源云计算、容器及自动化运维在金融行业的推广
  • 拥有MBA、ITIL V3、Cobit5、C-STAR、TOGAF9.1(鉴定级)等管理认证。
  • 拥有红帽RHCE/RHCA、VMware VCP-DCV、VCP-DT、VCP-Network、VCP-Cloud、AIX、HPUX等技术认证。

原文发布于微信公众号 - 大魏分享(david-share)

原文发表时间:2018-06-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏散尽浮华

DNS之BIND使用小结(Forward转发)

之前详细介绍了DNS及其在linux下的部署过程,今天再说下DNS的BIND高级特性-forwarder转发功能。比如下面一个案例: 1)已经在测试环境下部署了...

1513
来自专栏数据库

数据恢复-SQL被注入攻击程序的应对策略

前几天某客户紧急求助我们,其Oracle数据库由于重启之后无法正常启动。最后通过数据库全备进行了一天一夜的恢复,最后仍然无法正常打开数据库。 alter dat...

1898
来自专栏数据订阅

数据订阅案例

我们会通过模拟从库向主库获取对应 binlog 内容进行分析,大概架构图如下,我们会通过解析 binlog ,按照订阅通道配置的库表进行分析,所以几乎对主库没有...

1343
来自专栏晓晨的专栏

IdentityServer Topics(5)- 使用第三方登录

773
来自专栏Rainbond开源「容器云平台」

Kubernetes容器网络接口(CNI) midonet网络插件的设计与实现

1307
来自专栏熊二哥

JMeter快速入门

今天的年会已过,仍然是空手而归,不过俺坚信能让生活稳定永远都是努力。由于隔壁组负责年会的抢红包项目,因而趁此机会把通过工具模拟高并发的知识补了补,通过和身边大师...

2205
来自专栏owent

atsf4g完整游戏工程示例

近期仍然在搭建完整的游戏服务器架构。基于atsf4g(asynchronously-tree server framework fo game)的完整解决方案终...

451
来自专栏xingoo, 一个梦想做发明家的程序员

Head插件——学习Elasticsearch的锋刃利器!

在学习Elasticsearch的过程中,必不可少需要通过一些工具查看es的运行状态以及数据。如果都是通过rest请求,未免太过麻烦,而且也不够人性化。 此...

2196
来自专栏Golang语言社区

golang微信支付服务端

一般来说,使用golang主要还是写服务端。所以本文主要讲golang在处理微信移动支付的服务端时的统一下单接口和支付回调接口,以及查询接口。 微信支付流程 下...

6137
来自专栏运维一切

mesos:Authentication timed out

引用:https://blog.csdn.net/mhfh611/article/details/9470599

722

扫码关注云+社区