Spring Web Application应用到OSGI环境 二

一、域模型
先从最底层开始,把域模型建立起来,创建一个Plug-in project -

org.phrancol.osgi.jpetstore.domain,不创建Activator,创建一个package - org.phrancol.osgi.jpetstore.domain,将src\org\springframework\samples\jpetstore\domain 里面的java文件copy进去(重构一下package的名字,java文件里的package自动就变了,不用改每个文件),在MANIFEST.MF里面把依赖包导入一下并export这个package
domain里面的logic,引用了dao,dao也引用了domain,会导致一个错误,于是将logic做为一个独立的bundle,就称为域逻辑吧

二、域逻辑
创建一个Plug-in project - org.phrancol.osgi.jpetstore.domain.logic,不创建Activator,创建一个同名package,将jpetstore\src\org\springframework\samples\jpetstore\domain\logic里面的java文件copy进去,在MANIFEST.MF里面把依赖包导入

三、DAO
该做dao部分了,创建一个 Plug-in project - org.phrancol.osgi.jpetstore.dao 并创建一个同名package,将jpetstore\src\org\springframework\samples\jpetstore\dao里面的东西全部copy进去,在MANIFEST.MF里面导入依赖包(有一些包需要导入成bundle,例如 spring-jdbc,spring-ibatis),启动看看,发现spring-ibatis和persistence没有启动,手动启动spring-ibatis,发现缺少ibatis,于是 New-> Other -> Plug-in from existing JAR archives ,导入ibatis,再启动,发现少 javax.transaction,于是用相同方法导入。

四、配置文件
 关于spring的配置文件,只有3个
petstore-servlet.xml - 用于mvc的,定义dispatch bean
applicationContext.xml - 用于域逻辑的
dataAccessContext-local.xml - 用于DAO的,定义了DataSource
(一)dataAccessContext-local.xml
1,将 jdbc.properties和sql-map-config.xml拷贝到META-INF目录里,sql-map-config.xml里面的资源路径可能需要修改一下,maps里面的模型的class属性也需要改一下
2,在META-INF目录中创建一个目录spring,将dataAccessContext-local.xml拷贝进去,将applicationContext.xml里面的加载jdbc.properties的bean移植过来,放在DataSource的上面
< bean  id ="propertyConfigurer"  class ="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
        
< property  name ="locations" >
            
< list >
                
< value > META-INF/jdbc.properties </ value >
            
</ list >
        
</ property >
    
</ bean >


再把dataAccessContext-local.xml里面的dao-bean->class属性值修改一下,再把sqlMapClient的configLocation的值修改成META-INF/sql-map-config.xml,例如
<!--  SqlMap setup for iBATIS Database Layer  -->
    
< bean  id ="sqlMapClient"  class ="org.springframework.orm.ibatis.SqlMapClientFactoryBean" >
        
< property  name ="configLocation"  value ="META-INF/sql-map-config.xml" />
        
< property  name ="dataSource"  ref ="dataSource" />
    
</ bean >


    
<!--  ========================= DAO DEFINITIONS: IBATIS IMPLEMENTATIONS =========================  -->

    
< bean  id ="accountDao"  class ="org.phrancol.sogi.jpetstore.dao.ibatis.SqlMapAccountDao" >
        
< property  name ="sqlMapClient"  ref ="sqlMapClient" />
    
</ bean >
3,启动,报错,找不到ibatis的某个类,报错信息如下
org.springframework.beans.BeanInstantiationException: Could not instantiate bean  class  [org.springframework.orm.ibatis.SqlMapClientFactoryBean]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
Caused by: java.lang.NoClassDefFoundError: com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
    at org.springframework.orm.ibatis.SqlMapClientFactoryBean.
class $(SqlMapClientFactoryBean.java: 72 )
看来是spring-ibatis找不到com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig,来看看spring-ibatis的MANIFEST.MF,Dependencies的Import Packages, 加上com.ibatis.sqlmap.engine.transaction.external,再启动,找不到DBCP,导入common-DBCP和common-pool,再启动,正常,SS一下,还是正常

(二)applicationContext.xml
1,在org.phrancol.osgi.jpetstore.domain.logic的META-INF目录中创建一个目录spring,将applicationContext.xml拷贝进去,并改名为 logic-context.xml,删除propertyConfigurer这个bean,因为它已经被移到了dataAccessContext-local.xml里面,将里面的bean的class属性修改一下,启动,发现缺少org.aspectj,导入一个,再启动,报错
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named  ' accountDao '  is defined
无法找到 accountDao,accountDao被定义在org.phrancol.osgi.jpetstore.dao里面了,于是现在需要使用spring-osgi 来进行跨bundle的引用了。
2,org.phrancol.osgi.jpetstore.dao/META-INF/spring目录中创建一个spring配置文件dataAccessContext-local-osgi.xml,使用<osgi:service>将accountDao和其他被引用的DAO注册成为OSGI Service
<? xml version="1.0" encoding="UTF-8" ?>
< beans  xmlns ="http://www.springframework.org/schema/beans"
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:osgi
="http://www.springframework.org/schema/osgi"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"
>
    
    
< osgi:service  id ="accountDaoOsgi"  ref ="accountDao"
        interface
