【问题标题】:How to build and wire Spring database dependency .JAR project for use with multiple .WAR projects?如何构建和连接 Spring 数据库依赖项 .JAR 项目以用于多个 .WAR 项目?
【发布时间】:2014-04-04 19:53:07
【问题描述】:

我正在构建一套 Web 服务,它们都访问同一个数据库,但使用不同的凭据。因此,为了模块化数据库代码,我将其从每个 Web 应用程序 .WAR 文件中移出,并为数据库调用其自己的 .JAR 文件。因此,如果 WebApp1 和 WebApp2 使用 getAllColumnsFromTable1 MyBatis 调用,我不必在两个项目中定义相同的映射器和域对象。这样,如果 Table1 发生更改,我只需在一个地方更改 MyBatis 代码,并且复制和粘贴错误更少。

WebApp1 applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

  <context:annotation-config />

  <context:component-scan base-package="com.example.webapp1.service" />
  <context:component-scan base-package="com.example.webapp1.controller" />

  <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:/example/ds/WebApp1DS" />
  </bean>

  <bean id="databaseConnector" class="com.example.databaseconnector.connector"
    <property name="dataSource" ref="dataSource" />
  </bean>
</beans>

所以我想传递给数据库连接器的 .JAR 文件只是 .WAR 正在使用的数据源。

WebApp1 pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>WebApp1</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>3.2.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>databaseconnector</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>

然后在 .WAR 中的一项服务中有这样的东西

WebApp1 Service.java:

package com.example.webapp1.service;

import com.example.databaseconnector.domain.TableSearchResult;
import com.example.databaseconnector.persistence.TableMapper;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Service {
  @Autowired
  private TableMapper tableMapper;

  public List<TableSearchResult> getSearchResults(String param) {
    return tableMapper.getAllColumnsFromTable1(param);
  }
}

然后在 .JAR 方面我有

数据库连接器 pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>databaseconnector</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>Database Connector</name>

  <dependencies>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.0.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.0.0.RELEASE</version>
    </dependency>
  </dependencies>
</project>

数据库连接器DatabaseConnection.java:

package com.example.databaseconnector.connector;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

public class DatabaseConnection implements InitializingBean {
  private DataSource dataSource;
  private DataSourceTransactionManager dataSourceTransactionManager;
  private SqlSessionFactoryBean sqlSessionFactoryBean;
  private MapperScannerConfigurer mapperScannerConfigurer;

  public DataSource getDataSource() {
    return this.dataSource;
  }

  public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    if (getDataSource() == null) {
      throw new IllegalArgumentException("Property 'dataSource' is required");
    } else {
      this.configureDataSourceTransactionManager();
      this.configureSqlSessionFactoryBean();
      this.configureMapperScannerConfigurer();
    }
  }

  private void configureDataSourceTransactionManager() {
    this.dataSourceTransactionManager = new DataSourceTransactionManager();

    this.dataSourceTransactionManager.setDataSource(dataSource);
  }

  private void configureSqlSessionFactoryBean() {
    this.sqlSessionFactoryBean = new SqlSessionFactoryBean();

    this.sqlSessionFactoryBean.setDataSource(dataSource);

    this.sqlSessionFactoryBean.setConfigLocation(
        new ClassPathResource("mybatis-config.xml"));

    this.sqlSessionFactoryBean.setTypeAliasesPackage(
        "com.example.sewp5databaseconnector.domain");
  }

  private void configureMapperScannerConfigurer() {
    this.mapperScannerConfigurer = new MapperScannerConfigurer();

    this.mapperScannerConfigurer.setBasePackage(
        "com.example.databaseconnector.persistence");

    this.mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
  }
}

当我运行 WebApp1 时,程序失败,因为它找不到 TableMapper bean 来自动装配服务中的映射器。我缺少什么 Spring 设置才能让所有这些都一起工作,还是我以完全错误的方式解决这个问题?

【问题讨论】:

    标签: java spring maven jndi mybatis


    【解决方案1】:

    您似乎缺少 TableMapper bean 的 Spring 配置。该类需要是一个 Spring bean 才能将其注入Service。 将相关的bean配置添加到你的applicationContext.xml

    【讨论】:

    • 我添加了一个应用程序上下文并将 dataSource bean 从 .war 传递到 .jar。它在java文件中设置没有问题,但是我不能将dataSource传递给applicationContext。所以我只传递了我的 Jndi 名称字符串,同样的问题再次无法从 java 类中的变量转到应用程序上下文中的 bean。我做的最后一件事是在我的课堂上实现 ApplicationContextAware。我能够将 .war 中定义的数据源传递给 .jar 的 applicationContext,但是在 .jar applicationContext 中创建的任何内容都没有传递给 .war。
    【解决方案2】:

    Spring 上下文层次结构有助于常见代码场景。 如果您在单个 EAR 中有多个 webapp,EAR 可以有自己的上下文,它是各个 webapp 上下文的父级。 同样在每个 webapp 中,您也可以拥有一个根上下文和单独的子上下文。 您可以在 web.xml 中定义此层次结构。可以通过上下文参数指定父上下文:locatorFactorySelector 和 parentContextKey。通过上下文参数 contextConfigLocation(外部 servlet)的根上下文。子上下文可以在每个 servlet 的 init param - context 参数中指定。

    在 EAR 中有一个 jar 来保存所有公共服务和 DAO 层代码,并在 beanRefContext.xml(基本上是另一个应用程序上下文 xml)中定义它们。让这个 jar 在类路径中可用。

    在您要引用父上下文代码的每个应用的 web.xml 中:

        <!--  root application context -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:rootContextBeans.xml</param-value>
        </context-param>
        <!--  shared service layer - parent application context -->
        <context-param>
            <param-name>locatorFactorySelector</param-name>
            <param-value>classpath:beanRefContext.xml</param-value>
        </context-param>
        <context-param>
            <param-name>parentContextKey</param-name>
            <param-value>servicelayer-context</param-value>
        </context-param>
        <listener>
            <listener-class>
                org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>     
        <servlet>
            <servlet-name>dispatcherServletApp1</servlet-name> 
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
            <init-param> 
                <param-name>contextConfigLocation</param-name> 
                <param-value>classpath*:webApp1.xml</param-value> 
            </init-param> 
        </servlet> 
    

    beanRefContext.xml 会是这样的:

        <beans>
          <bean id="servicelayer-context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
            <constructor-arg>
              <list>
                <value>data-layer-context.xml</value>
              </list>
            </constructor-arg>
          </bean>
        </beans>
    

    这样你就可以实现你想要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-24
      • 2020-03-13
      • 1970-01-01
      • 2020-07-24
      • 1970-01-01
      • 1970-01-01
      • 2017-02-11
      • 2015-12-12
      相关资源
      最近更新 更多