spring从一定层面上讲是Bean容器,那么它是怎么实现Bean的装配,这块对于理解springBoot自动装配有很大帮助。这里说的装配,我指的是基于注解/代码的方式,毕竟现在开发都是注解先行,至于xml方式就不讨论了。
方式
- 模式注解
@Component
等(Spring2.5+) - 配置类
@Configuration
与@Bean
(Spring3.0+) - 模块装配
@EnableXXX
与@Import
(Spring3.1+)
模式注解
使用它在我们日常开发中很常见,@Component
、@Service
、@Repository
等。但是它又个天然的缺陷,只能在我们自己写的代码中,对于jar包中组件,无能为力。
配置类
@Configuration
与 @Bean
方式,这种方式我们在开发中也经常使用,例如配置数据源,一些中间件。但是它也有个天然的缺点,配置一多,类就显得很臃肿,编码和修改成本都比价高。
模块装配
这是个杀手锏,特别对于需要装配较多的bean到容器,一般它的套路是:@Enablexxx、@Import 注解来完成。
- 元注解@EnableBean
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(User.class)
public @interface EnableBean {
}
- 实体
@Data
public class Order {
private Integer id;
private Integer userId;
private Integer productId;
private BigDecimal amount;
public Order() {
System.out.println("order init ...");
}
}
@Data
public class User {
private Integer id;
private String name;
public User() {
System.out.println("user init ...");
}
}
- 配置类
@Configuration
@EnableBean
public class Config {
}
- 启动容器
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
Stream.of(beanDefinitionNames).forEach(System.out::println);
}
- 打印的日志
user init ...
10:38:50.701 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.hf.astilt.normal.Orange'
10:38:50.702 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'com.hf.astilt.normal.Order'
order init ...
10:38:50.710 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
config
com.hf.astilt.normal.User
com.hf.astilt.normal.Orange
com.hf.astilt.normal.Order
可以看到spring启动后,打印出了我配置的几个类,是不是简单很多。
@Import
这个注解隐含了模块装配的秘密,我们看看。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
翻译下它的备注:@Import里面的值是个数组。被@Configuration
修饰的配置类、实现ImportSelector
的类,实现ImportBeanDefinitionRegistrar
的类,普通的Java bean。
配置类、普通Java类就不说了,简单易懂。重点看看实现了:ImportSelector
和ImportBeanDefinitionRegistrar
的类。
ImportSelector
public class UserImport implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{User.class.getName()};
}
}
ImportBeanDefinitionRegistrar
public class FruitImport implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("apple", new RootBeanDefinition(Apple.class));
registry.registerBeanDefinition("orange", new RootBeanDefinition(Orange.class));
}
}
@EnableBean
@Configuration
@EnableBean
@Import({UserImport.class, FruitImport.class})
public class Config {
}
- 效果
user init ...
15:06:34.692 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'apple'
apple init ...
15:06:34.692 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orange'
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
config
com.hf.astilt.normal.User
apple
orange
在@Import
里面配置ImportBeanDefinitionRegistrar
和ImportSelector
的实现类,效果与直接导入Java Bean一样。