Java 如何部署一个 webapp 并创建它的资源
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19530730/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to deploy a webapp and create its resources
提问by Michele Mariotti
before deploy "myapp.war" on glassfish 4 i have to
在 glassfish 4 上部署“myapp.war”之前,我必须
- create jdbc connection pool (/WEB-INF/glassfish-resources.xml ->
jdbc-connection-pool
does not work by itself... fine from asadmin) - create jdbc resource for pool (/WEB-INF/glassfish-resources.xml ->
jdbc-resource
same as above) - create auth-realm (nothing auto, using asadmin for now)
- create schema (peristence.xml ->
property javax.persistence.schema-generation.create-database-schemas
, but is bogus) - create tables (persistence.xml -> `create-tables', not perfect but at least it works)
- 创建 jdbc 连接池(/WEB-INF/glassfish-resources.xml ->
jdbc-connection-pool
本身不起作用... asadmin 很好) - 为池创建 jdbc 资源(/WEB-INF/glassfish-resources.xml ->
jdbc-resource
同上) - 创建 auth-realm(没有自动,现在使用 asadmin)
- 创建模式( peristence.xml ->
property javax.persistence.schema-generation.create-database-schemas
,但是是假的) - 创建表(persistence.xml -> `create-tables',不完美,但至少可以工作)
now i'm doing:
现在我在做:
- upload "myapp.war", "glassfish-resources.xml" on /tmp/install
asadmin add-resources ...
asadmin create-auth-realm ...
asadmin deploy ...
asadmin disable myapp ...
nano /.../glassfish/applications/myapp/WEB-INF/classes/META-INF/persistence.xml
- comment a few lines,
ctrl+o
,enter
,ctrl+x
,enter
asadmin enable myapp ...
rm -Rf /tmp/install
- 在 /tmp/install 上上传“myapp.war”、“glassfish-resources.xml”
asadmin add-resources ...
asadmin create-auth-realm ...
asadmin deploy ...
asadmin disable myapp ...
nano /.../glassfish/applications/myapp/WEB-INF/classes/META-INF/persistence.xml
- 注释几行,
ctrl+o
,enter
,ctrl+x
,enter
asadmin enable myapp ...
rm -Rf /tmp/install
and without other suggestion i'm planning to:
在没有其他建议的情况下,我打算:
- upload "myapp.war", "deploy.sh" on /tmp/install
chmod +x deploy.sh
./deploy.sh
- 在 /tmp/install 上上传“myapp.war”、“deploy.sh”
chmod +x deploy.sh
./deploy.sh
and the script will take care of everything. but i'd like to upload onlya war file via glassfish http console and obtain the same result.
脚本会处理一切。但我只想通过 glassfish http 控制台上传一个战争文件并获得相同的结果。
is there a way to have a class or script called beforecontextInitialized
?
有没有办法在之前调用一个类或脚本contextInitialized
?
how would you deploy this thing?
你会如何部署这个东西?
for completeness here are some additional info:
为了完整起见,这里有一些附加信息:
/myapp/WEB-INF/classes/META-INF/persistence.xml
/myapp/WEB-INF/classes/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="myapp" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/myapp</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/myapp"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="password"/>
<property name="javax.persistence.schema-generation.database.action" value="create"/>
<property name="javax.persistence.schema-generation.create-database-schemas" value="false"/>
<property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/>
<property name="javax.persistence.schema-generation.scripts.create-target" value="C:/tmp/myapp_create.ddl"/>
<property name="javax.persistence.schema-generation.scripts.drop-target" value="C:/tmp/myapp_drop.ddl"/>
<property name="eclipselink.deploy-on-startup" value="true"/>
<property name="eclipselink.target-database" value="MySQL"/>
<!-- <property name="eclipselink.ddl-generation" value="create-tables"/> -->
<!-- <property name="eclipselink.ddl-generation.output-mode" value="database"/> -->
<!-- <property name="eclipselink.create-ddl-jdbc-file-name" value="myapp.ddl"/> -->
<!-- <property name="eclipselink.logging.level" value="FINE" /> -->
<!-- <property name="eclipselink.logging.level.sql" value="FINE"/> -->
<!-- <property name="eclipselink.logging.parameters" value="true"/> -->
<!-- <property name="eclipselink.logging.logger" value="org.eclipse.persistence.logging.DefaultSessionLog"/> -->
</properties>
</persistence-unit>
</persistence>
/myapp/WEB-INF/glassfish-resources.xml
/myapp/WEB-INF/glassfish-resources.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="jdbc/myapp_pool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
<property name="serverName" value="localhost"/>
<property name="portNumber" value="3306"/>
<property name="databaseName" value="myapp"/>
<property name="User" value="root"/>
<property name="Password" value="password"/>
<property name="URL" value="jdbc:mysql://localhost:3306/myapp"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</jdbc-connection-pool>
<jdbc-resource enabled="true" jndi-name="jdbc/myapp" object-type="user" pool-name="jdbc/myapp_pool"/>
</resources>
while glassfish understands /myapp/.../persistence.xml (sometimes executing also CREATE SCHEMA myapp
, sometimes not, apparently random - but it's fine),
而 glassfish 理解 /myapp/.../persistence.xml (有时也执行CREATE SCHEMA myapp
,有时不是,显然是随机的 - 但它很好),
i definitely can't make glassfish read /myapp/WEB-INF/glassfish-resources.xml. it ignores this file.
我绝对不能让 glassfish 读取 /myapp/WEB-INF/glassfish-resources.xml。它忽略这个文件。
UPDATEglassfish reads the file but prefixes jndi names with java:app/
breaking other references. being aware of this thing i rewrite references with prefix and now it is working fine.
lastly, i noted that if glassfish-resources.xml
is inside META-INF
(instead of WEB-INF
) glassfish reads the file and it is also present in http ui under "applications > myapp > descriptors"
UPDATEglassfish 读取文件,但在 jndi 名称前加上java:app/
破坏其他引用的前缀。意识到这件事后,我用前缀重写了引用,现在它工作正常。最后,我注意到如果glassfish-resources.xml
在内部META-INF
(而不是WEB-INF
) glassfish 读取文件,并且它也存在于 http ui 中的“应用程序 > myapp > 描述符”下
采纳答案by Michele Mariotti
finally i found a solution:
最后我找到了一个解决方案:
database create/upgrade: in
ServletContextListener.contextInitialized
i use compile-time-generated ddl script to create database if not exists, or use liquibase to upgrade database if exists. no more persistence.xml usage for database generation.authentication realm deploy: i don't deploy or create any container-specific realm. in
ServletContextListener.contextInitialized
i register a custom JASPICimplementation, which is itself a JAAS login module wrapper. thanks to @ArjanTijms for this aricleand this answer
回答by NBW
You can configure application scoped resources for the jdbc-connection-pooland jdbc-resourceinside the glassfish-resources.xmland when you deploy your WAR file they will be created. When you undeploy your WAR they will go away. That solves the problem of manually adding them with asadmin. What I usually do it set it up manually using the GUI, then copy and paste the <jdbc-connection-pool>
and <jdbc-resource>
elements from the domain.xmlinto glassfish-resources.xmlthen I change the jndi-name to be application scoped, for example:
您可以在glassfish-resources.xml 中为jdbc-connection-pool和jdbc-resource配置应用程序范围的资源,当您部署 WAR 文件时,它们将被创建。当您取消部署 WAR 时,它们将消失。这解决了使用 asadmin 手动添加它们的问题。我通常使用 GUI 手动设置它,然后将domain.xml 中的<jdbc-connection-pool>
和<jdbc-resource>
元素复制并粘贴到glassfish-resources.xml 中,然后将 jndi-name 更改为应用程序范围,例如:
<jdbc-resource pool-name="MyAppPool" jndi-name="java:app/jdbc/my-app-pool"></jdbc-resource>
Then I make sure glassfish-resources.xmlis packaged into the appropriate place in the WAR file, namely in the WEB-INFfolder.
然后我确保glassfish-resources.xml被打包到 WAR 文件中的适当位置,即WEB-INF文件夹中。
From what I have read in the Oracle documentation for Glassfish 4 it does not appear that you can package the auth-realm configuration with the application like you can for the JDBC stuff. I have filed an enhancement request for this glassfish auth-realm packaging enhancementIt only appears that you can package the association to the realm in various deployment descriptors, see the "How to set a realm for an Application or Module" section of this guidefor details.
从我在 Glassfish 4 的 Oracle 文档中读到的内容来看,您似乎无法像处理 JDBC 一样将 auth-realm 配置与应用程序打包在一起。我已经提交了增强请求此GlassFish的验证领域的包装增强它只是看起来,你可以包装协会在各种部署描述符的境界,请参阅“如何设置一个域的应用程序或模块”这一部分指南为细节。
HACK Alert
黑客警报
Actually I just thought of something which is a bit of a hack but might work around this issue. You could create a simple web APP which includes your real applications WAR file in it (in a resource directory). This wrapper app would include a REST client (like Jersey client) which would make REST calls to the Glassfish administration REST API to see if the auth-realm is there and configured. If it is it would use the REST API to deploy the embedded WAR file. If it isn't it would use the REST API to create the auth-realm and then it would deploy the WAR.
其实我只是想到了一些有点黑客但可能会解决这个问题的东西。您可以创建一个简单的 Web APP,其中包含您的真实应用程序 WAR 文件(在资源目录中)。此包装器应用程序将包括一个 REST 客户端(如 Jersey 客户端),该客户端将对 Glassfish 管理 REST API 进行 REST 调用,以查看 auth-realm 是否存在并已配置。如果是,它将使用 REST API 来部署嵌入式 WAR 文件。如果不是,它将使用 REST API 创建 auth-realm,然后它会部署 WAR。
I'm not quite clear on the issues you are having with schema generation but that's all supported via the persistence.xml and works fine. If you want even more functionality in the way of automatic migration scripting then I would look at integrating a package like FlyAway
我不太清楚您在模式生成方面遇到的问题,但这一切都通过 persistence.xml 支持并且工作正常。如果你想要更多的自动迁移脚本功能,那么我会考虑集成一个像FlyAway这样的包
Here's an example of a glassfish-resources.xml file with app scoped resources which works for me under Glassfish 3.1.2. Some of the attributes you have I don't and I also don't use a JDBC JNDI naming style for the pool-name on the jdbc-resource.
这是一个带有应用范围资源的 glassfish-resources.xml 文件示例,它在 Glassfish 3.1.2 下对我有用。您拥有的一些属性我没有,我也不使用 JDBC JNDI 命名样式作为 jdbc-resource 上的 pool-name。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC
"-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN"
"http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
<jdbc-connection-pool validation-table-name="TABLEVALIDATION" allow-non-component-callers="true"
statement-cache-size="200" associate-with-thread="true" statement-timeout-in-seconds="300"
non-transactional-connections="true" connection-leak-reclaim="true"
lazy-connection-association="true" connection-creation-retry-attempts="12"
lazy-connection-enlistment="true" validate-atmost-once-period-in-seconds="120"
statement-leak-timeout-in-seconds="360"
datasource-classname="oracle.jdbc.pool.OracleDataSource" res-type="javax.sql.DataSource"
connection-leak-timeout-in-seconds="420" statement-leak-reclaim="true"
name="UnitTestPool" is-connection-validation-required="true">
<property name="DataSourceName" value="OracleDataSource"></property>
<property name="ImplicitCachingEnabled" value="false"></property>
<property name="NetworkProtocol" value="tcp"></property>
<property name="DatabaseName" value="unittestdb"></property>
<property name="LoginTimeout" value="0"></property>
<property name="Password" value="tester"></property>
<property name="URL" value="jdbc:oracle:thin:@testbed:1521:xe"></property>
<property name="User" value="testertester"></property>
<property name="PortNumber" value="1521"></property>
<property name="ExplicitCachingEnabled" value="false"></property>
<property name="dynamic-reconfiguration-wait-timeout-in-seconds" value="960"></property>
<property name="MaxStatements" value="0"></property>
</jdbc-connection-pool>
<jdbc-resource pool-name="UnitTestPool" jndi-name="java:app/jdbc/unittestdb-pool"></jdbc-resource>
</resources>