web-dev-qa-db-ja.com

注釈を使用して構成されたSpringコンソールアプリケーション

スプリングコンソールアプリケーションを作成したい(たとえば、コマンドラインからmavenを実行:mvn exec:Java -Dexec.mainClass = "package.MainClass")。

このアプリケーションは、ある種のサービスとdaoレイヤーが必要です。 Webアプリケーションでそれを行う方法は知っていますが、コンソールアプリケーションの場合(Swingの場合もあります)に行う方法についての情報はありません。

私は次のようなものを作成しようとしています:

public interface SampleService {
 public String getHelloWorld();
}


@Service
public class SampleServiceImpl implements SampleService {
 public String getHelloWorld() {
  return "HelloWorld from Service!";
 }
}

public class Main {
 @Autowired
 SampleService sampleService;
 public static void main(String [] args) {
  Main main = new Main();
  main.sampleService.getHelloWorld();
 }
}

出来ますか?どこでそれを行うかの例を見つけることができますか?

34
fatman

Spring Reference、 .2.2コンテナのインスタンス化 をご覧ください。

コンソールアプリケーションでSpringを使用するには、ApplicationContextのインスタンスを作成し、そこからSpring管理Beanを取得する必要があります。

XML設定を使用してコンテキストを作成する方法については、リファレンスをご覧ください。完全に注釈ベースのアプローチの場合、次のように実行できます。

@Component // Main is a Spring-managed bean too, since it have @Autowired property
public class Main {
    @Autowired SampleService sampleService;
    public static void main(String [] args) {
        ApplicationContext ctx = 
            new AnnotationConfigApplicationContext("package"); // Use annotated beans from the specified package

        Main main = ctx.getBean(Main.class);
        main.sampleService.getHelloWorld();
    }
}
33
axtavt

Spring Referenceでは、mainメソッドで ClassPathXmlApplicationContext を使用してアプリケーションコンテキストを作成し、getBeanメソッドを呼び出してアプリケーションコンテキストからBeanへの初期参照を取得することを推奨しています。 。この同じコードを数回書いた後、ボイラープレートをこのユーティリティクラスにリファクタリングします。

/**
 * Bootstraps Spring-managed beans into an application. How to use:
 * <ul>
 * <li>Create application context XML configuration files and put them where
 * they can be loaded as class path resources. The configuration must include
 * the {@code <context:annotation-config/>} element to enable annotation-based
 * configuration, or the {@code <context:component-scan base-package="..."/>}
 * element to also detect bean definitions from annotated classes.
 * <li>Create a "main" class that will receive references to Spring-managed
 * beans. Add the {@code @Autowired} annotation to any properties you want to be
 * injected with beans from the application context.
 * <li>In your application {@code main} method, create an
 * {@link ApplicationContextLoader} instance, and call the {@link #load} method
 * with the "main" object and the configuration file locations as parameters.
 * </ul>
 */
public class ApplicationContextLoader {

    protected ConfigurableApplicationContext applicationContext;

    public ConfigurableApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * Loads application context. Override this method to change how the
     * application context is loaded.
     * 
     * @param configLocations
     *            configuration file locations
     */
    protected void loadApplicationContext(String... configLocations) {
        applicationContext = new ClassPathXmlApplicationContext(
                configLocations);
        applicationContext.registerShutdownHook();
    }

    /**
     * Injects dependencies into the object. Override this method if you need
     * full control over how dependencies are injected.
     * 
     * @param main
     *            object to inject dependencies into
     */
    protected void injectDependencies(Object main) {
        getApplicationContext().getBeanFactory().autowireBeanProperties(
                main, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
    }

    /**
     * Loads application context, then injects dependencies into the object.
     * 
     * @param main
     *            object to inject dependencies into
     * @param configLocations
     *            configuration file locations
     */
    public void load(Object main, String... configLocations) {
        loadApplicationContext(configLocations);
        injectDependencies(main);
    }
}

アプリケーションのmainメソッドでloadメソッドを呼び出します。 MainクラスはSpringで作成されたBeanではありませんが、そのプロパティの1つにアプリケーションコンテキストからのBeanを注入できることに注意してください。

public class Main {
    @Autowired
    private SampleService sampleService;

    public static void main(String[] args) {
        Main main = new Main();
        new ApplicationContextLoader().load(main, "applicationContext.xml");
        main.sampleService.getHelloWorld();
    }
}
20
Chin Huang

最近、プロジェクトでこれを理解したいと思います。私は、スケジュールされたジョブから実行され、プロジェクトのWebアプリケーションコードの一部を再利用するユーティリティ用のCLIを構築していました。すべての@Autowired依存関係のブートストラップに問題があり、実際にはそれらすべてを必要としなかったため、次のようにAnnotationConfigApplicationContext register(Java.lang.Class ...)メソッドを使用してメインクラスの特定の依存関係をブートストラップしました。

@Component
public class SpringAppCLI
{

