I am new to the Springboot framework, and I have some questions about the defualt run() function in the application.java file of the springboot maven project.
I'm trying to build a REST api with spring maven project. In specific, if I have a #Restcontroller class, when and how does the default run() function call an instantiated object of it? And how are the annotated classes like #Service, #RestController and #SpringBootApplication linked together when running the application? (like, what is the process of execution of all these components at runtime?) I know the controller class is used to host APIs, but what should I put in the #Service classes?
Thanks!
#SpringBootApplication annotation in the main application class combines the #EnableAutoConfiguration, #Configuration and the #ComponentScan annotations.
When run, the static run() method starts the Spring Boot application:
#ComponentScan scans the main class package and subpackages for different #Component classes such as controllers, services and repos and registers them as beans in the ApplicationContext.
#EnableAutoConfiguration auto configures your application based on the included jars in classpath.
As far as components go:
#RestController as you said exposes the application's endpoints using #RequestMapping method annotations.
#Service holds the business logic and calls repository methods.
#Repository is data access object that connects to the databases.
Related
I'm new to Java and the Spring framework. I would like to understand the difference between
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
and
import org.springframework.web.bind.annotation.RestController;
I see people are using the above annotations to define the controllers in the application. I would like to understand what is the difference between them and when to use what.
In my case, I'm using the spring webflux framework so which is the most suitable annotation for defining the routers?
Any help is appreciatable :)
#Bean:
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container.
--> Classes that have logic in them. They do some business logic.
https://www.baeldung.com/spring-bean
#Configuration:
Spring #Configuration annotation is part of the spring core framework. Spring Configuration annotation indicates that the class has #Bean definition methods. So Spring container can process the class and generate Spring Beans to be used in the application
https://www.journaldev.com/21033/spring-configuration-annotation
--> How you tell Spring that you have beans that need to setup.
#RestController:
The #RestController annotation was introduced in Spring 4.0 to simplify the creation of RESTful web services. It's a convenience annotation that combines #Controller and #ResponseBody – which eliminates the need to annotate every request handling method of the controller class with the #ResponseBody annotation.
https://www.baeldung.com/spring-controller-vs-restcontroller
--> If you have endpoints? You are definining an API, GET/POST/DELETE api interface for your business. In those #Controller, you call your #Autowired beans (Services/Components) to do the business logic.
If there is another Application calling yours through the REST API? Then they call your #Controller Endpoints, (That is their main entry point to your system)
We have created a custom spring boot starter which holds several common feature reusable cross internal projects.
The starter is working fine as expected. However, while integration test, the projects using the starter are not able to find all beans created by the custom starter.
NB: The internal project are using in their integration test class the annotation #SpringBootTest in order to load the whole spring context.
without more information, I would say your custom spring-boot-starter has not the same namespace, so the components are not scanned from your internal Application.
Lets say your internal Project namespace is: com.hello.package.p1 and your Spring-boot-starter has the namespace: net.greeting.package.p1
Try perhaps something like this:
#SpringBootTest(classes = TestConfiguration.class)
and in your TestConfiguration.class:
#Configuration
#ComponentScan(basePackages = "net.greeting.package.p1")
public static class TestConfiguration {
// ...
}
Thanks for your answer.
When executing the internal project normally, I see clearly that they are getting the bean instances without the need to add any custom component scan. We have just added the custom starter to their dependencies. I don't see why it's not loaded while integration test. (I think that it should be reported to Spring community)
I have found a workaround which I consider not the best solution, by importing the CommonAutoConfiguration class to the internal project integration class.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { InternalProjectbootApplication.class })
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
#Import(CommonAutoConfiguration.class)
public class ArchiveUnitServiceITTest implements ServiceInterfaceIT {...
How does Spring boot application works without #SpringBootApplication?
In our project, we used #Component, #Configuration and bean configuration with #Bean annotation. Later we have commented both the spring-boot-maven-plugin dependency and #SpringBootApplication, but application is built successfully without #SpringBootApplication annotation. I don't understand how its working?
#SpringBootApplication annotation is a combination of #ComponentScan, #Configuration and #EnableAutoConfiguration.
If you comment out #SpringBootApplication but still include #Configuration and #Component you are still allowing your application to be scanned for components and allowing additional components to be added to the applicationContext.The only difference is that Spring's auto configuration mechanism is not included.
https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-using-springbootapplication-annotation.html
I am using Spring Boot embedded tomcat.
In my application I have three configuration classes and I have used the #Order annotation to control the loading order of classes. When I run the application in embedded Tomcat it's working fine, but in standalone Tomcat (WAR) it's not loading in the correct order.
My classes are like below :
#Order(1) public Class WebConfig
#Order(2) public Class SwaggerConfig
#Order(3) public Class PlanoutConfig
#Order defines the sort order for annotated components, not for configuration classes.
I suppose that in embedded Tomcat mode, you benefit from a side effect.
If your classes are configuration classes, that is, classes
annotated with #Configuration, the spring boot documentation states that
you should favor #AutoconfigureOrder over #Order.
44.1 Understanding auto-configured beans
If you want to order certain auto-configurations that shouldn’t have
any direct knowledge of each other, you can also use
#AutoconfigureOrder. That annotation has the same semantic as the
regular #Order annotation but provides a dedicated order for
auto-configuration classes.
AutoConfigureOrder
public #interface AutoConfigureOrder
Auto-configuration specific variant of Spring Framework's Order
annotation. Allows auto-configuration classes to be ordered among
themselves without affecting the order of configuration classes passed
to AnnotationConfigApplicationContext.register(Class...).
You could so write :
#AutoConfigureOrder(0) public Class WebConfig {...}
#AutoConfigureOrder(1) public Class SwaggerConfig {...}
#AutoConfigureOrder(2) public Class PlanoutConfig {...}
I have spring boot application (1.1.5.RELEASE) and enabling my profiles via the configuration protperty spring.profiles.active=MyProfile
The profile gets activated correctly which I can see by beans from that profile being created.
Then I have a #Controller used as follows:
#Controller
#RequestMapping("/someUrl")
#Profile("MyProfile")
public class MyController {
...
}
This controller is not instantiated and URL used in the controller are not mapped. In the same package I have another controllers which are not limited by #Profile and these get instsantiated and mapped as expected.
So is using #Profile annotation on controller something which is not compatible with spring boot? Is there other approach I should be using?
Edit: It seems to be a bug after all as if I include -Dspring.profiles.active=MyProfile as JVM property the controller gets instantiated :'(
Edit2: So here comes the interesting part:
If you define spring.profiles.active in application.properties which is loaded by default from classpath thne it works
when you rename the file to test.properties and include it via #PropertySource("classpath:test.properties") it stops working. Will raise a bug against it.
Edit 3: As promised: https://github.com/spring-projects/spring-boot/issues/1417
Thanks!
I've tracked this down to what I believe to be a bug in Spring. See SPR-12111 for more details.
You can definitely annotate a controller with #Profile in Spring Boot, just as you are doing above. MyController gets instantiated if MyProfile is active. Are you sure that "MyProfile" is the active profile? Are you setting the spring.profiles property?
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/context/annotation/Profile.html
The #Profile annotation may be used in any of the following ways:
as a type-level annotation on any class directly or indirectly annotated with #Component, including #Configuration classes
as a meta-annotation, for the purpose of composing custom stereotype annotations