vaadin6/vaadin7整合OSGi成功

备注一下,本人从07年开始一直做OSGi的应用商业开发,我整合过很多的框架,vaadin也不例外,整合成功了。其实也没那么难,掌握的技巧是classload问题。

add-on里面好像也有人做了一个整合,我看了一下,能运行起来,但我感觉不适合商用,我建议大家不要使用那个。

本人只在Equinox下测试,使用Eclipse JAVA EE作为开发环境,其他的环境理论上是可行的,但是我没有太多精力去弄。
下面就重点说说我的整合思路:

  1. 定制OSGiTarget,这个很关键,关系到项目成败;实际上,整合web程序最难的也就是OSGiTarget,如果论坛里有人整合不起来,本人到愿意贡献一个。
    我使用的是jetty7或者jetty8,加上spring dm,过程我就不细说,反正就是到eclipse官方网站下载jetty即可。
    另外,这种整合方式跟vaadin版本无关,我在vaadin6整合成功,我相信任何版本的vaadin都能成功,只要你只把它当成一个正常的web程序即可。最新版本的osgi规范(R4)是支持的。
  2. 明确好web程序的整合方式。从其配置来看,是每个请求都生成了一个servlet的实例,配置的是App的class对象,就意味着web程序是不能声明为osgi服务,也不能直接注入osgi服务的,只能通过ServletContext来查找osgi的服务。
    差不多可以这么理解,web容器位于osgi容器之上,两者关联的唯一纽带就是ServletContext。这样做的好处就是osgi管理的bundle负责核心业务服务,web只负责对外界面,就意外着你的界面可以使用jsf、restlet+模板引起来实现。
  3. classload问题解决。vaadin需要加载其他bundle的class,如何实现加载任何程序的class呢?这就用到了Dynamic-Import: * 这个声明了,有了这个声明就可以动态引入任何东西。官方提供的vaadin.jar是缺少这个声明的,需要我们手工加入这个,加入方法也简单,使用rar打开,拖出到桌面,记事本修改,然后拖进去,重新压缩即可。
    增加了Dynamic-Import:* 只是解决了vaadin方面的classload问题,如果加载的App没有对外export这些App的class,还是会出现ClassNotFound的问题,所以还需要我们把做的app的bundle相关classexport出去—我直接export所有class,反正也是自己用,没有任何安全问题。

要说的也就这么多,最后建议大家使用spring dm来暴露和引入osgi服务。

可以共享给我一份吗, QQ575940574, 邮箱575940574@qq.com

我补充一下,如果用了推送,启动atmosphere的过程中会需要扫描jar包中的类,但OSGi中的jar包
加载进URLClassLoader并非都是file://xxx的URL,因此需要对其中class文件扫描的部分进行完善。
我修改了org.atmosphere.util.annotation.AnnotationDetector类的detect方法,使其支持URL为
bundle://或platfomr://开头的URLClassLoader,否则atmosphere自带的那些filter都无法自动启动。

代码如下,我修改增加的是29到40行。

    public final void detect(final String... packageNames) throws IOException
    {
        final String pkgNameFilter = new String[packageNames.length]
;
        for (int i = 0; i < pkgNameFilter.length; ++i)
        {
            pkgNameFilter[i]
 = packageNames[i]
.replace('.', '/');
            if (!pkgNameFilter[i]
.endsWith("/"))
            {
                pkgNameFilter[i]
 = pkgNameFilter[i]
.concat("/");
            }

        }
        final Set<File> files = new HashSet<File>();
        final Set<InputStream> streams = new HashSet<InputStream>();

        for (final String packageName : pkgNameFilter)
        {
            final ClassLoader loader = Thread.currentThread()
                    .getContextClassLoader();
            final Enumeration<URL> resourceEnum = loader
                    .getResources(packageName);
            while (resourceEnum.hasMoreElements())
            {
                final URL url = resourceEnum.nextElement();
                // Handle JBoss VFS URL's which look like (example package 'nl.dvelop'):
                // vfs:/foo/bar/website.war/WEB-INF/classes/nl/dvelop/
                // vfs:/foo/bar/website.war/WEB-INF/lib/dwebcore-0.0.1.jar/nl/dvelop/
                // On JBoss 5.1, the protocol of VFS URL is vfsfile, make it work on JBoss 5.1
                if (url.getProtocol().startsWith("bundle")
                        || url.getProtocol().startsWith("platform"))
                {
                    URL fileUrl = FileLocator.toFileURL(url);
                    final File dir = toFile(fileUrl);
                    if (dir.isDirectory())
                    {
                        files.add(dir);
                        if (DEBUG)
                            print("Add directory: '%s'", dir);
                    }
                } else if ("file".equals(url.getProtocol())
                        || "vfs".equals(url.getProtocol())
                        || "vfsfile".equals(url.getProtocol()))
                {
                    final File dir = toFile(url);
                    if (dir.isDirectory())
                    {
                        files.add(dir);
                        if (DEBUG)
                            print("Add directory: '%s'", dir);
                    }
                } else if (isRunningJavaWebStart())
                {
                    try
                    {
                        webstart((JarURLConnection) url.openConnection(),
                                packageName, streams);
                    } catch (ClassCastException cce)
                    {
                        throw new AssertionError("Not a File: "
                                + url.toExternalForm());
                    }
                } else
                {
                    // Resource in Jar File
                    File jarFile;

                    try
                    {
                        jarFile = toFile(((JarURLConnection) url
                                .openConnection()).getJarFileURL());
                    } catch (ClassCastException cce)
                    {
                        try
                        {
                            // Weblogic crap
                            String u = url.toExternalForm();
                            if (u.startsWith("zip:"))
                            {
                                u = u.substring(4);
                                if (!u.startsWith("file:"))
                                {
                                    u = "file:" + u;
                                }
                                u = u.substring(0, u.indexOf("!"));
                            }
                            jarFile = toFile(new URL(u));
                        } catch (Exception ex)
                        {
                            throw new AssertionError("Not a File: "
                                    + url.toExternalForm());
                        }
                    }
                    if (jarFile.isFile())
                    {
                        files.add(jarFile);
                        if (DEBUG)
                            print("Add jar file: '%s'", jarFile);
                    } else
                    {
                        throw new AssertionError("Not a File: " + jarFile);
                    }
                }
            }
        }

        if (!files.isEmpty())
        {
            detect(new ClassFileIterator(files.toArray(new File[files.size()]
),
                    pkgNameFilter));
        } else if (!streams.isEmpty())
        {
            detect(new ClassFileIterator(
                    streams.toArray(new InputStream[streams.size()]
),
                    pkgNameFilter));
        }
    }
[/i]
[/i]
[/i]
[/i]
[/i]

楼主可否将demo工程发一下,好学习一下,308637147@qq.com 谢谢