创建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=TRACE

log4j.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>

设置的插件为:

  1. maven-war-plugin,用于war打包时包含文件的设置;
  2. 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

osgi.bundles=com.springsource.slf4j.api.jar@start,com.springsource.slf4j.org.apache.commons.logging.jar@start,com.springsource.slf4j.log4j.jar,log4j.osgi.jar@start,com.springsource.org.aopalliance.jar@start,com.springsource.net.sf.cglib.jar@start,spring-aop.jar@start,spring-beans.jar@start,spring-context.jar@start,spring-context-support.jar@start,spring-core.jar@start,spring-web.jar@start,spring-webmvc.jar@start,servlet-api.osgi.jar@start,jsp-api.osgi.jar@start,commons-el.osgi.jar@start,jstl.osgi.jar@start,jasper.osgi.jar@start,mx4j.osgi.jar@start,catalina.osgi.jar@start,catalina.start.osgi.jar@start,spring-osgi-core.jar@start,spring-osgi-io.jar@start,spring-osgi-extender.jar@start,spring-osgi-web.jar@start,spring-osgi-web-extender.jar@start,../target/web_demo.war@start,logging-demo.jar

创建日志模块的日志属性文件

在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项目

通过浏览器访问:

http://localhost:8080/web-demo/

接下来

接下来可以:

  1. 利用spring-dm提供的osgi测试支持为web-demo做集成测试;
  2. 集成其他组件,比如hibernate/JPA等。

源代码下载

通过svn或者web访问:

http://easymorse.googlecode.com/svn/tags/multi-modules-demo_2.0.0/

或者本地下载:

[Download not found]
PDF格式打印機    发送文章为PDF   

这篇文章上的评论的 RSS feed TrackBack URI

Leave a Reply