Spring console application configured using annotations - java

I want to create spring console application (running from command line with maven for example: mvn exec:java -Dexec.mainClass="package.MainClass").
Is this application I want to have some kind of services and dao layers. I know how to do it for a web application but I have not found any information on how to do in case of a console application (leter maybe with Swing).
I'm trying to create something like:
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();
}
}
Is it possible?
Can I find somewhere an example of how to do it?

Take a look at the Spring Reference, 3.2.2 Instantiating a container.
In order to use Spring in console application you need to create an instance of ApplicationContext and obtain Spring-managed beans from it.
Creating a context using XML config is described in the Reference. For completely annotation-based approach, you can do someting like this:
#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();
}
}

The Spring Reference suggests using ClassPathXmlApplicationContext in the main method to create the application context, then calling the getBean method to get an initial reference to a bean from the application context. After writing this same code a few times, you wind up refactoring the boilerplate into this utility class:
/**
* 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);
}
}
Call the load method in your application main method. Notice that the Main class is not a Spring-created bean, and yet you can inject one of its properties with a bean from the application context.
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();
}
}

I'd to figure this out for a project recently. I was building a CLI for a utility that would be run from a scheduled job and reused part of the web application code for the project. I had a problem bootstrapping all of the #Autowired dependencies, and I didn't actually need them all, so I bootstrapped the specific dependencies in the main class using the AnnotationConfigApplicationContext register(java.lang.Class...) method as follows:
#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();
}
}
}
and here's the configuration class:
#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;
}
}

Regarding Chin Huang's answer above...
Your example won't actually work, or at least isn't working for me locally. That's because you're initializing the SampleService object using #Autowired, but you specify AutowireCapableBeanFactory.AUTOWIRE_NO on the properties. Instead set it to AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE or AutowireCapableBeanFactory.AUTOWIRE_BY_NAME.
Also, this is odd, so I may be doing something wrong. But it seems that with AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, I have to have a setProp() with #Autowired for it to work. So instead of this:
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();
}
}
I have to do this:
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;
}
}
If I have, as in Chin's original example, private data with #Autowired, the DI fails. I'm using 3.1.1.RELEASE and I think some of the auto-wiring stuff has changed in 3.1.x, so it may be due to that. But I'm curious as to why this wouldn't work, since that's consistent with earlier releases of Spring.

You can do it this way :
Do the initialization in your main method
You can then use the start method as your sudo controller
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();
}
}

This was my solution to run an exit. I use it in a module which works as common ground to all other specific ones: a website and an API one. When I specify the right arguments on the right module it will run the right task.
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);
}
}
As you see, I also disabled the unused web environment and JMX. I will focus on scanning the classpath from the package of the class and use the autoconfiguration skills of Spring Boot.
After the application finishes doing what it needs it closes like a console app.

I used EliuX's approach with other findings from around the web and came up with this one-class command line application.
It also demonstrates how you can take advantage of the annotation scanning and spring context to pull in, say, spring services from other parts of your application to use in the CLI.
Also note that the API has changed for .web since #EliuX's answer above.
// 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);
}
}

Related

Spring : Cannot get value from application.properties

I created Spring project via Spring Initializr with project following struct:
I defined property in application.properties file :
my.prop=testvalue
I inject this value into MyClass as following :
#Component
class MyClass {
#Value("${my.prop}")
private String myProp;
public String getMyProp() {
return myProp;
}
}
ConfigBeans defined as following:
package com.example.propertiesdemo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ConfigBeans {
#Bean
public MyClass myLitoBean() {
return new MyClass();
}
}
PropertiesdemoApplication.java :
package com.example.propertiesdemo;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(
ConfigBeans.class);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}
I am expecting that after executing line
System.out.println(myClass.getMyProp());
will be printed value of myprop defined in application.properties (i.e testvalue), but after running (via Netbeans IDE) I get output :
${my.prop}
What was missed / wromg in this code ? Thanks in advance
You are creating MyClass bean twice.
Using #component annotation
using #bean annotation in the config class (use method name lowerCamelCase i.e. in your case myClass())
Create bean only once using any one of the above.
You dont need to create an application context in the main method like this. The presented code is a kind of mixture of "traditional" spring and spring boot. So you're kind of bypassing all the goodies that spring boot offers, among which is automatic application.properties loading.
If you're using spring boot (there is a #SpringBootApplication annotation) then it will create everything by itself.
Usually it should be something like this
public static void main(String[] args) {
SpringApplication.run(PropertiesdemoApplication.class, args);
}
Right, as Navnath Adsul said, you need the bean to be created once, and also, since you are using Spring Boot, you need to raise the context using a special method
#SpringBootApplication
public class PropertiesdemoApplication implements CommandLineRunner {
// Inject Bean
#Autowired
private MyClass myClass;
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(PropertiesdemoApplication.class)
.run(args);
// or SpringApplication.run(PropertiesdemoApplication.class, args);
}
#Override
public void run(String[] args) throws Exception {
System.out.println(myClass.getMyProp());
}
}
#SpringBootApplication
public class PropertiesdemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(PropertiesdemoApplication.class, args);
MyClass myClass = context.getBean(MyClass.class);
System.out.println(myClass.getMyProp());
}
}

Access java arguments in spring standalone application [duplicate]

Here is my code:
public class Main {
public static void main(String[] args) {
Main p = new Main();
p.start(args);
}
#Autowired
private MyBean myBean;
private void start(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/config.xml");
System.out.println("my beans method: " + myBean.getStr());
}
}
#Service
public class MyBean {
public String getStr() {
return "string";
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="mypackage"/>
</beans>
Why doesn't this work? I get NullPointerException. Is it possible to use autowiring in a standalone application?
Spring works in standalone application. You are using the wrong way to create a spring bean. The correct way to do it like this:
#Component
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/config.xml");
Main p = context.getBean(Main.class);
p.start(args);
}
#Autowired
private MyBean myBean;
private void start(String[] args) {
System.out.println("my beans method: " + myBean.getStr());
}
}
#Service
public class MyBean {
public String getStr() {
return "string";
}
}
In the first case (the one in the question), you are creating the object by yourself, rather than getting it from the Spring context. So Spring does not get a chance to Autowire the dependencies (which causes the NullPointerException).
In the second case (the one in this answer), you get the bean from the Spring context and hence it is Spring managed and Spring takes care of autowiring.
Spring is moving away from XML files and uses annotations heavily. The following example is a simple standalone Spring application which uses annotation instead of XML files.
package com.zetcode.bean;
import org.springframework.stereotype.Component;
#Component
public class Message {
private String message = "Hello there!";
public void setMessage(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
This is a simple bean. It is decorated with the #Component annotation for auto-detection by Spring container.
package com.zetcode.main;
import com.zetcode.bean.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
#ComponentScan(basePackages = "com.zetcode")
public class Application {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(Application.class);
Application p = context.getBean(Application.class);
p.start();
}
#Autowired
private Message message;
private void start() {
System.out.println("Message: " + message.getMessage());
}
}
This is the main Application class. The #ComponentScan annotation searches for components. The #Autowired annotation injects the bean into the message variable. The AnnotationConfigApplicationContext is used to create the Spring application context.
My Standalone Spring tutorial shows how to create a standalone Spring application with both XML and annotations.
For Spring 4, using Spring Boot we can have the following example without using the anti-pattern of getting the Bean from the ApplicationContext directly:
package com.yourproject;
#SpringBootApplication
public class TestBed implements CommandLineRunner {
private MyService myService;
#Autowired
public TestBed(MyService myService){
this.myService = myService;
}
public static void main(String... args) {
SpringApplication.run(TestBed.class, args);
}
#Override
public void run(String... strings) throws Exception {
System.out.println("myService: " + MyService );
}
}
#Service
public class MyService{
public String getSomething() {
return "something";
}
}
Make sure that all your injected services are under com.yourproject or its subpackages.
I case you are running SpringBoot:
I just had the same problem, that I could not Autowire one of my services from the static main method.
See below an approach in case you are relying on SpringApplication.run:
#SpringBootApplication
public class PricingOnlineApplication {
#Autowired
OrchestratorService orchestratorService;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(PricingOnlineApplication.class, args);
PricingOnlineApplication application = context.getBean(PricingOnlineApplication.class);
application.start();
}
private void start() {
orchestratorService.performPricingRequest(null);
}
}
I noticed that SpringApplication.run returns a context which can be used similar to the above described approaches. From there, it is exactly the same as above ;-)
A nice solution would be to do following,
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
/**
* Returns the Spring managed bean instance of the given class type if it exists.
* Returns null otherwise.
* #param beanClass
* #return
*/
public static <T extends Object> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// store ApplicationContext reference to access required beans later on
SpringContext.context = context;
}
}
Then you can use it like:
YourClass yourClass = SpringContext.getBean(YourClass.class);
I found this very nice solution in the following website: https://confluence.jaytaala.com/pages/viewpage.action?pageId=18579463

