Консольное приложение Spring, настроенное с помощью аннотаций
Я хочу создать консольное приложение spring (выполняется из командной строки с maven, например: mvn exec: java -Dexec.mainclass= "package.MainClass" ).
Является ли это приложение, я хочу иметь какие-то службы и уровни dao. Я знаю, как это сделать для веб-приложения, но я не нашел никакой информации о том, как это сделать в случае консольного приложения (возможно, с 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();
}
}
Возможно ли это?
Могу ли я найти пример того, как это сделать?
Ответы
Ответ 1
Взгляните на Spring Reference, 3.2.2 Создание экземпляра контейнера.
Чтобы использовать Spring в консольном приложении, вам нужно создать экземпляр ApplicationContext
и получить из него Spring -managed beans.
Создание контекста с использованием 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();
}
}
Ответ 2
Справочник Spring предлагает использовать ClassPathXmlApplicationContext в методе 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);
}
}
Вызвать метод load
в основном методе приложения. Обратите внимание, что класс main
не является Spring -created bean, и все же вы можете ввести одно из своих свойств с помощью 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();
}
}
Ответ 3
Относительно ответа Чин Хуан выше...
Ваш пример на самом деле не работает или, по крайней мере, не работает для меня локально. Это потому, что вы инициализируете объект SampleService
, используя @Autowired
, но вы указываете 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.
Ответ 4
Я бы подумал об этом недавно. Я создавал 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;
}
}
Ответ 5
Вы можете сделать это следующим образом:
- Сделайте инициализацию в своем основном методе
- Затем вы можете использовать метод 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();
}
}
Ответ 6
Это было мое решение для запуска выхода. Я использую его в модуле, который работает как общий язык для всех других конкретных: веб-сайт и 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);
}
}
Как вы видите, я также отключил неиспользуемую веб-среду и JMX. Я сосредоточусь на сканировании classpath из пакета класса и использовании навыков автоконфигурации Spring Boot.
После того, как приложение закончит делать то, что ему нужно, оно закрывается, как консольное приложение.