    /**
     * Service to be autowired!
     */
    @Autowired
    private SampleService sampleService;

    /**
     *
     */
    public static void main(String[] args) throws Exception {

        final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // setup configuration
        applicationContext.register(SampleServiceConfig.class);
        applicationContext.register(SampleServiceRepository.class);
        applicationContext.register(JpaConfig.class);
        applicationContext.register(CommandLineConfig.class);
        applicationContext.register(SampleService.class);
        applicationContext.register(SpringAppCLI.class);
        // add CLI property source
        applicationContext.getEnvironment().getPropertySources()
                .addLast(new SimpleCommandLinePropertySource(args));

        // setup all the dependencies (refresh) and make them run (start)
        applicationContext.refresh();
        applicationContext.start();

        try {
            SpringAppCLI springAppCLI = applicationContext.getBean(SpringAppCLI.class);
            springAppCLI.doWhatever();
        } catch (Exception e) {
            //some handling

        } finally {
            applicationContext.close();
        }
    }
}

構成クラスは次のとおりです。

@Configuration
@ComponentScan(basePackageClasses = SolrLoadCLI.class, includeFilters = @Filter(Controller.class), useDefaultFilters = false)
class CommandLineConfig implements ApplicationContextAware {

    /**
     * 
     */
    private ApplicationContext applicationContext;

    /**
     * 
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 
     * @return
     */
    @Bean
    public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
        Resource[] resourceArray = new Resource[2];
        resourceArray[0] = new ClassPathResource("/SampleService.properties");
        resourceArray[1] = new ClassPathResource("/Database.properties");
        ppc.setLocations(resourceArray);
        return ppc;
    }
}
3
gffny

上記のChin Huangの答えについて...

あなたの例は実際には機能しないか、少なくとも私にとってはローカルでは機能しません。 _@Autowired_を使用してSampleServiceオブジェクトを初期化しているが、プロパティで_AutowireCapableBeanFactory.AUTOWIRE_NO_を指定しているためです。代わりに、_AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE_または_AutowireCapableBeanFactory.AUTOWIRE_BY_NAME_に設定します。

また、これは奇妙であるため、何か間違ったことをしている可能性があります。しかし、_AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE_を使用するには、setProp()と_@Autowired_が必要です。したがって、これの代わりに:

_public class Main {
    @Autowired
    private SampleService sampleService;

    public static void main(String[] args) {
        Main main = new Main();
        ApplicationContextLoader loader = new ApplicationContextLoader();
        loader.load(main, "applicationContext.xml");
        main.sampleService.getHelloWorld();
    } 
}
_

私はこれをしなければなりません:

_public class Main {
    private SampleService sampleService;

    public static void main(String[] args) {
        Main main = new Main();
        ApplicationContextLoader loader = new ApplicationContextLoader();
        loader.load(main, "applicationContext.xml");
        main.sampleService.getHelloWorld();
    } 

    @Autowired
    public void setSampleService(SampleService sampleService) {
        this.sampleService = sampleService;
    }
}
_

Chinの元の例のように、_@Autowired_のプライベートデータがある場合、DIは失敗します。 3.1.1.RELEASEを使用していますが、3.1.xでは自動配線機能の一部が変更されたため、それが原因である可能性があります。しかし、これが以前のリリースのSpringと一貫しているため、なぜこれが機能しないのか興味があります。

3
Spanky Quigman

このようにすることができます:

  • Mainメソッドで初期化を行います
  • その後、startメソッドをSudoコントローラーとして使用できます
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import com.org.service.YourService;

@Component
public class YourApp{

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "ApplicationContext.xml");

        YourApp p = context.getBean(App.class);
        p.start(args);
    }

    @Autowired
    YourService yourService;
    private void start(String[] args) {

        yourService.yourMethod();

    }

}
2
royjavelosa

これが出口を実行するための私のソリューションでした。私は他のすべての特定のものに共通の基盤として機能するモジュールでそれを使用します:ウェブサイトとAPIのもの。適切なモジュールで適切な引数を指定すると、適切なタスクが実行されます。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class CLIApp {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx =
                new SpringApplicationBuilder(CLIApp.class)
                        .web(false)
                        .properties("spring.jmx.enabled=false")
                        .run(args);

        final int exitCode = SpringApplication.exit(ctx);

        System.out.println("************************************");
        System.out.println("* Console App sucessfully executed *");
        System.out.println("************************************");

        System.exit(exitCode);
    }
}

ご覧のとおり、未使用のWeb環境とJMXも無効にしました。クラスのパッケージからクラスパスをスキャンすることに焦点を当て、Spring Bootの自動構成スキルを使用します。アプリケーションが必要な処理を完了すると、コンソールアプリのように閉じます。

0
EliuX