随笔 - 1  文章 - 37  trackbacks - 0
<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

留言簿(16)

随笔分类

随笔档案

文章分类

文章档案

test

搜索

  •  

最新评论

关于本文
本文是之前写的Developing Equinox/Spring-osgi/Spring Framework Web Application系列的升级版,Tomcat-OSGi的基础Demo之一,主要演示传统web application到OSGi application的转换,由于是升级版,所以本文的侧重点不再是基础配置的演示。

一、准备工作

1,JDK 1.6
2,Eclipse 3.4-jee
3,Spring-framework-2.5.6
4,spring-osgi-1.2.0
5,   org.eclipse.equinox源码,可从 :pserver:anonymous@dev.eclipse.org:/cvsroot/rt  中获得

二、显示首页中的几个问题

1.  ClassNotFoundException: org.springframework.web.servlet.view.InternalResourceViewResolver

META-INF/dispatcher/petstore-servlet.xml中定义的bean:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        
<property name="prefix" value="/web/jsp/spring/"/>
        
<property name="suffix" value=".jsp"/>
    
</bean>

在之前的版本中,这里是没有问题的,可是在spring-osgi-1.2.0中,却会有这个问题,这是因为缺少一个
DynamicImport-Package: *

为何要使用动态引入?
因为无法在spring-beans中import定义的bean,因此如果不使用动态引入,那么spring-beans就无法load定义的bean,而下面统一使用spring-core中的ClassUtils.forName来查找bean class,是一个非常好的做法。

spring-beans中是这样load一个bean的
Class resolvedClass = ClassUtils.forName("org.springframework.web.servlet.view.InternalResourceViewResolver", loader);

Thread.currentThread().getContextClassLoader()中的ClassLoader是org.eclipse.core.runtime.internal.adaptor.ContextFinder,它是osgi framework的classloader,它通过查找类调用堆中距离本次loadClass调用最近的DefaultClassLoader(bundle的classloader)去加载一个类。
DefaultClassLoader中封装了ClassLoaderDelegate(BundleLoader)查找类的过程

