Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用注释配置的Spring控制台应用程序_Java_Spring_Command Line - Fatal编程技术网

Java 使用注释配置的Spring控制台应用程序

Java 使用注释配置的Spring控制台应用程序,java,spring,command-line,Java,Spring,Command Line,我想创建spring控制台应用程序(使用maven从命令行运行,例如:mvn exec:java-Dexec.mainClass=“package.mainClass”) 这个应用程序就是我想要的服务和dao层。我知道如何为web应用程序这样做,但我没有找到任何关于如何在控制台应用程序(leter可能带有Swing)中这样做的信息 我正在尝试创建类似于: public interface SampleService { public String getHelloWorld(); } @S

我想创建spring控制台应用程序(使用maven从命令行运行,例如:mvn exec:java-Dexec.mainClass=“package.mainClass”)

这个应用程序就是我想要的服务和dao层。我知道如何为web应用程序这样做,但我没有找到任何关于如何在控制台应用程序(leter可能带有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();
 }
}
可能吗?
我能在什么地方找到一个如何做的例子吗?

看看Spring参考

为了在控制台应用程序中使用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();
    }
}

Spring引用建议使用
main
方法创建应用程序上下文,然后调用
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);
    }
}

关于金黄上面的回答

你的例子实际上不起作用,或者至少在本地对我不起作用。这是因为您正在使用
@Autowired
初始化
SampleService
对象,但您在属性上指定了
autowiredcapablebeanfactory.AUTOWIRE\u NO
。而是将其设置为
AutowireCapableBeanFactory.AUTOWIRE按类型
AutowireCapableBeanFactory.AUTOWIRE按名称

而且,这很奇怪,所以我可能做错了什么。但似乎有了
autowirelablebeanfactory.AUTOWIRE\u BY\u 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的早期版本是一致的。

您可以这样做:

  • 在main方法中进行初始化
  • 然后可以使用start方法作为sudo控制器

我想在最近的一个项目中解决这个问题。我正在为一个实用程序构建一个CLI,该实用程序将从计划作业运行,并为项目重用部分web应用程序代码。我在引导所有@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;
    }
}

这是我运行出口的解决方案。我在一个模块中使用它,该模块作为所有其他特定模块的共同基础:一个网站和一个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。我将着重于从类的包中扫描类路径,并使用SpringBoot的自动配置技巧。
在应用程序完成所需的操作后,它会像控制台应用程序一样关闭。

我使用了EliuX的方法和来自web的其他发现,并提出了这个单类命令行应用程序

它还演示了如何利用注释扫描和spring上下文从应用程序的其他部分引入spring服务,以便在CLI中使用

还要注意的是,自从@EliuX给出上述答案后,.web的API发生了变化

// spring boot imports
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.Banner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;

// spring imports
import org.springframework.context.annotation.ComponentScan;

// my import from another package that has spring annotations like
// @Service, @Component, @Autowired, to demonstrate how I can wrap those
// in a command line application
import my.packages.having.annotations.services.MyOtherService;

// This starts the spring container
@SpringBootApplication

// I deliberately scan packages in MY namespace that I know to have
// Spring annotations
@ComponentScan(value = "my.packages.having.annotations.*")
public class MyCliWithSpringAnnotations implements ApplicationRunner
{
    // I can autowire other services in since spring instantiates
    // this CLI class - as long as these are component-scanned (above)
    private MyOtherService _otherService;

    @Autowired
    public MyCliWithSpringAnnotations(MyOtherService otherService)
    {
        _otherService = otherService;
    }

    // This implements the ApplicationRunner interface which Spring is going
    // to find, then instantiate, then autowire, and then _run_ when I call
    // run() below in the main method.
    // This can be be implemented in any other scanned class (or classes)
    // on the classpath and will be run, but I'm sticking it all in one 
    // class for simplicity.
    @Override
    public void run(ApplicationArguments args) throws Exception
    {
        // getSourceArgs() returns the original String[] of command 
        // line args to the main() method
        _otherService.toSomethingWithThese(args.getSourceArgs());
    }

    public static void main(String... args)
    {
        new SpringApplicationBuilder(MyCliWithSpringAnnotations.class)
                .web(WebApplicationType.NONE)
                .bannerMode(Banner.Mode.OFF)
                .logStartupInfo(false)
                .build()
                .run(args);
    }
}

另外,如果您像我一样,碰巧为您的配置添加了注释:ctx=newannotationConfigApplicationContext(MyConfig.class);如何将命令行参数提供给应用程序上下文,以便上下文反过来可以将这些参数注入bean?这对我不起作用,因为我的用例与本问题中的用例完全相同。在我的情况下,我希望有一个独立的迁移数据迁移应用程序,并且我希望重用bean,例如服务、VOs和DAO来访问各种数据库,这样我就可以避免重新编码所有复杂的业务逻辑和数据验证。我得到“…未满足的依赖项异常,未满足的依赖项通过字段表示”。在我的例子中,单机版位于主SpringWebApp的子模块中。
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);
    }
}
// spring boot imports
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.Banner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;

// spring imports
import org.springframework.context.annotation.ComponentScan;

// my import from another package that has spring annotations like
// @Service, @Component, @Autowired, to demonstrate how I can wrap those
// in a command line application
import my.packages.having.annotations.services.MyOtherService;

// This starts the spring container
@SpringBootApplication

// I deliberately scan packages in MY namespace that I know to have
// Spring annotations
@ComponentScan(value = "my.packages.having.annotations.*")
public class MyCliWithSpringAnnotations implements ApplicationRunner
{
    // I can autowire other services in since spring instantiates
    // this CLI class - as long as these are component-scanned (above)
    private MyOtherService _otherService;

    @Autowired
    public MyCliWithSpringAnnotations(MyOtherService otherService)
    {
        _otherService = otherService;
    }

    // This implements the ApplicationRunner interface which Spring is going
    // to find, then instantiate, then autowire, and then _run_ when I call
    // run() below in the main method.
    // This can be be implemented in any other scanned class (or classes)
    // on the classpath and will be run, but I'm sticking it all in one 
    // class for simplicity.
    @Override
    public void run(ApplicationArguments args) throws Exception
    {
        // getSourceArgs() returns the original String[] of command 
        // line args to the main() method
        _otherService.toSomethingWithThese(args.getSourceArgs());
    }

    public static void main(String... args)
    {
        new SpringApplicationBuilder(MyCliWithSpringAnnotations.class)
                .web(WebApplicationType.NONE)
                .bannerMode(Banner.Mode.OFF)
                .logStartupInfo(false)
                .build()
                .run(args);
    }
}