创建spring-dm和maven驱动的简单webapp
在osgi环境下运行webapp是很吸引人的特性。它提供了动态部署组件的特性,包括对组件的安装、更新和卸载等;组件的粒度可以小于war这样的构建单位,使组件复用程度得到提高(比如多个webapp可以共享一个hibernate相关的jar文件)。
不过,直接使用比如eclipse的equinox(或者其他osgi框架的实现)和相关的http service bundle创建动态的webapp还是比较麻烦的,spring-dm提供了对osgi开发的简化。
手工使用spring提供的bundle是可以在比如eclipse环境下创建一个基于osgi的开发环境的,比如spring-dm开发简单的web绑定就是实现一个最简单的webapp的步骤,但是,这个过程开发效率还是比较低的。
借助maven,可以使开发进程进一步提高效率。以下以创建支持eclipse的多模块maven项目中示例为基础进一步演化,集成spring-dm。
为web-demo模块增加log4j的配置文件
创建src/main/resources目录,在该目录下创建log4j.properties文件,内容如下:
log4j.rootCategory=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout.ConversionPattern=%t %p [%c{2}] – %m%n
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.threshold=TRACElog4j.logger.org.springframework.osgi=INFO
#log4j.logger.org.springframework=TRACE
为web-demo模块增加osgi清单文件
osgi的清单文件即java的清单文件,只是在该文件中增加osgi自定义的header。在src/main/resources目录下创建META-INF目录,该目录下创建MANIFEST.MF文件,内容为:
Web-ContextPath: web-demo
Bundle-ManifestVersion: 2
Bundle-Name: Simple OSGi War
Bundle-SymbolicName: com.easymorse.marshal.webdemo
Bundle-ClassPath: WEB-INF/classes
Import-Package: javax.servlet;version="2.4.0",
javax.servlet.http;version="2.4.0",
javax.servlet.resources;version="2.0.0",
javax.servlet.jsp;version="2.0.0",
javax.servlet.jsp.jstl.core;version="1.1.2",
javax.servlet.jsp.jstl.fmt;version="1.1.2",
javax.servlet.jsp.jstl.tlv;version="1.1.2",
org.apache.taglibs.standard.resources;version="1.1.2",
org.apache.taglibs.standard.tag.common.core;version="1.1.2",
org.apache.taglibs.standard.tag.rt.core;version="1.1.2",
org.apache.taglibs.standard.tei;version="1.1.2",
org.apache.taglibs.standard.tlv;version="1.1.2"
这个文件很关键,osgi通过该文件识别将来构建的war为bundle。
为web-demo模块增加依赖类库
pom.xml文件中增加如下依赖类库:
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>servlet-api.osgi</artifactId>
<version>2.5-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>jsp-api.osgi</artifactId>
<version>2.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5.5</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>2.5.5</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>spring-osgi-test</artifactId>
<version>1.1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>com.springsource.junit</artifactId>
<version>3.8.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>mx4j.osgi</artifactId>
<version>3.0.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.cglib</groupId>
<artifactId>com.springsource.net.sf.cglib</artifactId>
<version>2.1.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>jasper.osgi</artifactId>
<version>5.5.23-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>commons-el.osgi</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>jstl.osgi</artifactId>
<version>1.1.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>catalina.osgi</artifactId>
<version>5.5.23-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>catalina.start.osgi</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>spring-osgi-web</artifactId>
<version>1.1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>spring-osgi-web-extender</artifactId>
<version>1.1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>spring-osgi-extender</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.aopalliance</groupId>
<artifactId>com.springsource.org.aopalliance</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>2.5.5</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>aopalliance</artifactId>
<groupId>aopalliance</groupId>
</exclusion>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>2.5.5</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>aopalliance</artifactId>
<groupId>aopalliance</groupId>
</exclusion>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>easymock</groupId>
<artifactId>easymock</artifactId>
<version>1.2_Java1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>com.springsource.slf4j.org.apache.commons.logging</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>com.springsource.slf4j.api</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>com.springsource.slf4j.log4j</artifactId>
<version>1.5.0</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>com.springsource.org.apache.log4j</artifactId>
<groupId>org.apache.log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>log4j.osgi</artifactId>
<version>1.2.15-SNAPSHOT</version>
<scope>test</scope>
</dependency>
为web-demo模块增加构建扩展
在pom.xml文件build节点内部增加:
<extensions>
<extension>
<groupId>org.springframework.aws</groupId>
<artifactId>spring-aws-maven</artifactId>
<version>1.2.3</version>
</extension>
</extensions>
spring针对maven的插件,用于通过amazon s3作为仓库的库文件下载。
为web-demo模块增加资源的设置
还是在pom文件的build节点内部:
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>META-INF/*</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/java</directory>
</resource>
</resources>
作用是设置哪些目录下的是资源文件。
为web-demo模块增加插件支持和配置
在pom文件的plugins节点内部:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceExcludes>WEB-INF/lib/*</warSourceExcludes>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin><plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>META-INF</directory>
<includes>
<include>MANIFEST.MF</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
设置的插件为:
- maven-war-plugin,用于war打包时包含文件的设置;
- maven-clean-plugin,清除临时文件时的设置。
为web-demo模块增加equinox依赖
这个依赖没有放在上面的dependency中,是因为equinox只是osgi框架的一种,通过profile方式可以灵活更换为其他osgi实现,比如felix。在profiles节点内部:
<profile>
<id>equinox</id>
<dependencies>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi</artifactId>
<version>${equinox.ver}</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<osgi.test.platform>org.springframework.osgi.test.platform.EquinoxPlatform</osgi.test.platform>
<log4j.ignoreTCL>true</log4j.ignoreTCL>
</properties>
</profile>
为web-demo模块配置maven-dependency-plugin
maven-dependency-plugin插件也配置在profile中,这样便于灵活决定是否执行,这个配置将会复制所有项目依赖的jar文件到web-demo/libs目录下。
<profile>
<id>dependencies</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>libs</outputDirectory>
<excludeTransitive>false</excludeTransitive>
<stripVersion>true</stripVersion>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
增加repository的配置信息
默认maven只使用官方repository,osgi封装成bundle的很多jar需要第三方的repository,加入以下repository可保证所有依赖包都能正常下载使用。
<repository>
<id>eclipse-repository</id>
<name>Eclipse Repository</name>
<url>http://repo1.maven.org/eclipse/</url>
</repository><repository>
<id>com.springsource.repository.bundles.external</id>
<name>SpringSource Enterprise Bundle Repository – External Bundle Releases</name>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository><repository>
<id>com.springsource.repository.bundles.release</id>
<name>SpringSource Enterprise Bundle Repository – SpringSource Bundle Releases</name>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository><repository>
<id>spring-release</id>
<name>Spring Portfolio Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
<repository>
<id>spring-external</id>
<name>Spring Portfolio External Repository</name>
<url>http://maven.springframework.org/external</url>
</repository>
<repository>
<id>spring-milestone</id>
<name>Spring Portfolio Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository><repository>
<id>spring-ext</id>
<name>Spring External Dependencies Repository</name>
<url>
http://springframework.svn.sourceforge.net/svnroot/springframework/repos/repo-ext/
</url>
</repository><!– used when building against Spring snapshots –>
<repository>
<id>spring-snapshot</id>
<name>Spring Portfolio Milestone Repository</name>
<url>http://maven.springframework.org/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository><repository>
<id>i21-s3-osgi-repo</id>
<name>i21 osgi artifacts repo</name>
<snapshots>
<enabled>true</enabled>
</snapshots>
<url>http://maven.springframework.org/osgi</url>
</repository>
这部分代码应复制到总项目pom.xml的repositories节点下面。各个子模块通过继承可以使用到这些repository。
创建osgi需要的启动文件config.ini
在web-demo项目中创建libs/configuration目录,在该目录下创建config.ini文件:
eclipse.ignoreApp=true
osgi.noShutdown=true
osgi.console=
osgi.clean=true
创建日志模块的日志属性文件
在logging-demo项目增加src/main/resources目录,在该目录下创建log4j.properties文件:
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout.ConversionPattern=%t %p [%c{2}] – %m%n
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.threshold=TRACE#log4j.logger.org.springframework.osgi=TRACE
#log4j.logger.org.apache.catalina=INFO
创建日志模块的osgi清单文件
创建src/main/resources/META-INF目录,在该目录下创建MANIFEST.MF文件:
Bundle-ManifestVersion: 2
Bundle-Name: Log4j configuration bundle
Bundle-SymbolicName: com.easymorse.marshal.webdemo.logging.cfg
Fragment-Host: org.springframework.osgi.log4j.osgi
日志模块pom文件的修改
日志模块将打包为jar文件,其中包含清单文件和日志属性文件,需要设置pom文件中的jar打包插件,在pom文件中增加:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>META-INF/*</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>
在web-demo项目中编写web页面供测试
编写一个静态页面index.html:
<html>
<body>
<h2>Hello World!</h2>
<p><%="JSP test success!"%></p>
<p><a href="helloworld">Servlet test</></p>
<p><a href="jstl.jsp">JSTL test</></p>
</body>
</html>
编写一个Servlet:
package com.easymorse.marshal.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class HelloOsgiWorldServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");ServletOutputStream out = resp.getOutputStream();
out.println("<html>");
out.println("<head><title>Hello Osgi World</title></head>");
out.println("<body>");
out.println("<h1>Hello OSGi World</h1>");
out.println("</body></html>");
}
}
在web.xml文件中配置该servlet:
<servlet>
<servlet-name>HelloOsgiWorldServlet</servlet-name>
<servlet-class>
com.easymorse.marshal.servlet.HelloOsgiWorldServlet
</servlet-class>
</servlet><servlet-mapping>
<servlet-name>HelloOsgiWorldServlet</servlet-name>
<url-pattern>/helloworld</url-pattern>
</servlet-mapping>
编写一个测试jstl的页面jstl.jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:out value="jstl ok."/>
maven构建
在根项目目录下执行:
mvn install
在web-demo项目目录下执行:
mvn -P dependencies,equinox clean package
启动web项目
在web-demo项目目录下执行:
java -jar libs\org.eclipse.osgi.jar
访问web项目
通过浏览器访问:
接下来
接下来可以:
- 利用spring-dm提供的osgi测试支持为web-demo做集成测试;
- 集成其他组件,比如hibernate/JPA等。
源代码下载
通过svn或者web访问:
http://easymorse.googlecode.com/svn/tags/multi-modules-demo_2.0.0/
或者本地下载:
[Download not found]这篇文章上的评论的 RSS feed TrackBack URI