I am trying to create a java library that uses spring. But I am not able to find any resources that shows you how to set up component scan and load all beans when you do not have a main entry point into the application.
A common approach used by spring is to define a #EnableXXXX and let the client of your library to enable it by annotating it on their configuration class. Something like :
#Target(ElementType.TYPE)
#Import(FooLibarayConfiguration.class)
#Documented
public #interface EnableFooLibaray{
}
#ComponentScan("xxxxx")
#Configuration
public class FooLibarayConfiguration{
}
And client enables your library by :
#EnableFooLibaray
#Configuration
public class Application{
}
The #Import actually supports a more dynamic way to include the bean settings for your library. You can refer to many existing #EnableXXX provided by spring such as #EnableAsync , #EnableWebSecurity , #EnableTransactionManagement , #EnableCaching etc. for many examples.
Related
I am learning Spring Boot and have a question with one example in the reference documentation.
Following section of the documentation mentions
6. Using the #SpringBootApplication Annotation
A single #SpringBootApplication annotation can be used to enable those
three features, that is:
#EnableAutoConfiguration: enable Spring Boot’s auto-configuration
mechanism
#ComponentScan: enable #Component scan on the package where the
application is located (see the best practices)
#Configuration: allow to register extra beans in the context or import
additional configuration classes
and the following example to replace this single annotation by any of the features that it enables is bit confusing for me . The example
package com.example.myapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
#Configuration(proxyBeanMethods = false)
#EnableAutoConfiguration
#Import({ MyConfig.class, MyAnotherConfig.class })
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Explanation for the example
In this example, Application is just like any other Spring Boot
application except that #Component-annotated classes and
#ConfigurationProperties-annotated classes are not detected
automatically and the user-defined beans are imported explicitly (see
#Import).
The only major difference I see in the example code above is that it does not have #ComponentScan annotation. I also read in the comments section of an SO answer (Stephane Nicoll May 5 '17 at 11:07) that #Component annotation is not recommended officially to auto detect #ConfigurationProperties. So my assumption is that Spring framework classes with #ConfigurationProperties are not annotated with #Component.
Also I checked the #SpringBootApplication annotation source and couldn't identify anything that should enable the automatic detection of #ConfigurationProperties annotated classes.
The reference document 2.8.3. Enabling #ConfigurationProperties-annotated types section shows the following way to scan and autodetect #ConfigurationProperties
#SpringBootApplication
#ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
With all these details , I would like to understand
Why is it explicitly mentioned for this example that #ConfigurationProperties-annotated classes are not detected automatically ? and How is #ConfigurationProperties annotated classes automatically detected when #SpringBootApplication is used.
Additional note : I saw a small difference between the prior version of the documentation and the current one. The following reference is missing the current one
Keep in mind that the #EnableConfigurationProperties annotation is
also automatically applied to your project so that any existing bean
annotated with #ConfigurationProperties is configured from the
Environment
Following is what I understand from my analysis.
#ConfigurationProperties annotated types can be registered to the ApplicationContext by
Annotating the class with #ConfigurationProperties with an
annotation that falls in the scope of #ComponentScan (
#Component, #Service and the like ) . Not recommended as per the comment from Stephane Nicoll , which makes sense to me now.
Using annotation
#EnableConfigurationProperties . For this to
work the class annotated with #EnableConfigurationProperties
should be annotated with an annotation that falls in the scope of
#ComponentScan ( #Component, #Service and the like )
Using annotation #ConfigurationPropertiesScan and by making sure
the classes annotated with #ConfigurationProperties is placed
under its radar. The usage is similar to #ComponentScan .
Now , when we replace #SpringBootApplication with individual annotations that it enables and omit #ComponentScan (as in example) , the #EnableConfigurationProperties way (Point 2) of registering the types with #ConfigurationProperties will not work. This probably answers both my questions on why and how .
This was explicitly mentioned probably because the connection between #EnableConfigurationProperties and #ComponentScan is not that obvious for people like me.
Additional details.
The registration of #ConfigurationProperties annotated types when we use #EnableConfigurationProperties happens through of the EnableConfigurationPropertiesRegistrar class that is imported by the annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Import(EnableConfigurationPropertiesRegistrar.class)
public #interface EnableConfigurationProperties {..}
I know that when we annotate a java class as #SpringBootApplication we will have internally annotations #EnableAutoConfiguration and #SpringBootConfiguration but i'm confused what is the difference between them.
I am very much new to spring boot, Can someone please elaborate on this.
public #interface SpringBootConfiguration
Indicates that a class provides Spring Boot application
#Configuration. Can be used as an alternative to the Spring's standard
#Configuration annotation so that configuration can be found
automatically (for example in tests).
from: SpringBootConfiguration docs
public #interface EnableAutoConfiguration
Enable auto-configuration of the Spring Application Context,
attempting to guess and configure beans that you are likely to need.
from: EnableAutoConfiguration docs
So what is the difference?
#SpringBootConfiguration annotation tells us that a class is a configuration class, and #EnableAutoConfiguration automatically configures the Spring application based on its included jar files.
it is meta annotation #SpringBootApplication will have other annotations
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java
if #SpringBootApplication is not there applications need to use other annotations on Main class
When using spring, I want to have a configuration structure like:
//package com.test
//main configuration A
#Configuration
#ComponentScan({"com.pakcage.A", "com.common"})
public class AppA{
...
}
//package com.test
//main configuration B
#Configuration
#ComponentScan({"com.pakcage.B", "com.common"})
public class AppB{
...
}
//package com.common
//sub configuration for common use
#Configuration
#ComponentScan({"com.pakcage.common1", "com.package.common2"})
public class CommonConfig{
...
}
I can launch my Application by useing Configuration AppA or Configuration AppB, and all of them contains some common packages to scan like
"com.pakcage.common1"/"com.package.common2"
, I want to put it into a single configuration.
I want to ask
What will happen when I put multiply #ComponentScan, there will be a combination of all of these #ComponenScan?
Is there some source code reference to read about how this happen?
Yes, all the packages defined by any #ComponentScan will be scanned.
Yes, spring framework is opensource. You can access the sources here.
I tried to use #PropertySource in a #Component like:
#Component
#PropertySource("somepropertiesfile.properties")
public class Student {
...
}
It worked fine.
I want to understand, what is the different between using #PropertySource with #Component and #PropertySource with #Configuration.
Is there any difference or impact of using #PropertySource with #Component.
Configuration is itself a Component type, look into the #Configuration annotation implementation below.
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Component
public #interface Configuration {
}
From API
Component: Indicates that an annotated class is a "component". Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning.
Configuration: Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
The #Bean annotation is used to indicate that a method instantiates, configures and initializes a new object to be managed by the Spring IoC container. These are same as Spring’s XML configuration. You can use #Bean annotated methods with any Spring #Component, however, they are most often used with #Configuration beans.
Here also you can use #PropertySource in #Component class but these are most suitable for #Configuration classes as it is a configuration related task.
You can refer Doc for detailed information.
If you are starting a Spring project, you may know where you have placed the #controller, #requestmapping annotations and other annotations and the corresponding controller class.
Lets say few months down the line a new developer comes into your team, how would he figure out which classes to work with? Because unlike the xml based approach where all the configurations is centrally located in an config.xml file, we don't have nothing of that sort with annotation as per my knowledge (I am new to spring), we write the respective annotations in a class itself.
In Spring, two ways to define your configuration :
Either in a XML file or
Java class
So just like xml, in Java also you need to create a configuration class which will have all the required configurations details. You can define all of your beans, filters etc here.
For example , You create a configuration class MvcConfig with the below annotations
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy(proxyTargetClass = true)
#ComponentScan(basePackages = {"com.abc.example"})
Now your base package is com.abc.example. In all the applications, the best practice is to keep all of you controller\service\DAO classes in specific packages like
Controller : com.abc.example.controller,
Service : com.abc.example.service,
DAO : com.abc.example.dao
So anybody who comes in will know where are all the respective classes located and from where to start.
Example configuration class :
#Configuration
#EnableWebMvc
#EnableAspectJAutoProxy(proxyTargetClass = true)
#ComponentScan(basePackages = {"com.abc.example"})
public class MvcConfig extends WebMvcConfigurerAdapter