What is the difference between #ComponentScan and #EnableAutoConfiguration in Spring Boot? - java

What is the difference between the #ComponentScan and #EnableAutoConfiguration annotations in Spring Boot? Is it necessary to add these? My application works very well without these annotations. I just want to understand why we have to add them.

What is the difference between the #ComponentScan and
#EnableAutoConfiguration annotations in Spring Boot?
#EnableAutoConfiguration annotation tells Spring Boot to "guess" how you will want to configure Spring, based on the jar dependencies that you have added. For example, If HSQLDB is on your classpath, and you have not manually configured any database connection beans, then Spring will auto-configure an in-memory database.
#ComponentScan tells Spring to look for other components, configurations, and services in the specified package. Spring is able to auto scan, detect and register your beans or components from pre-defined project package. If no package is specified current class package is taken as the root package.
Is it necessary to add these?
If you need Spring boot to Auto configure every thing for you #EnableAutoConfiguration is required. You don't need to add it manually, spring will add it internally for you based on the annotation you provide.
Actually the #SpringBootApplication annotation is equivalent to using #Configuration, #EnableAutoConfiguration and #ComponentScan with their default attributes.
See also:
Using the #SpringBootApplication annotation
Auto-configuration

One of the main advantages of Spring Boot is its annotation driven versus traditional xml based configurations, #EnableAutoConfiguration automatically configures the Spring application based on its included jar files, it sets up defaults or helper based on dependencies in pom.xml.
Auto-configuration is usually applied based on the classpath and the defined beans. Therefore, we donot need to define any of the DataSource, EntityManagerFactory, TransactionManager etc and magically based on the classpath, Spring Boot automatically creates proper beans and registers them for us. For example when there is a tomcat-embedded.jar on your classpath you likely need a TomcatEmbeddedServletContainerFactory (unless you have defined your own EmbeddedServletContainerFactory bean). #EnableAutoConfiguration has a exclude attribute to disable an auto-configuration explicitly otherwise we can simply exclude it from the pom.xml, for example if we donot want Spring to configure the tomcat then exclude spring-bootstarter-tomcat from spring-boot-starter-web.
#ComponentScan provides scope for spring component scan, it simply goes though the provided base package and picks up dependencies required by #Bean or #Autowired etc, In a typical Spring application, #ComponentScan is used in a configuration classes, the ones annotated with #Configuration. Configuration classes contains methods annotated with #Bean. These #Bean annotated methods generate beans managed by Spring container. Those beans will be auto-detected by #ComponentScan annotation. There are some annotations which make beans auto-detectable like #Repository , #Service, #Controller, #Configuration, #Component.
In below code Spring starts scanning from the package including BeanA class.
#Configuration
#ComponentScan(basePackageClasses = BeanA.class)
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class Config {
#Bean
public BeanA beanA(){
return new BeanA();
}
#Bean
public BeanB beanB{
return new BeanB();
}
}

#EnableAutoConfiguration in spring boot tells how you want to configure spring, based on the jars that you have added in your classpath.
For example, if you add spring-boot-starter-web dependency in your classpath, it automatically configures Tomcat and Spring MVC.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
You can use #EnableAutoConfiguration annotation along with #Configuration annotation.
It has two optional elements,
exclude : if you want to exclude the auto-configuration of a class.
excludeName : if you want to exclude the auto-configuration of a class using fully qualified name of class.
Examples:
#Configuration
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}
#EnableAutoConfiguration(excludeName = {"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#SpringBootApplication is a newer version of #EnableAutoConfiguration which was introduced in Spring Boot 1.2.
#SpringBootApplication is a combination of three annotations,
#Configuration - for java based configuration classes.
#ComponentScan - to enable component scanning, all the packages and
subpackages will be auto-scanned which are under the root package on
which #SpringBootApplication is applied.
#EnableAutoConfiguration - to enable auto-configuration of the
classes bases on the jars added in classpath.
#ComponentScan enables component scanning so that web controller classes and other components that you create will be automatically
discovered and registered as beans in spring's application context.
You can specify the base packages that will be scanned for auto-discovering and registering of beans.
One of the optional element is,
basePackages - can be used to state specific packages to scan.
Example,
#ComponentScan(basePackages = {"com.example.test"})
#Configuration
public class SpringConfiguration { }