="org.phrancol.osgi.jpetstore.dao.AccountDao" >
    
</ osgi:service >
    
    
< osgi:service  id ="categoryDaoOsgi"  ref ="categoryDao"
        interface
="org.phrancol.osgi.jpetstore.dao.CategoryDao" >
    
</ osgi:service >
    
    
< osgi:service  id ="productDaoOsgi"  ref ="productDao"
        interface
="org.phrancol.osgi.jpetstore.dao.ProductDao" >
    
</ osgi:service >
    
    
< osgi:service  id ="itemDaoOsgi"  ref ="itemDao"
        interface
="org.phrancol.osgi.jpetstore.dao.ItemDao" >
    
</ osgi:service >
    
    
< osgi:service  id ="orderDaoOsgi"  ref ="orderDao"
        interface
="org.phrancol.osgi.jpetstore.dao.OrderDao" >
    
</ osgi:service >
    
</ beans >

3,在org.phrancol.osgi.jpetstore.domain.logic/META-INF/spring 也创建一个spring配置文件logic-context-osgi.xml,使用<osgi:reference>获取服务
<? xml version="1.0" encoding="UTF-8" ?>
< beans  xmlns ="http://www.springframework.org/schema/beans"
    xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:osgi
="http://www.springframework.org/schema/osgi"
    xsi:schemaLocation
="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"
>

    
< osgi:reference  id ="accountDaoOsgi"  interface ="org.phrancol.osgi.jpetstore.dao.AccountDao" />

    
< osgi:reference  id ="categoryDaoOsgi"  interface ="org.phrancol.osgi.jpetstore.dao.CategoryDao" />

    
< osgi:reference  id ="productDaoOsgi"  interface ="org.phrancol.osgi.jpetstore.dao.ProductDao" />

    
< osgi:reference  id ="itemDaoOsgi"  interface ="org.phrancol.osgi.jpetstore.dao.ItemDao" />

    
< osgi:reference  id ="orderDaoOsgi"  interface ="org.phrancol.osgi.jpetstore.dao.OrderDao" />
    
</ beans >
将logic-context.xml里面的bean  petStore的属性引用修改一下
< bean  id ="petStore"  class ="org.phrancol.osgi.jpetstore.domain.logic.PetStoreImpl" >
        
< property  name ="accountDao"  ref ="accountDaoOsgi" />
        
< property  name ="categoryDao"  ref ="categoryDaoOsgi" />
        
< property  name ="productDao"  ref ="productDaoOsgi" />
        
< property  name ="itemDao"  ref ="itemDaoOsgi" />
        
< property  name ="orderDao"  ref ="orderDaoOsgi" />
    
</ bean >
再启动看看,还是报错
org.springframework.beans.factory.BeanCreationException: Error creating bean with name  ' txAdvice ' : Cannot resolve reference to bean  ' transactionManager '   while  setting bean property  ' transactionManager ' ; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named  ' transactionManager '  is defined
原来是transactionManager的问题,在DAO里面将transactionManager注册成osgi service,在domain.logic里面引用,然后给txAdvice加上 transaction-manager属性
< tx:advice  id ="txAdvice"  transaction-manager ="transactionManagerOsgi" >
        
< tx:attributes >
            
< tx:method  name ="insert*" />
            
< tx:method  name ="update*" />
            
< tx:method  name ="*"  read-only ="true" />
        
</ tx:attributes >
    
</ tx:advice >
OK,启动,正常了
 
(三)petstore-servlet.xml
最后到spring-mvc的配置文件了,在前面已经将这个配置文件拷贝到org.phrancol.osgi.jpetstore.springmvc/META-INF/dispatcher目录下了,并且做了一些修改,让DispatcherServlet加载用以显示首页
1,新建一个package org.phrancol.osgi.jpetstore.springmvc.controller,将jpetstore\src\org\springframework\samples\jpetstore\web\spring里面的java文件拷贝进去,将依赖包导入,然后在petstore-servlet.xml里面加上一个dispatch-bean,
< bean  name ="/shop/addItemToCart.do"  class ="org.phrancol.osgi.jpetstore.springmvc.controller.AddItemToCartController" >
        
< property  name ="petStore"  ref ="petStore" />
    
