Could anyone provide an example of a SpringApplication that loads an applicationContext.xml file?
I'm attempting to move my GWT RPC application to a RESTful web service by using a Spring's Example (Gradle based). I have an applicationContext.xml but I do not see how to get SpringApplication to load it. Loading manually via
ApplicationContext context = new ClassPathXmlApplicationContext(args);
results in an empty context. ...and even if that worked it would be separate from the one returned from
SpringApplication.run(Application.class, args);
Or is there a way to get external beans into the app context created by SpringApplication.run?
If you'd like to use file from your classpath, you can always do this:
#SpringBootApplication
#ImportResource("classpath:applicationContext.xml")
public class ExampleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(ExampleApplication.class, args);
}
}
Notice the classpath string in #ImportResource annotation.
You can use #ImportResource to import an XML configuration file into your Spring Boot application. For example:
#SpringBootApplication
#ImportResource("applicationContext.xml")
public class ExampleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(ExampleApplication.class, args);
}
}
The annotation does not have to be (on the class) that (has the main method) that (has this below call):
SpringApplication.run(Application.class, args);
(in your case, what I am saying is that #ImportResource does NOT have to be on your class)
public class ExampleApplication {}
.........
You can have a different class
#Configuration
#ImportResource({"classpath*:applicationContext.xml"})
public class XmlConfiguration {
}
or for clarity
#Configuration
#ImportResource({"classpath*:applicationContext.xml"})
public class MyWhateverClassToProveTheImportResourceAnnotationCanBeElsewhere {
}
The above is mentioned in this article
http://www.springboottutorial.com/spring-boot-java-xml-context-configuration
.........
BONUS:
And just in case you may have thought "SpringApplication.run" was a void method.....that is NOT the case.
You can also do this:
public static void main(String[] args) {
org.springframework.context.ConfigurableApplicationContext applicationContext = SpringApplication.run(ExampleApplication.class, args);
String[] beanNames = applicationContext.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String name : beanNames) {
System.out.println(name);
}
This will also subtly clue you in to all the many, many, many (did I mention "many"?)....dependencies that spring boot is bringing in. Depending to whom you speak, this is a good thing (somebody else did all the nice figuring out for me) or an evil thing (whoah, that's a lot of dependencies that I don't control).
hashtag:sometimesLookBehindTheCurtain
Thanks Andy, that made it very concise. However, my main problem turned out to be getting applicationContext.xml into the classpath.
Apparently, putting files into src/main/resources is required to get them into the classpath (by placing them into the jar). I was attempting to set CLASSPATH which was just ignored. In my example above, the load seemed to fail silently. Using #ImportResource caused it to fail verbosely (which helped me track down the real cause).
Related
I wanted to migrate/run old java code to docker using Jenkins.
It is structured to run using normal main method of java (Jar file having main method is executed through some script).
Its making use of spring.xml(applicationContext.xml) files with spring-context-2.5.xsd
Uses properties file for all configurations.
Questions as I am looking for recommendations now on:
Does this project needs to be migrated to spring-boot application for migrating to/creating docker image?
If yes, please have a look at current code block
Do I need to replace properties files by yml files?
Current code of main class can be framed as :
public class SIIRunner {
public static void main(String[] args){
String envStr = null;
if (args != null && args.length > 0) {
envStr = args[0];
}
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
SIIExecutor siiExecutor= (SIIExecutor) ctx.getBean("SIIExecutor");
siiExecutor.pollAndOperate();
}
}
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
ApplicationContext app = SpringApplication.run(Application.class,
args);//init the context
SIIExecutor siiExecutor = (SIIExecutor)
app.getBean(SIIExecutor.class);//get the bean by type
}
#Bean // this method is the equivalent of the <bean/> tag in xml
public SIIExecutor getBean(){
return new SIIExecutor();
}
}
As long as you are starting with a base #Configuration class to begin with, which it maybe sounds like you are with #SpringBootApplication, you can use the #ImportResource annotation to include an XML configuration file as well.
#SpringBootApplication
#ImportResource("classpath:beanFileName.xml")
public class SpringConfiguration {
//
}
Spring boot ideal concept is avoid xml file. but if you want to keep xml bean, you can just add #ImportResource("classPath:beanFileName.xml")
I would recommend remove the beanFileName.xml file. and, convert this file to spring annotation based bean. So, whatever class has been created as bean. Just write #Service or #Component annotation before class name. for example:
XML based:
<bean ID="id name" class="com.example.MyBean">
Annotation based:
#Service or #Component
class MyBean {
}
And, add #ComponentScan("Give the package name").
This is the best approach. Hope this helps.
I'm using #ConfigurationProperties for auto configuration of properties. My code is working in IDE. But when I run the jar in command line, it is not working.
Configuration class:
#Configuration
#ConfigurationProperties(prefix="location")
public class Location {
private String base;
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
}
Main class:
#SpringBootApplication
#EnableConfigurationProperties(Location.class)
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.yml:
location:
base: c:\test
If I autowire Location class, I see an instance created. But there is not property set. The code is not entering setBase() method.
The application prints this in the console.
AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject'
annotation found and supported for autowiring
Make sure that application.yml file is in the root of your classpath, usually it's put in the resources folder.
The fact that the setBase() method is not called suggests that your application.yml file is not being found. Spring looks in the root of your classpath for the application.yml file.
The comment from M. Deinum is correct saying that your duplicated annotations will result in 2 spring beans for Location class. However, as you say you managed to autowire the bean without getting an error it suggests that your Location class isn't in a package that is found by spring when it's scanning for beans. If there were 2 beans then you'd get an error when you autowired it. By default spring will scan use the package where the #SpringBootApplication is as the base. It will then look in this package and all sub packages.
If your package structure is like this...
myapp.main
Application.java
myapp.config
Location.java
Then you need to add scanBasePackages="myapp" to the #SpringBootApplication annotation.
Also change your main class and remove the #Enable.. annotations. i.e.:
#SpringBootApplication(scanBasePackages="myapp")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
As nothing worked with yaml, I had to change to property file and use
#PropertySource({"classpath:application.properties"})
for the spring to identify the properties file
I didn't understand the proper use of #Componenet, #Configuration,#Bean annotation.
I want to run one method in every 60 seconds.Please check the below code. If I don't give #Component annotation then it doesn't run. so What is the use of #Component in this context?
#EnableScheduling
public class SchedulingProjectApplication {
private static final Logger log =
LoggerFactory.getLogger(SchedulingProjectApplication.class);
public static void main(String[] args) {
SpringApplication.run(SchedulingProjectApplication.class, args);
}
#Scheduled(fixedDelay = 6000)
public void r()
{
log.info("Start- main-job");
log.info("stop-main-job");
}
}
There are several problems with this piece of code:
Your Spring Boot application is not flagged with #SpringBootApplication (or #EnableAutoConfiguration). As a result, the auto-configuration will not kick in at all (Spring Boot will start your app but won't do anything with it besides basic stuff such as env preparation, etc). It's perfectly fine in certains cases but that isn't probably what you want
You've flagged the run task directly on your app. It's ok for demo but it would be better to move that logic in its own class
So to answer your question: SchedulingProjectApplication is the root source of your app but it's just a simple POJO. There's nothing that instructs the container to process it. Usually the app is a #Configuration (you can use one of the #EnableXYZ on it, you can define additional beans, etc.
If you add #SpringBootApplication on your class, it will scan any #Component in the same package of your app (and all the sub-packages).
More details about code structure in the documentation
One basic/simple structure for you would be:
package com.example.foo;
#SpringBootApplication
#EnableScheduling
public class SchedulingProjectApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulingProjectApplication.class, args);
}
}
And
package com.example.foo;
#Component
public class SchedulingLogger {
private static final Logger log =
LoggerFactory.getLogger(SchedulingLogger.class);
#Scheduled(fixedDelay = 6000)
public void r()
{
log.info("Start- main-job");
log.info("stop-main-job");
}
}
There are other things that you should be aware with regards to configuration (such as moving decisions outside of your #SpringBootApplication if you use slicing).
How can I replace beans.xml file for testing purposes?
I use
#SpringBootApplication
#ImportResource("classpath:Beans.xml")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
to init class, but in my testing class
#RunWith(SpringRunner.class)
#SpringBootTest
public class ArrayCointainerTest {
I'd like to use another one.
Any idea for this?
Define a separate configuration class which has you beans xml imported and annotate that with #TestConfiguration. Spring boot automatically pick this up as your test configuration
Detecting test configuration
I have a very simple Spring Boot application with classes detailed below.
My problem is with the application.properties file and how they get auto-configured. I'm trying to get Groovy Templates to update in dev by setting 'spring.groovy.template.cache: false', however this is not working. I added two more properties to see if the application.properties file was being read. The 'logging.level.org.springframework.web: ERROR' still results in INFO level messages printed to the console. However, some.prop is read correctly into the MyBean class on application start.
Is there a configuration declaration I'm missing for these properties?
src/main/resources/application.properties:
spring.groovy.template.cache: false
logging.level.org.springframework.web: ERROR
some.prop: bob
src/main/java/sample/MyBean.java:
#Component
public class MyBean {
#Value("${some.prop}")
private String prop;
public MyBean() {}
#PostConstruct
public void init() {
System.out.println("================== " + prop + "================== ");
}
}
and src/main/java/sample/Application.java:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and src/main/java/sample/com/example/MainController.java
#Controller
public class MainController {
#RequestMapping(value="/login", method = RequestMethod.GET)
public ModelAndView risk(#RequestParam Optional<String> error) {
return new ModelAndView("views/login", "error", error);
}
}
It seems you missing scanned your package "sample". Please make sure that you have scanned it.
#ComponentScan({
"sample" })
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Also, your application.properties is right. No problem with it.
It appears the solution was much simpler than I thought:
gradle bootRun
should be used to hot reload templates
gradle run does not work (all compiled classes are just built in build/ )