preface
In the process of using SpringBoot, the @enablexxx annotation is often used, and along with an @import annotation, this time to look at the @import source code
The body of the
Let’s copy some of its English notes:
/** * // Indicates one or more <em>component classes</em> to import — /** * / Indicates one or more <em>component classes</em> to import — typically * {@link Configuration @Configuration} classes. * * // provides the same functionality as the import tag in Spring's XML. You can import the configuration, ordinary, ImportSelector or ImportBeanDefinitionRegistrar interface implementation class * < p > Provides functionality equivalent to the {@code <import/>} element in Spring XML.
* Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
* {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
* classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
*
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
* injection. Either the bean itself can be autowired, or the configuration class instance
* declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
* navigation between {@code @Configuration} class methods.
*
* <p>May be declared at the class level or as a meta-annotation.
*
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
* imported, use the {@link ImportResource @ImportResource} annotation instead.
*
*/
Copy the code
It probably means:
- You can import a class or classes into a container, just as the import tag does in XML
- Can be introduced into ordinary classes, Configuration class, ImportSelector or ImportBeanDefinitionRegistrar interface implementation class
- Import a configuration file that can be injected by other beans and other beans can be injected into the configuration.
example
- Create a new
springboot
project - Create the same level of packages on top of the startup class. For example, the startup class
test.java
ina.b.c.d
Down here, so inc
Package builde
Package,e
andd
In the same level of directory.
The reason for the second point is that SpringBoot scans for files in the same directory as the boot class. If you’re in the same directory, just use @componment. So I think @import is importing classes that are not in the same directory as the project.
Importing a common class
Create two new classes in package E, TestImportA and TestImportB:
public class TestImportA {
public void test(a){
System.out.println("TestImportB run"); }}public class TestImportB {
public void test(a){
System.out.println("TestImportB run"); }}Copy the code
Then add the following to the startup class:
@SpringBootApplication
@Import({TestImportA.class, TestImportB.class})
public class SpringbootOneApplication {
public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(SpringbootOneApplication.class, args); TestImportB testImportB = run.getBean(TestImportB.class); testImportB.test(); }}Copy the code
In this way, TestImportA. Class, testimPortb. class can be scanned through the @import annotation and put into the container.
Import configuration class
Create a configuration class TestImportConfig in package E
@Configuration
public class TestImportConfig {
@Bean
public TestImportA testImportA(a) {
return new TestImportA();
}
@Bean
public TestImportB testImportB(a) {
return newTestImportB(); }}Copy the code
Then add the following to the startup class:
@SpringBootApplication
@Import(TestImportConfig.class)
public class SpringbootOneApplication {
public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(SpringbootOneApplication.class, args); TestImportB testImportB = run.getBean(TestImportB.class); testImportB.test(); }}Copy the code
The effect is the same as the first one.
Import the implementation class of ImportSelector
- Create a new annotation class TestImport
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ImportSelectorImpl.class) // Note that the ImportSelectorImpl class is created with this part of annotation
public @interface TestImport {
String value(a) default "value";
boolean flag(a) default false;
}
Copy the code
Explain why you want to create a new annotation class. ImportSelector interface String[] selectImports(AnnotationMetadata importingClassMetadata). This interface receives an AnnotationMetadata This class contains the annotation information where the @import annotation is located (class, interface, enumeration), so that we can get the required information when starting the configuration. The most typical is the @enablexxx annotation. Import the ImportSelector implementation class in @enablexxx using @import, so you can get some information about the @enablexxx annotation.
- Create a new ImportSelectorImpl to implement the ImportSelector interface
public class ImportSelectorImpl implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// Get the annotation collection
MergedAnnotations annotations = importingClassMetadata.getAnnotations();
// Get the TestImport annotation
MergedAnnotation<TestImport> testImportMergedAnnotation = annotations.get(TestImport.class);
/ / print
System.out.println("= = = ="+testImportMergedAnnotation.getString("value"));
return new String[]{"a.b.c.e.TestImportA"."a.b.c.e.TestImportB"}; }}Copy the code
- Use the @tESTIMPort annotation on the startup class instead
@SpringBootApplication
@TestImport
public class SpringbootOneApplication {
public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(SpringbootOneApplication.class, args); TestImportB testImportB = run.getBean(TestImportB.class); testImportB.test(); }}Copy the code
Import ImportBeanDefinitionRegistrar implementation class
The usage and ImportSelector usage is the same, there is not all shows, directly on the TestImport annotations into @ Import (ImportBeanDefinitionRegistrarImpl. Class).
- New ImportBeanDefinitionRegistrar implementation class
public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// Get the annotation collection
MergedAnnotations annotations = importingClassMetadata.getAnnotations();
// Get the TestImport annotation
MergedAnnotation<TestImport> testImportMergedAnnotation = annotations.get(TestImport.class);
// Print the value of the value attribute
System.out.println("= = = ="+testImportMergedAnnotation.getString("value"));
// Registration information
registry.registerBeanDefinition("testImportB".newRootBeanDefinition(TestImportB.class)); }}Copy the code
The last
In a recent interview, I was asked how to register beans with the Spring container and my response was:
- @Component, @Service, @Controller, and @repository. The last three layers use @Component.
- @Configuration, using @Bean registration in the Configuration class
- BeanFactoryAware, ApplicationContextAware, implements the two interfaces and then manually registers them with the container.
This can add another one @ Import, ImportBeanDefinitionRegistrar and ImportSelector.