刚开始学的时候,都是在xml里面注册类,或者直接在类上面写@Bean相关的注解。但是理解这些还不够,因为这些注册组件的效率并不高,此外,SpringBoot的源码往往并不是用上面的方法注册的,理解下面的注册方法有利于理解springboot。
@Import
是关键的注解,可以直接引入类、配置类、注册类等。以下的组件注册和@Import有很大的关系。在进行下面的练习前,需要自行添加一些实体类。
1. @Import直接引入需要组装的类
@Import指定要注入Apple和Banana实体类
@EnableFruit
注解代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({Apple.class, Banana.class})
public @interface EnableFruit {
}
然后在启动类里添加这个注解:
@SpringBootApplication
@EnableFood
public class EnableAnnotationTestApplication {
public static void main(String[] args) {
SpringApplication.run(EnableAnnotationTestApplication.class, args);
}
}
测试代码:
@Autowired
Apple apple;
@Autowired
Banana banana;
@Test
void fruitTest() {
System.out.println("apple = " + apple);
System.out.println("banana = " + banana);
}
2. @Import引入配置类
@Import指定要注入一个配置类。我这里指定了自己创建的配置类ToolConfig类。
@EnableTool
注解如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({ToolConfig.class})
public @interface EnableTool {
}
ToolConfig是个配置类,配置类的写法如下:
@Configuration
public class ToolConfig {
@Bean
public Pen pen() {
return new Pen();
}
@Bean
public Eraser eraser() {
return new Eraser();
}
}
测试代码:
@Autowired
Pen pen;
@Autowired
Eraser eraser;
@Test
void toolTest() {
System.out.println("pen = " + pen);
System.out.println("eraser = " + eraser);
}
3. @Import引入ImportSelector子类
@Import引入ImportSelector子类也可成功组装组件。
@EnableAnimal
注解代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({AnimalImportSelector.class})
public @interface EnableAnimal {
}
AnimalImportSelector类代码如下:
public class AnimalImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{Tiger.class.getName(), Monkey.class.getName()};
}
}
可以看到选择导入了Tiger和Monkey类进行组装。
同时,在启动类需要添加@EnableAnimal注解。
@SpringBootApplication
@EnableFruit
@EnableAnimal
public class EnableAnnotationTestApplication {
public static void main(String[] args) {
SpringApplication.run(EnableAnnotationTestApplication.class, args);
}
}
测试:
@Autowired
Tiger tiger;
@Autowired
Monkey monkey;
@Test
void animalTest() {
System.out.println("tiger = " + tiger);
System.out.println("monkey = " + monkey);
}
3. @Import引入ImportBeanDefinitionRegistrar子类
这是用来定义Bean的类,同时也可以通过@Import引入。
@EnableFood
注解代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({FoodImportDefinitionRegistrar.class})
public @interface EnableFood {
}
自己创建了一个子类,registerBeanDefinitions,代码如下,可以看到注册了两个bean。
public class FoodImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("chicken", new RootBeanDefinition(Chicken.class));
registry.registerBeanDefinition("pizza", new RootBeanDefinition(Pizza.class));
}
}
同时,仍然需要在启动类上添加注解。
@SpringBootApplication
@EnableFruit
@EnableAnimal
@EnableFood
public class EnableAnnotationTestApplication {
public static void main(String[] args) {
SpringApplication.run(EnableAnnotationTestApplication.class, args);
}
}
测试:
@Autowired
Chicken chicken;
@Autowired
Pizza pizza;
@Test
void foodTest() {
System.out.println("chicken = " + chicken);
System.out.println("pizza = " + pizza);
}
@Test
void contextLoads() {
}
以上为四种通过注解注册Bean的方法。后两种IDEA无法识别到bean而报错,但不会影响测试的运行。