</ bean >
启动看看效果,报错
Caused by: java.lang.ClassNotFoundException: org.phrancol.osgi.jpetstore.springmvc.controller.AddItemToCartController
居然找不到这个类,来看看ClassLoader
Thread.currentThread().getContextClassLoader()  ->  org.eclipse.core.runtime.internal.adaptor.ContextFinder
Activator
' s ClassLoader -> org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader
原来如此,那就这样
Thread.currentThread().setContextClassLoader( this .getClass().getClassLoader())
其实这样也是可以的,但是为了不绕弯路,而且既然是Spring的配置文件,Spring-osgi也提供得有Bundle的ClassLoader -> org.springframework.osgi.context.support.BundleDelegatingClassLoader 交给Spring的ClassLoader吧
2,看一段代码 org.springframework.osgi.context.support.BundleContextAwareProcessor
public   boolean  postProcessAfterInstantiation(Object bean, String beanName)  throws  BeansException  {
        
if (bean instanceof BundleContextAware) {
            
if (this.bundleContext == null{
                
throw new IllegalStateException("Cannot satisfy BundleContextAware for bean '" +
                        beanName 
+ "' without BundleContext");
            }

            
if (logger.isDebugEnabled()) {
                logger.debug(
"Invoking setBundleContext on BundleContextAware bean '" + beanName + "'");
            }

            ((BundleContextAware) bean).setBundleContext(
this.bundleContext);
        }

        
return true;
    }

3,再来看看这个接口 org.springframework.osgi.context.BundleContextAware
Interface that enables beans to find the bundle context they are defined in. Note that in most circumstances there is no need  for  a bean to implement  this   interface
OK,那就写个BundleContextAware,然后配置成Bean就可以了

4,创建一个 Plug-in project   org.phrancol.osgi.jpetstore.util,并创建同名package,新建一个Interface HttpServiceRegister 用于注册Servlet或Resource,这个过程在方法 public void serviceRegister(BundleContext context);里进行,新建一个Class  BundleServiceRegister
public   class  BundleServiceRegister  implements  BundleContextAware  {
    
    
private HttpServiceRegister httpServiceRegister;
    
    
public BundleServiceRegister(HttpServiceRegister httpServiceRegister){
        
this.httpServiceRegister = httpServiceRegister;
    }


    
public void setBundleContext(BundleContext context) {
        
this.httpServiceRegister.serviceRegister(context);
    }

}

5,生成一个类org.phrancol.osgi.jpetstore.springmvc.SpringmvcHttpServiceRegister implements HttpServiceRegister
将Activator.start方法里的内容拷贝到SpringmvcHttpServiceRegister.serviceRegister方法里,删除Activator(MANIFEST.MF)

6,在org.phrancol.osgi.jpetstore.springmvc/META-INF/下建立一个目录spring,从别的地方copy一个bean配置文件过来,改名为logic-context.xml,加入如下配置
< beans >
    
< bean  id ="springHttpServiceRegister"
        class
="org.phrancol.osgi.jpetstore.util.BundleServiceRegister" >
        
< constructor-arg >
            
< bean  class ="org.phrancol.osgi.jpetstore.springmvc.SpringmvcHttpServiceRegister"   />
        
</ constructor-arg >
    
</ bean >
</ beans >
启动,报错,petstore-servlet.xml里面的bean petStore 找不到,这个bean被定义在org.phrancol.osgi.jpetstore.domain.logic里面,于是使用<osgi:service>和<osgi:reference>来获取
在logic-context-osgi.xml里面加上
< osgi:service  id ="petStoreOsgi"  ref ="petStore"
        interface
="org.phrancol.osgi.jpetstore.domain.logic.PetStoreFacade" >
    
</ osgi:service >
在springmvc-context.xml加入如下内容(注意namespaces)
     < osgi:reference  id ="petStoreOsgi"
        interface
="org.phrancol.osgi.jpetstore.domain.logic.PetStoreFacade"   />
修改一下petstore-servlet.xml
< property  name ="petStore"  ref ="petStore" />
改成
< property  name ="petStore"  ref ="petStoreOsgi" />
OK,这次应该没问题了,启动看看效果,还是报错
org.springframework.beans.factory.BeanCreationException: Error creating bean with name  ' /shop/addItemToCart.do '  defined in ServletContext resource [ / META - INF / dispatcher / petstore - servlet.xml]: Cannot resolve reference to bean  ' petStoreOsgi '   while  setting bean property  ' petStore ' ; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named  ' petStoreOsgi '  is defined
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 
' petStoreOsgi '  is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:
353 )
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedBeanDefinition(AbstractBeanFactory.java:
916 )
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:
243 )
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:
160 )
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:
261 )
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:
109 )
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:
1100 )

居然找不到petStoreOsgi这个bean......

 

 

 

 

你可能感兴趣的:(spring,bean,Web,ibatis,osgi)