Related

Spring Boot Application add external library component scan

I have a spring boot app, which has a library as a dependency. In this library I have several #Component and #Configuration classes, which are not scanned by Spring Boot app. I would like to add them to component scan, but I am not able to
How can this be achieved correctly? I think adding #ComponentScan to MainApp class, annotated with #SpringBootApplication will override the default config
Thanks!
#SpringBootApplication Annotation is the combination for #Configuration, #EnableAutoConfiguration and #ComponentScan
We can also use basePackages for scan based on requirement.
For example common package is com.example so directory will be com -> example and sub packages. So for the project there will be different packages for the different modules like controller, service, dto, repository etc...
If we want to use any package for the component scan then we can use like below script.
Hierarchy will be :
com.example.controller
com.example.service
com.example.repository
So basePackages will be look like this :
#ComponentScan(basePackages = "com.example")
Because com.example is only the path/package which is common for all other packages. So we can use like this.

What is the purpose of org.springframework.boot.spring-boot POM?

What is the purpose of this POM in Sprint Boot org.springframework.boot.spring-boot
It includes
org.springframework.spring-core
org.springframework.spring-context
So in something like org.springframework.boot.spring-boot-starter-web you have
org.springframework.spring-webmvc
org.springframework.boot.spring-boot-starter
org.springframework.boot.spring-boot-starter-json
org.springframework.boot.spring-boot-starter-tomcat
Why not just make org.springframework.boot.spring-boot-starter-web
org.springframework.spring-webmvc
org.springframework.spring-core
org.springframework.spring-context
org.springframework.boot.spring-boot-starter-json
org.springframework.boot.spring-boot-starter-tomcat
spring-boot-starter has following dependencies:
jakarta.annotation-api
spring-core
spring-boot
spring-boot-autoconfigure
spring-boot-starter-logging
if you replace spring-boot-starter with spring-core and spring-context, then you miss out all the classes and annotations that are defined in spring-boot and spring-boot-autoconfigure(spring-boot depends on spring-core and spring-context, but it has implemented some important classes itself, see below).
take spring-boot-starter-web as an example, usually we need to set server.port in our application.yml, this property is defined in ServerProperties class in spring-boot-autoconfigure project(that's why we need spring-boot-starter in org.springframework.boot.spring-boot-starter-web), there are other commonly used properties such as server.address, server.servlet.context-path, and server.ssl.* ....etc.They are all defined here in spring-boot-autoconfigure project.
in order to auto configure the properties defined in ServerProperties, class ServletWebServerFactoryAutoConfiguration is created to take ServerProperties as a parameter and apply it's values to set up software like tomcat
now see that ServerProperties is neither annotated with #Configuration nor #Component, so it wouldn't be instantiated when component-scan is happening, so this annotation EnableConfigurationProperties is created to make sure ServerProperties's instance will be injected. this annotation is defined in spring boot project, that's why we need spring-boot dependency. And it's used
here.
for what is a spring boot starter and how it works, here is a helpful article: Quick Guide to Building a Spring Boot Starter

excludeFilters in #ComponentScan vs exclude in #EnableAutoConfiguration

New to spring boot.
While trying to exclude a bean from #ComponentScan, to my surprise found very flexible exclude option from #EnableAutoConfiguration.
To my understanding, #Configuration is inheriting from #Component.
So,
Why I have to remove the configuration from #EnableAutoConfiguration and why not from #ComponentScan.
We have ASSIGNABLE_TYPE/REGEX/etc. in exclude. So why still we need excludeFilters from #ComponentScan.
Is there any restrictions over each other and is it bad approach if we switch between these exclusions?
Could someone clarify here.
#ComponentScan and #EnableAutoConfiguration are used in different phases of initializing the spring application context.
#ComponentScan - used to scan for bean candidates, spring will search for various annotations like #Component, #Configuration, etc, and take bean candidates. This is a spring's feature.
#EnableAutoConfiguration - used to scan for auto-configuration candidates, spring will search for configurations marked for auto-configuration and from them load bean candidates. This is a spring boot's feature.
An auto-configuration candidate can be annotated with #ComponentScan to load bean candidates, but usually modules that are auto-configuration modules will be more precise and use #Import or special annotations. In your spring-boot project, you should have a class annotated with #SpringBootApplication that does both #ComponentScan and #EnableAutoConfiguration. This will trigger both features and do the following:
Load all bean candidates from your module that is annotated with #SpringBootApplication
Search for auto-configuration modules that are loaded in your classpath
Try to load auto-configuration modules
Try to load bean candidates from your auto-configuration modules
When you exclude something from #ComponentScan, it is excluded from the scope of the specific #ComponentScan annotation and process, wether if it is your module or an auto-configuration module you created.
When you exclude something from #EnableAutoConfiguration, you try to exclude an auto-configuration candidate. Also note that you can not exclude normal #Configuration using this annotation, only auto-configuration candidates.

#ComponentScan on external library not working

In my spring boot project i have to use a external library which it has define beans in spring context. So in my Application class i have add below which are the base package for bothe my project and the external library,
#SpringBootApplication(exclude = SecurityAutoConfiguration.class)
#EnableHypermediaSupport(type = { EnableHypermediaSupport.HypermediaType.HAL })
#EnableSwagger2
#ComponentScan(basePackages = {"com.mylibrary.test", "com.otherlibrary.springtool"})
//#EnableDiscoveryClient
public class Application extends RepositoryRestMvcConfiguration {
}
But the beans in other library such as #Configuration are not initialize?
#ComponentScan works for the classes that are annotated with #Component, #Repository or #Service. Make sure classes in "com.otherlibrary.springtool" are annotated with above annotation to be found or else you have to declare them as Spring beans with #Bean annotation. Hope it helps.
I had something similar when I was trying to use open feign interfaces coming from an external lib and then I had to add the #EnableFeignClients(basePackages = {"lib.pckg"}), because the Feign had to create the beans for me, not the Spring IoC.
It would be good if you provide some log error.

Loading configuration classes present in Spring MVC

I have a Spring MVC application with multiple separate modules which all have their own JavaConfig #Configuration class. My goal is to load all spring configurations that are present in the war. Depending on options passed to the build command some modules and thus configurations may not be present and so #Import isn't an option as it would throw ClassDefNotFound.
In the spring documentation it says
#Configuration is meta-annotated with #Component, therefore #Configuration classes are candidates for component scanning (typically using Spring XML's element) and therefore may also take advantage of #Autowired/#Inject at the field and method level (but not at the constructor level).
#Configuration classes may not only be bootstrapped using component scanning, but may also themselves configure component scanning using the #ComponentScan annotation:
However the main application class entry point looks like this
#Configuration
#EnableWebMvc
#EnableAutoConfiguration
#ComponentScan(basePackages="com.svims.common.web.config")
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And there is another class with the #Configuration annotation in the com.svims.common.web.config package that isn't found or the beans inside this configuration just aren't loaded.
I have tried adding this to the main application class
#ComponentScan(basePackages="com.svims.common.web.config",
includeFilters = {#ComponentScan.Filter( Configuration.class ) })
To ensure the scan is configured to find these types of classes but it still doesn't work.
I can only assume that Spring MVC bootstraps in a way as to ignore these configurations but I can't find any reference to this in the documentation.
Does anyone know what is going on or any suggestions on how I might do this?
Always check the packages being scanned again and again.

Categories