spring-beans加载bean class的过程:
读取配置文件 -> 发现一个bean配置 -> 通过ClassUtils加载 -> 使用Thread.currentThread().getContextClassLoader()加载bean class
ContextFinder加载bean class的过程:
从类调用堆中找到距离最近DefaultClassLoader,使用ClassUtils的DefaultClassLoader来加载bean class -> 使用ClassUtils所在bundle的BundleLoader去查找一个类
BundleLoader加载bean class的过程在OSGi规范中有比较详细的介绍,这里主要看一下动态引入
private PackageSource findDynamicSource(String pkgName) {
        
if (isDynamicallyImported(pkgName)) {
            ExportPackageDescription exportPackage 
= bundle.getFramework().getAdaptor().getState().linkDynamicImport(proxy.getBundleDescription(), pkgName);
            
if (exportPackage != null{
                PackageSource source 
= createExportPackageSource(exportPackage, null);
                
synchronized (this{
                    
if (importedSources == null)
                        importedSources 
= new KeyedHashSet(false);
                }

                
synchronized (importedSources) {
                    importedSources.add(source);
                }

                
return source;
            }

        }

        
return null;
    }


现在,spring-bean是如何加载一个bean的过程就变得非常明了了,ClassUtils在spring-core中,当使用spring-core的BundleLoader去加载一个bean class时,如果没有动态引入,则会出现找不到class的情况。
很明显,spring-osgi-1.2.0中的spring-core并没有配置动态引入,在这个版本中或许是通过操作classloader来实现bean的加载,这个没有研究。

同理,对于数据库驱动找不到的问题,也可以这样来解决。


2. 找不到tld

index.jsp中包含了2个标签库,在上一个版本中,将其放入/web/WEB-INF目录中就可以正常显示,可是在新版本中却不行。

当一个对jsp的请求到达时,先将jsp生称java文件,之后进行编译。而生称java文件时,需要处理tld资源。
tld资源路径的处理是由TldLocationsCache来完成的,当它第一次初始化时,会在 "/WEB-INF/",classpath中的jar包,web.xml中查找tld文件并缓存起来。
private void init() throws JasperException {
        
if (initialized) return;
        
try {
            processWebDotXml();
            scanJars();
            processTldsInFileSystem(
"/WEB-INF/");
            initialized 
= true;
        }
 catch (Exception ex) {
            
throw new JasperException(Localizer.getMessage(
                    
"jsp.error.internal.tldinit", ex.getMessage()));
        }

    }

这里主要看一下为什么这个版本中直接将tld文件放入/web/WEB-INF目录中会提示找不到tld

processWebDotXml()方法是处理web.xml的
scanJars()是处理classpath资源
processTldsInFileSystem("/WEB-INF/"); 是查找web-inf目录中的tld (这个方法在equinox部分的实现上行不通)

在方法processTldsInFileSystem("/WEB-INF/")中使用的是当前Servlet的ServletContext.getResourcePaths()方法来获取web-inf目录中的tld资源,注册equinox-JspServlet的过程中,做了2层封装,ServletRegistration和org.eclipse.equinox.jsp.jasper.JspServlet,分别生成了2个ServletConfig和ServletContext,大概过程如下:

ProxyServlet:
//Effective registration of the servlet as defined HttpService#registerServlet()  
    synchronized void registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext context, Bundle bundle) throws ServletException, NamespaceException {
        checkAlias(alias);
        
if (servlet == null)
            
throw new IllegalArgumentException("Servlet cannot be null"); //$NON-NLS-1$

        ServletRegistration registration 
= new ServletRegistration(servlet, proxyContext, context, bundle, servlets);
        registration.checkServletRegistration();

        ServletContext wrappedServletContext 
= new ServletContextAdaptor(proxyContext, getServletContext(), context, AccessController.getContext());
        ServletConfig servletConfig 
= new ServletConfigImpl(servlet, initparams, wrappedServletContext);

        registration.init(servletConfig);
        registrations.put(alias, registration);
    }

equinox-JspServlet:
public void init(ServletConfig config) throws ServletException {
        ClassLoader original 
= Thread.currentThread().getContextClassLoader();
        
try {
            Thread.currentThread().setContextClassLoader(jspLoader);
            jspServlet.init(
new ServletConfigAdaptor(config));
        }
 finally {
            Thread.currentThread().setContextClassLoader(original);
        }

    }

那么processTldsInFileSystem("/WEB-INF/")方法中的ServletContext就是从equinox-JspServlet$ServletContextAdaptor开始的
public Set getResourcePaths(String name) {
            Set result 
= delegate.getResourcePaths(name);
            Enumeration e 
= bundle.findEntries(bundleResourcePath + name, nullfalse);
            
if (e != null{
                
if (result == null)
                    result 
= new HashSet();
                
while (e.hasMoreElements()) {
                    URL entryURL 
= (URL) e.nextElement();
                    result.add(entryURL.getFile().substring(bundleResourcePath.length()));
                }

            }

            
return result;
        }

代码中的bundleResourcePath,就是注册这个Servlet填写的alias——/web/jsp

现在,已经了解如何查找tld了,只要将/WEB-INF目录放入/web/jsp中就可以了或者注册servlet的时候这样写:
httpService.registerResources("/""/web"null);
httpService.registerServlet(
"/*.jsp"new JspServlet(context .getBundle(), "/web"), nullnull);

为何上一个版本可以呢?时间距离太远,也不太好找源码,所以没有研究这部份,我猜测应该是在scanJars()方法中,通过classloader的URLs遍历来获取的,

equinox在处理相同HttpContext的ServletContext时,只是将attributes共享,而并没有共享资源访问,在这个例子中,应该是将相同HttpContext中的资源遍历,在Tomcat-OSGi中,使用的是naming.DirContext去处理资源的查找。

3. SpringMVC中的Controller 的问题

在上一个版本中,对于无法找到Controller的问题,是通过BundleContextAware来解决的,因为它是在Spring-OSGi中完成,因此其本质就是修改ClassLoader来解决的。
而更好的解决办法其实是export controller所在的package,使用动态引入功能,因为Spring-bean都是通过Spring-core中的ClassUtils.forName来查找的。

4. DispatcherServlet中的URI-Bean与osgi-bean引用的问题

DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setContextConfigLocation(
"META-INF/dispatcher/petstore-servlet.xml");

DispatcherServlet读取配置文件中的bean,存放于DispatcherServlet的ApplicationContext的BeanFactory中,某个bean需要使用到OSGi的bean 引用时,例如:
<osgi:reference id="petStoreOsgi"
        interface
="org.extwind.osgi.demo.jpetstoreosgi.domain.logic.PetStoreFacade" />

<bean name="/shop/viewCategory.do"
        class
="org.extwind.osgi.demo.jpetstoreosgi.springmvc.controller.ViewCategoryController">
        
<property name="petStore" ref="petStoreOsgi" />
    
</bean>

可以看到/shop/viewCategory.do是一个bean,它被保存在DispatcherServlet的ApplicationContext中,
osgi bean引用petStoreOsgi是存放在bundle的ApplicationContext中,这2个ApplicationContext并没有关联,因此无法找到。

这个两个ApplicationContext的创建顺序是这样的:
1. 程序中注册DispatcherServlet后,它被初始化时创建ApplicationContext,加载contextConfigLocation中定义的bean
2. Spring-OSGi当监听到bundle started的事件时,为该bundle创建ApplicationContext,加载bundle中/META-INF/spring/*.xml中定义的bean

因此,这个问题的解决办法就是,让DispatcherServlet的ApplicationContext在bundle的ApplicationContext之后创建,并设置成parent-child关系

实际上这个问题应该是由mvc框架去考虑的,在Spring-OSGi的文档中有解决方法,它是通过OsgiBundleXmlWebApplicationContext来实现的,也就是说它无法在本例中使用,因为当DispatcherServlet被初始化时,使用的Equinox的ServletConfig。

  > 如何让bundle的ApplicationContext成为DispatcherServlet的ApplicationContext的parent?
     在DispatcherServlet的ApplicationContext在创建时的部分代码如下:

FrameworkServlet.java
/**
     * Initialize and publish the WebApplicationContext for this servlet.
     * <p>Delegates to {
@link #createWebApplicationContext} for actual creation
     * of the context. Can be overridden in subclasses.
     * 
@return the WebApplicationContext instance
     * 
@throws BeansException if the context couldn't be initialized
     * 
@see #setContextClass
     * 
@see #setContextConfigLocation
     
*/

    
protected WebApplicationContext initWebApplicationContext() throws BeansException {
        WebApplicationContext wac 
= findWebApplicationContext();
        
if (wac == null{
            
// No fixed context defined for this servlet - create a local one.
            WebApplicationContext parent =
                    WebApplicationContextUtils.getWebApplicationContext(getServletContext());
            wac 
= createWebApplicationContext(parent);
        }


WebApplicationContextUtils.java
/**
     * Find the root WebApplicationContext for this web application, which is
     * typically loaded via {
@link org.springframework.web.context.ContextLoaderListener} or
     * {
@link org.springframework.web.context.ContextLoaderServlet}.
     * <p>Will rethrow an exception that happened on root context startup,
     * to differentiate between a failed context startup and no context at all.
     * 
@param sc ServletContext to find the web application context for
     * 
@return the root WebApplicationContext for this web app, or <code>null</code> if none
     * 
@see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
     
*/

    
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
        
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    }

      可以看到,使用的是ServletContext的属性来存放ApplicationContext,因此在ApplicationContextAware.setApplicationContext(ApplicationContext bundleApplicationContext)中,可以通过下面的代码来设置:
    
HttpServlet tmpHttpServlet = new HttpServlet() {
            
public void init(ServletConfig config) {
                
// config.getServletContext().setAttribute(OsgiBundleXmlWebApplicationContext.BUNDLE_CONTEXT_ATTRIBUTE,
                
// bundleContext);
                OsgiBundleXmlWebApplicationContext webApplicationContext = new OsgiBundleXmlWebApplicationContext() {
                    
protected String[] getDefaultConfigLocations() {
                        
return new String[0];
                    }

                }
;
                webApplicationContext.setParent(applicationContext);
                webApplicationContext.setServletContext(config.getServletContext());
                webApplicationContext.refresh();

                config.getServletContext().setAttribute(
                        WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
                        webApplicationContext);
            }

        }
;
        httpService.registerServlet(
"/init-context-loader-petsore-web", tmpHttpServlet, null,
                httpContext);

    让tmpHttpServlet和DispatcherServlet具有相同的HttpContext,那么DispatcherServlet就可以得到parent-ApplicationContext了。


    >如何让DispatcherServlet的ApplicationContext在bundle的ApplicationContext之后创建?

按照上一个版本中的方法,使用spring中的ApplicationContextAware接口,在这个接口的setParentApplicationContext方法之后,进行资源注册。
这里需要注意的是在bundle停止时注销注册的资源


以上几点基本就是在新版中遇到的问题。

Demo下载: http://extwind.googlecode.com/svn/JPetStoreOSGi_Workspace.rar

如何使用这个Demo:
建议新建一个workspace,java编译器需要6.0版本
将所有的bundles导入后,需要再将 org.extwind.osgi.demo.jpetstoreosgi.launcher 导入
本例中不包含DB数据,因此还需要准备Spring 2.5.6中的jpetstore
运行 spring-framework-2.5.6\samples\jpetstore\db\hsqldb\server.bat
在Eclipse中运行 org.extwind.osgi.demo.jpetstoreosgi.launcher.Launcher
访问首页地址:http://localhost/shop/index.do

-----------------------------------------------------------------------------------------------------------

稍后将介绍如何在Tomcat-OSGi中使用JPetStoreOSGi
posted on 2009-04-19 03:31 Phrancol Yang 阅读(4475) 评论(6)  编辑  收藏 所属分类: OSGI

FeedBack:
# re: Tomcat-OSGi Demo: JPetStoreOSGi(Spring-osgi 1.2.0) [未登录] 2009-06-05 17:46 tiger
楼主,Demo无法下载啊  回复  更多评论
  
# re: Tomcat-OSGi Demo: JPetStoreOSGi(Spring-osgi 1.2.0)  2009-06-05 19:39 Phrancol Yang
@tiger
已更新链接  回复  更多评论
  
# re: Tomcat-OSGi Demo: JPetStoreOSGi(Spring-osgi 1.2.0)  2009-06-17 15:15 梦醒
为什么会出现下面异常。。。。。。。。。。。。。。。。。。。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManagerOsgi': Invocation of init method failed; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.jdbc.datasource.DataSourceTransactionManager] for bean with name 'transactionManager' defined in URL [bundleentry://122/META-INF/spring/dataaccessContext.xml]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: org.springframework.jdbc.datasource.DataSourceTransactionManager not found from bundle [Dataaccess Plug-in (com.futuresoftware.jpetstore.dataaccess)]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:423)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext.access$1600(AbstractDelegatedExecutionApplicationContext.java:69)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext$4.run(AbstractDelegatedExecutionApplicationContext.java:355)
at org.springframework.osgi.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85)
at org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext.completeRefresh(AbstractDelegatedExecutionApplicationContext.java:320)
at org.springframework.osgi.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor$CompleteRefreshTask.run(DependencyWaiterApplicationContextExecutor.java:136)
at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.jdbc.datasource.DataSourceTransactionManager] for bean with name 'transactionManager' defined in URL [bundleentry://122/META-INF/spring/dataaccessContext.xml]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: org.springframework.jdbc.datasource.DataSourceTransactionManager not found from bundle [Dataaccess Plug-in (com.futuresoftware.jpetstore.dataaccess)]
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1144)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractBeanFactory.getType(AbstractBeanFactory.java:487)
at org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean.afterPropertiesSet(OsgiServiceFactoryBean.java:171)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
... 17 more  回复  更多评论
  
# re: Tomcat-OSGi Demo: JPetStoreOSGi(Spring-osgi 1.2.0)  2009-07-01 23:03 Phrancol Yang
@梦醒

java.lang.NoClassDefFoundError: org.springframework.jdbc.datasource.DataSourceTransactionManager not found from bundle [Dataaccess Plug-in (com.futuresoftware.jpetstore.dataaccess)]

在你的bundle中import这个package: org.springframework.jdbc.datasource  回复  更多评论
  
# re: Tomcat-OSGi Demo: JPetStoreOSGi(Spring-osgi 1.2.0)  2009-07-08 14:11 梦醒
JSTL.jar中的javax.servlet.jsp.jstl.core包全部也引入了,为什么在访问页面时还会出现下面错误,希望能加我的QQ给说一下:8495138 谢谢

org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:924)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:596)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at org.eclipse.equinox.http.servlet.internal.ServletRegistration.handleRequest(ServletRegistration.java:90)
at org.eclipse.equinox.http.servlet.internal.ProxyServlet.processAlias(ProxyServlet.java:111)
at org.eclipse.equinox.http.servlet.internal.ProxyServlet.service(ProxyServlet.java:75)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at org.eclipse.equinox.http.jetty.internal.HttpServerManager$InternalHttpServiceServlet.service(HttpServerManager.java:269)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428)
at org.mortbay.jetty.servlet.ServletHandler.dispatch(ServletHandler.java:677)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:568)
at org.mortbay.http.HttpContext.handle(HttpContext.java:1530)
at org.mortbay.http.HttpContext.handle(HttpContext.java:1482)
at org.mortbay.http.HttpServer.service(HttpServer.java:909)
at org.mortbay.http.HttpConnection.service(HttpConnection.java:820)
at org.mortbay.http.HttpConnection.handleNext(HttpConnection.java:986)
at org.mortbay.http.HttpConnection.handle(HttpConnection.java:837)
at org.mortbay.http.SocketListener.handleConnection(SocketListener.java:245)
at org.mortbay.util.ThreadedServer.handle(ThreadedServer.java:357)
at org.mortbay.util.ThreadPool$PoolThread.run(ThreadPool.java:534)
Caused by: java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config
at org.springframework.web.servlet.support.JstlUtils.exposeLocalizationContext(JstlUtils.java:97)
at org.springframework.web.servlet.view.JstlView.exposeHelpers(JstlView.java:133)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:257)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1183)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:902)
... 22 more
Caused by: java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:489)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:405)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:393)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
... 28 more
12:02:32,883 DEBUG org.springframework.web.context.support.XmlWebApplicationContext:272 - Publishing event in context [org.springframework.web.context.support.XmlWebApplicationContext@834cfb]: ServletRequestHandledEvent: url=[/shop/index.do]; client=[127.0.0.1]; method=[GET]; servlet=[petstore]; session=[null]; user=[null]; time=[204ms]; status=[failed: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config]
12:02:32,883 DEBUG com.futuresoftware.usap.jpetstore.springmvc.DefaultHttpServiceRegister$1$1:272 - Publishing event in context [com.futuresoftware.usap.jpetstore.springmvc.DefaultHttpServiceRegister$1$1@8fcc7b]: ServletRequestHandledEvent: url=[/shop/index.do]; client=[127.0.0.1]; method=[GET]; servlet=[petstore]; session=[null]; user=[null]; time=[204ms]; status=[failed: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config]
12:02:32,883 DEBUG org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext:272 - Publishing event in context [org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext@62610b]: ServletRequestHandledEvent: url=[/shop/index.do]; client=[127.0.0.1]; method=[GET]; servlet=[petstore]; session=[null]; user=[null]; time=[204ms]; status=[failed: org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config]
  回复  更多评论
  
# re: Tomcat-OSGi Demo: JPetStoreOSGi(Spring-osgi 1.2.0)  2009-09-27 17:35 梦醒
@Phrancol Yang
有时,并不是加包可以解决的,即使加了,还是那样。。。我感觉是类加载的问题。。。。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: