What is the difference between #ComponentScans and #ComponentScan? - java

I see that we have #org.springframework.context.annotation.ComponentScans and #org.springframework.context.annotation.ComponentScan.
How do we use #ComponentScans() ?
How is #ComponentScans() different from #ComponentScan({"com.org.abc", "com.org.xyz"})

Spring can automatically scan a package for beans if component
scanning is enabled.
#ComponentScan configures which packages to scan for classes with
annotation configuration. We can specify the base package names
directly with one of the basePackages or value arguments (value is an
alias for basePackages)
#Configuration
#ComponentScan(basePackages = "com.baeldung.annotations")
class VehicleFactoryConfig {}
Also, we can point to classes in the base packages with the
basePackageClasses argument:
#Configuration
#ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}
Both arguments are arrays so that we can provide multiple packages for
each.
If no argument is specified, the scanning happens from the same
package where the #ComponentScan annotated class is present.
#ComponentScan leverages the Java 8 repeating annotations feature,
which means we can mark a class with it multiple times:
#Configuration
#ComponentScan(basePackages = "com.baeldung.annotations")
#ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
class VehicleFactoryConfig {}
Alternatively, we can use #ComponentScans to specify multiple
#ComponentScan configurations:
#Configuration
#ComponentScans({
#ComponentScan(basePackages = "com.baeldung.annotations"),
#ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
})
class VehicleFactoryConfig {}
You can found more Spring Bean Annotations

Take a look at documentation:
ComponentScans Container annotation that aggregates several
ComponentScan annotations.
ComponentScan Configures component scanning directives for use
with #Configuration classes.

Related

Spring AutoConfiguration manul import all components

I have the following autoconfigure class.
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#Import({LoggerController.class, LogService.class, LogConfig.class})
public class ProviderAutoConfiguration {
}
I need to import all the components, services, configurations using #import annotation, otherwise for example, when I remove LogService.class (LogController autowires LogService) from #Import parameters, it throws the following error
Consider defining a bean of type 'com.log.LogService' in your configuration.
Do I really have to include all of them manuelly as shown above, or is there any other way to automatically detect classes annotated Service, Component or Configuration?
!This is starter library, not a executable app!
The problem with your "library" is that it already needs a lot of moving parts, like Spring Data JPA, properly setup JPA. If that isn't available it will fail, or if you add #EnableJpaRepositories and/or things like #ComponentScan and #EntityScan it will (quite severely) interfere with the (auto)configuration of Spring Boot or the clients. Which is what you want to prevent.
Instead of all those annotations what you need to do is
Conditionally enable #EnableJpaRepositories or just include the dependency and let the auto-configuration kick in (I suggest the latter)
Don't add #ComponentScan, #EntityScan etc. instead use #AutoConfigurationPackage which is designed for starters.
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#AutoConfigurationPackage
public class ProviderAutoConfiguration {
}
NOTE: This assumes that the ProviderAutoConfiguration is in the same or a higher package then your other classes. If not specify the basePackages in the #AutoConfigurationPackage.
You can use #ComponentScan to specify the packages you want to scan to find configurations and/or components to load.
Assuming you are using Spring Boot, at least so it seems according to your tags, you should take a look at #SpringBootApplication.
#SpringBootApplication encapsulates #Configuration, #EnableAutoConfiguration, and #ComponentScan annotations with their default attributes. The default value for #ComponentScan means that all the sub packages on the package the #ComponentScan is used are scanned. That is why it is usually a good practice to include the main class in the base package of the project.
If your components, services, configurations are under com.log as direct class or in sub-package, you can use #ComponentScan(basePackages="com.log.*")
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#ComponentScan(basePackages="com.log.*")
public class ProviderAutoConfiguration {
}

Spring : annotations for #Configuration class

I'm new to SpringBoot, and I don't quite understand for example this class:
#Configuration
#EnableConfigurationProperties(...)
#ComponentScan(basePackages = {...})
#Import(SomeClass.class)
public class MyConfig {
#Bean
public IFactory myFactory(IService myService){
return new myFactory(myService);
}
...
}
Why we are using #ComponentScan here ? The moment Spring detects this configuration it should include everything annotated with #Bean inside no ?
What does the #Import do here ? Why should be import a class rather than annotate it inside with #Bean ?
Is there any relation bewteen #Bean and the classes under #ComponentScan ?
#ComponentScan scans for other #Configuration/#Component/#Service/etc. annotated classes, under e.g. the basePackages you specify. It has nothing to do with the #Beans inside your configuration.
#Import explicitly imports another #Configuration, with all its #Bean definitions.
Having methods annotated with #Bean and #ComponentScan (searching for Java classes that are annotated with e.g. #Component) are two different ways of achieving the same thing: registering #Bean definitions/creating #Beans.

What is a specific use case where you will use #Configuration with #ComponentScan in Spring?

