Spring контекст из файла jar

Я разрабатываю настольное приложение в java, используя spring и спящий режим. Я хочу упаковать его как исполняемый банку, но у меня возникают проблемы с загрузкой XML-конфигурации контекста из файла jar.

Я упакую приложение как исполняемый файл jar, и когда я запускаю файл jar, он сообщает мне, что файл не существует. Я знаю, что из файла jar я должен загружать InputStream, но там не поддерживается реализация ApplicationContext.

Я считаю, что мне придется закодировать свой собственный InputStreamXmlApplicationContext, и я уже пытался это сделать. Я сделал несколько исследований и немного кодировал:


import java.io.InputStream;

import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;

public class InputStreamXmlApplicationContext extends AbstractXmlApplicationContext {

    private Resource[] configResources;

    public InputStreamXmlApplicationContext(InputStream in) {
        InputStreamResource resource = new InputStreamResource(in);
        configResources = new InputStreamResource[] {resource};
        setConfigResources(configResources);
        refresh();
    }

    public Resource[] getConfigResources() {
        return configResources;
    }

    public void setConfigResources(Resource[] configResources) {
        this.configResources = configResources;
    }

    protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
        beanDefinitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
    }
}

Но я не могу заставить его работать. Может кто-нибудь мне помочь?

Ответ 1

Попробуйте ClassPaспасибоmlApplicationContext

Это автономный контекст XML-приложения, который принимает файлы определения контекста из пути к классу, интерпретируя простые пути как имена ресурсов класса, которые включают путь пакета (например, "mypackage/myresource.txt" ).

Полезно для тестовых жгутов, а также для контекстов приложений, встроенных в JAR.

Вот как вы можете это сделать:

Создайте себе тестовый класс со следующим содержимым в нем:

package com.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
  public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new 
           ClassPathXmlApplicationContext("/com/test/appConfig.xml");
    Integer someIntBean = (Integer) context.getBean("testBean");
    System.out.println(someIntBean.intValue()); // prints 100, as you will see later
  }
}

Теперь создайте конфигурационный файл приложения beans с именем appConfig.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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-2.0.xsd">
  <bean id="testBean" class="java.lang.Integer">
    <constructor-arg type="int" value="100" />
  </bean>
</beans>

Эти файлы создаются в пакете под названием com.test, рядом друг с другом. Добавьте ссылки на classpath на ваши кувшины spring или упакуйте их вместе в свой собственный файл jar, который должен выглядеть следующим образом:

test.jar --- com
          |   |--- test
          |          |--- appConfig.xml
          |          |--- Test.class
          |
          |-- META-INF
          |        |--- MANIFEST.MF
          |
          |-- org
          |     |--- springframework 
          |               |--- ...
          |               |--- ...
          |-- ....

В вашем файле манифеста вы получите это (используйте с завершающей пустой строкой):

Main-Class: com.test.Test

И это все.

Когда вы запустите свой файл (дважды щелкните или java -jar test.jar), вы увидите 100, напечатанных на экране. Вот что я получаю от его выполнения (обратите внимание на 100, о которых я говорил выше - в последней строке):

Feb 23, 2011 11:29:18 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org[email protected]ca2dce: 
display name [org[email protected]ca2dce]; 
startup date [Wed Feb 23 23:29:18 PST 2011]; root of context hierarchy
Feb 23, 2011 11:29:18 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [com/test/appConfig.xml]
Feb 23, 2011 11:29:20 PM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org[email protected]ca2dce]: 
org.s[email protected]199f91c
Feb 23, 2011 11:29:20 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.s[email protected]199f91c: 
defining beans [testBean]; root of factory hierarchy
100

P.S. Вам не обязательно включать содержимое spring jars в свою собственную банку. Вы можете иметь их доступными на пути к классам при запуске приложения. Я разместил их так, как вы упомянули одну банку. В основном это то, что вам нужно:

test.jar --- com
          |   |--- test
          |          |--- appConfig.xml
          |          |--- Test.class
          |
          |-- META-INF
                   |--- MANIFEST.MF

Ответ 2

Если ваша банка находится в classpath; вы можете импортировать определения bean из банки с помощью импорта

<import resource="classpath:/path-to.xml"/>

Ответ 3

Почему бы не использовать ClasspaспасибоmlApplicationContext и загрузить их с помощью относительного пути к классам?

Ответ 4

Предположим, вы хотите запустить приложение как java -jar myapp.jar

В этом случае используйте класс ClassPathXmlApplicationContext в своем классе с помощью метода main.

public static void main( String[] args ) {
    String config[] = { "spring-beans.xml" };
    ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
    DataSource ds = (DataSource) ctx.getBean("dataSource", DataSource.class);
}

Это страшная идея попробовать реализовать свой собственный ApplicationContext. Это слишком много работы и слишком много места для ошибок.