JavaConfig Spring make beans available to all application

I have a jar with a main method. I created a java config with the #Configuration annotation.
#Configuration
#ComponentScan(basePackages = { "com.test.commons" })
public class ProxyConfig {
}
In this com.test.commons I have put a service
package com.test.commons;
#Service
public class RestService {
//do rest calls
public String restGetCall(URL url){
...
}
}
I am NOT asking for this
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(ProxyConfig.class);
context.getBean("myBean");
The main
#SpringBootApplication(scanBasePackages={"com.test.commons", "com.test.soapproxy" })
public class MainAppProxy
{
private final static Logger logger = LoggerFactory.getLogger(MainAppProxy.class);
public static void main( String[] args )
{
SpringApplication.run(MainAppProxy.class, args);
// Choose environment from the arguments
String env = args[0];
// publish an endpoint here
Configuration config = null;
config = configs.properties
(new File("config_"+env+".properties"));
Endpoint.publish(endpointAddress, new SomeProxyImpl(config));
The class in which I am trying to inject the bean (is the #Component needed here really?)
#Component
public class SomeProxyImpl implements SomeServiceSoap {
#Autowired RestService restService;
I would like to be able to inject this RestService bean through #Autowired in all my application, not only in SomeProxyImpl(which is not working anyway). How can I do that?
Spring don't autowire field created by a new, unless you ask for it, like this : ApplicationContextHolder.getContext().getAutowireCapableBeanFactory().autowireBean(object);
If your SomeProxyImpl class is in the "com.test.soapproxy" package, and your class is annotated with #Component, then Spring must have created an instance with the bean autowired.
You should then get this bean from your context and use it instead of creating a new one.

How to execute a Java main class using #Configuration in a gradle project right after the beans are created

I have a config class that instantiates all the beans. I have a main class
TestUpdator() with an execute().
I plan to run this main class when I do a "gradle tomcatRunWar" to run the war which will generate the beans and run the execute() in the main class.
Example.
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "<packageName>", excludeFilters = { #Filter(type = FilterType.ANNOTATION, value = Service.class) })
#EnableSolrRepositories(basePackages = "<solrPackageName>", multicoreSupport = true)
public class JobConfig {
private static final Logger logger = LoggerFactory.getLogger(JobConfig.class);
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
....
}
#Bean
public SpringContextAware springContextAware() throws Exception {
.....
}
.....
//MAIN CLASS BEAN TO BE EXECUTED
#Bean(destroyMethod="shutdown")
public TestResultUpdator testResultUpdator() throws Exception {
TestResultUpdator resultUpdator = new TestResultUpdator();
/**
Bunch of dependencies for this bean
**/
resultUpdator.execute(); //call to execute()
return resultUpdator;
}
The TestUpdator class looks like this
public class TestResultUpdator {
//Variables
public static void main(String args[]) throws Exception {
//NOT SURE WHAT TO ADD HERE SINCE THE execute() will be called from the class above. But this is what I have right now commented out.
// ApplicationContext appContext = new AnnotationConfigApplicationContext(JobConfig.class);
// TestResultUpdator updator = appContext.getBean(TestResultUpdator.class);
// updator.execute();
}
public void execute() throws Exception {
logger.info("INSIDE EXECUTE FOR TEST UPDATOR!!!!");
while(true) {
//CODE TO BE EXECUTED
}
}
}
This class will execute in the background and would be executing code when the war is run.
Is there a way to do it the way I have it or is there an alternate way?
I have googled around and am not able to find good examples of this.
Basically what I am trying to do it two things,
1) when I do gradle tomcatRunWar, it will start tomcat and deploy the war
2) when it does that it should run the main class (TestUpdator) in the background by calling the execute()
Well, unless you're developing is a Spring Boot project, term main class is meaningless here.
If you're trying to execute a piece of code in TestResultUpdator class during context initialization, you can follow these steps:
1 Organize TestResultUpdator class as follows:
#Bean
public class TestResultUpdator {
#PostConstruct
public void execute() {
//CODE TO BE EXECUTED
}
}
2 Get this bean somewhere in your code:
#Autowire
private TestResultUpdator bean;

ApplicationContextProvider suddenly null

For the past 2 weeks things have been going great in my application. Last night I login remotely to work to find out that when I run my application my ApplicationContextProvider class no longer has knowledge of the Application Context. I've run Maven clean & build in addition to rebooting my PC. Can't seem to shake it...
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext (ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
My Main class:
public static void main(String[] args) throws IOException {
System.setProperty("java.util.logging.SimpleFormatter.format", "%4$s: %5$s%n");
final HttpServer server = HttpServer.createSimpleServer(".", 80);
WebappContext ctx = new WebappContext("ProductionQueue", "/");
//enable annotation configuration
ctx.addContextInitParameter("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
ctx.addContextInitParameter("contextConfigLocation", "com.production");
//allow spring to do all of it's stuff
ctx.addListener("org.springframework.web.context.ContextLoaderListener");
....
ctx.deploy(server);
server.start();
//start the production process
Production.init();
System.in.read();
server.stop();
My Production class:
public class Production {
private static final Logger logger = Logger.getLogger(Production.class.getName());
/* A list of active workflows */
private static List<Workflow> workflowList = new ArrayList<Workflow>();
private static ProductionService productionService;
/**
* Initialize the production line
*/
public static void init() {
logger.info("Initializing production workflows...");
ApplicationContext context = ApplicationContextProvider.getApplicationContext(); //THIS IS NULL
productionService = (ProductionService) context.getBean("productionService");
No configuration has been modified at all. Within my config class I do have a bean for it...
#Configuration
#ComponentScan(basePackages = {
"com.production"
})
#PropertySource(value= {
"classpath:/application.properties",
"classpath:/environment-${FETTER_ENVIRONMENT}.properties"
})
#EnableJpaRepositories("com.production.repository")
#EnableTransactionManagement
public class Config {
#Value("${db.url}")
String PROPERTY_DATABASE_URL;
#Value("${db.user}")
String PROPERTY_DATABASE_USER;
#Value("${db.password}")
String PROPERTY_DATABASE_PASSWORD;
#Value("${persistenceUnit.default}")
String PROPERTY_DEFAULT_PERSISTENCE_UNIT;
#Value("${hibernate.dialect}")
String PROPERTY_HIBERNATE_DIALECT;
#Value("${hibernate.format_sql}")
String PROPERTY_HIBERNATE_FORMAT_SQL;
#Value("${hibernate.show_sql}")
String PROPERTY_HIBERNATE_SHOW_SQL;
#Value("${entitymanager.packages.to.scan}")
String PROPERTY_ENTITYMANAGER_PACKAGES_TO_SCAN;
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
I'd say its mudsoup between the try to have it static and use it as a bean.
You creating a new instance of the ApplicationContextProvider as a spring bean. This is ApplicationContextAware and so gets the AC injected. But THEN you do not use said bean, you use its static getter to read the field, yet this, static thing never received the AC in the first place. You're never using your actual bean.
I'd say scratch that provider completly, and rely soley on the ApplicationContextAware interface, it does what you want, ie it was designed to do exactly that, why use a delegating bean?
I do not know if
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
the ApplicationContextAware interface.
Try to add #Component at ApplicationContextProvider class and then remove the #Bean. I hope that the ApplicationContextAware` interface is taken in account if this class is found by your normal component scan.
Turns out there was a buried exception my logging was preventing me from getting access to. Thanks for help.

Categories