I'm trying to understand the transition from using xml annotation to java based annotation in Spring. I have these definitions
<context:annotation-config>: Scanning and activating annotations for already registered beans in spring config xml.
<context:component-scan>: Bean registration + <context:annotation-config>
is #Configuration and is #ComponentScan.
If lets say I declare all my beans with #Component (disregard first the more specific ones like #Repository, #Service etc) annotation and make sure that the packages are getting scanned by the #ComponentScan annotation, what is a particular use case where I will still annotate my class with both #Configuration together with #ComponentScan?
I ask this question because sometimes I see classes annotated with both #Configuration and #ComponentScan at the same time.
First read the following carefully:
Difference between <context:annotation-config> vs <context:component-scan>
Thus <context:component-scan> does the scan job and the same job than <context:annotation-config> does, it means work around with the DI annotations
Then now consider:
<context:component-scan> equivalent to #ComponentScan
<context:annotation-config> no equivalent for annotation.
what is a particular use case where I will still annotate my class
with both #Configuration together with #ComponentScan?
#Configuration is used to define beans about Infastructure such as Database, JMS etc...
Yes, a class can use both, It could be used for example for MVC Infrastructure #Configuration such as:
#EnableWebMvc
#Configuration
#ComponentScan("com.manuel.jordan.controller", "com.manuel.jordan.rest")
public class WebMvcConfig extends WebMvcConfigurerAdapter {
Thus from that class your are configuring MVC and indicating only to scan the MVC classes created by you for the "web side", such as: #Controller, #RestController.
This really depends on your likings and coding style. Documentation states:
Either basePackageClasses() or basePackages() (or its alias value()) may be specified to define specific packages to scan. If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.
So every time you see just #ComponentScan annotation this means that all sub-packages should be scanned. This is a reasonable approach to take with package per feature layout: when you have a #Configuration class for your feature and all #Components related to the feature in sub-packages.

How to prevent the SpringJUnit4ClassRunner load all #Configuration classes

In my unit test class, I have the following configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = WebAppConfigTest.class)
public class ExampleTest {
But after loading the WebAppConfigTest class, it's loading my WebAppConfig class that has #Configuration and is out of the test package (src/test/java).
Note: the class WebAppConfig is not configured to be loaded into the unit test, but still is being charged.
WebAppConfig Class
#EnableWebMvc
#ComponentScan(basePackages = {"br.com.example"})
#PropertySource(value="classpath:application.properties")
#Configuration
public class WebAppConfig extends WebMvcConfigurerAdapter {
WebAppConfigTest Class
#ComponentScan(basePackages = {"br.com.example"})
#Configuration
public class WebAppConfigTest {
How to prevent this class out of the test package is loaded?
Spring doesn't differentiate packages from src/test/java or src/main/java for your component scan.
#ComponentScan(basePackages = {"br.com.example"})
is essentially scanning all the #Configurations,all packages within current package and sub-packages starting from "br.com.example".
These are the options available for you:
Change your package structure to give a more specific package to scan for test classes.
You can use the filters in #ComponenScan to include/exclude specific packages/classes. You can avoid the unwanted classes to be picked up by spring when loading the application context this way.
If its possible to handpick the required configurations to load the context for tests, you can even remove the #ComponentScan altogether and specify all the configuration classes in "classes" attribute.
You can use #Profile in your configuration classes and #ActiveProfiles in your test classes to map the configuration classes to be loaded in specific profiles.

Should I annotate configuration class as #Configuration for testing?

I spent some time resolving problem with missing org.joda.time.DateTime->java.util.Date converter in Spring Data (which should be enabled by default when Joda-Time is on a classpath). I have found a reason, but it generated a question about #Configuration annotation in Spring.
Standard application config using AbstractMongoConfiguration from spring-data-mongodb:
#Configuration
#ComponentScan
#EnableMongoRepositories
public class AppConfig extends AbstractMongoConfiguration { ... }
A test which explicit uses AppConfig class (with Spock, but internally mechanisms provided by spring-test are used):
#ContextConfiguration(classes = AppConfig)
class JodaDocRepositorySpec extends Specification {
#Autowired
private JodaDocRepository jodaDocRepository
def "save document with DateTime"() {
given:
def jodaDoc = new JodaDoc(DateTime.now())
when:
def savedJodaDoc = jodaDocRepository.save(jodaDoc)
then:
savedJodaDoc.id
}
}
It works fine. But when #Configuration annotation in AppConfig is removed/commented:
//#Configuration
#ComponentScan
#EnableMongoRepositories
public class AppConfig extends AbstractMongoConfiguration { ... }
the test fails with:
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type org.joda.time.DateTime to type java.util.Date
AFAIK it is not needed to use #Configuration for the configuration class when it is explicit registered in the context (by classes in #ContextConfiguration or a register() method in AnnotationConfigWebApplicationContext). The classes are processed anyway and all declared beans are found. It is sometimes useful to not use #Configuration to prevent detecting by a component scan when there are 2 similar configuration classes in the same packages in a test context used by different tests.
Therefor I think it could a bug in Spring which causes to different internal beans processing in the context depending on an usage or not a #Configuration annotation. I compared Spring logs from these two cases and there are some differences, but I'm not able to determine what are they caused by in the Spring internal classes. Before a bug submission I would like to ask:
My question. Is there an explicable reason why Spring for the same configuration class (pointed explicit in #ContextConfiguration) uses (or not) converters for Joda-Time depending on an existence of a #Configuration annotation?
I created also a quickstart project reproducing the issue. spring-data-mongodb 1.3.3, spring 4.0.0, joda-time 2.3.
It's everything OK in this behaviour. AbstractMongoConfiguration is annotated by #Configuration, but in fact this annotation is not #Inherited, so you have to explicitly annotate your class.
When you remove #Configuration annotation then your AppConfig class is not a full configuration. It's processes as a lite configuration just because it contains methods annotated by #Bean - please refer to methods in org.springframework.context.annotation.ConfigurationClassUtils
isFullConfigurationCandidate()
isLiteConfigurationCandidate()
isFullConfigurationClass()
Finally only full (annotated by #Configuration) configuration classes are processes and enhanced by configuration post processors - look at ConfigurationClassPostProcessor.enhanceConfigurationClasses()

Categories

Resources