本文最后编辑于 前,其中的内容可能需要更新。
IOC Bean注入相关
前提了解
组件型注解
使用@Component作为元注解的注解可理解为组件型注解,如常见的@Configuration、@Controller、@Service等
依赖注入注解
@Required(已弃用)
用于setter方法注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class ExampleBean3 {
private String name;
public String getName() { return name; }
@Required public void setName(@Value("abc") String name) { this.name = name; } }
|
@Autowired
根据类型注入,从容器中寻找与该属性class相同的bean进行匹配并注入,如果找到多个则抛出异常,找不到则该属性为null;
提供required属性,表示非必须注入,即容器中找不到bean进行注入则拉倒
支持@Primary
@Primary使用
有两个同类型不同名称的bean
1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration public class ExampleConfig3 { @Primary @Bean("bean3") public ExampleBean3 exampleBean3() { return new ExampleBean3(); } @Bean("bean32") public ExampleBean3 exampleBean3(@Value("abc") String a) { return new ExampleBean3(); } }
|
由于@Autowired是根据class进行注入的,没有@Primary注解的情况下,此处注入会抛出异常,有了@Primary注解使该bean成为@Autowired的首选。
1 2 3 4 5 6
| @Service public class ExampleService { @Autowired private ExampleBean3 bean; }
|
@Qualifier
指定名称注入,搭配@Autowired使用,解决@Autowired多个匹配的选择问题
@Resource(JSR250规范提供)
javax的注解,定义了资源相关的信息。在IOC中根据bean名称注入,不支持@Primary,不提供required属性
@Inject(JSR330规范提供)
拥有@Autowired的功能,支持@Primary,不提供required属性
>>> 开始进阶
@ComponentScan自定义过滤方式
@ComponentScan如果什么都不写,默认 basePackages 为当前类所在包,过滤类型为上述组件型注解的类。
@ComponentScan的其它过滤方式很常见了,不再赘述,使用@ComponentScan的过滤类型中的 CUSTOM 类型自定义过滤方式
1 2 3 4 5 6 7 8
| public enum FilterType { ANNOTATION, ASSIGNABLE_TYPE, ASPECTJ, REGEX, CUSTOM; }
|
自定义FilterType类型过滤器,实现 org.springframework.core.type.filter.TypeFilter 接口
1 2 3
| public class ExampleBean { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class MyTypeFilter implements TypeFilter {
@Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { String className = metadataReader.getClassMetadata().getClassName(); boolean b = ExampleBean.class.getName().equals(className); return b; } }
|
在@Configuration上使用
1 2 3 4 5 6 7 8 9
| @ComponentScan( basePackages = "ws.spring.insight.bean.injection", useDefaultFilters = false,// 默认规则不生效,即仅扫描 basePackages包下符合includeFilters 规则下的bean includeFilters = { // 自定义扫描规则 @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})}) @Configuration public class ExampleConfig { }
|
spring会扫描 basePackages 指定包下的所有类,符合过滤规则的都会加入IOC中
@Conditional 条件注入
简单了解:@Conditional在SpringBoot中大量使用,因为SpringBoot父工程集成了很多maven依赖,也就是集成了很多组件,但是子工程不一定能用得到,所以在IOC启动时,通过@Conditional注解进行条件注入,把需要的组件加入IOC中,子工程引入对应的starter时,对应的组件注入条件也就为true,即激活,也符合了SpringBoot特点,开关式的配置(不然你以为application配置文件有个开关图标是干嘛的)。
实现org.springframework.context.annotation.Condition接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class MyConditional implements Condition {
@Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory(); ClassLoader classLoader = conditionContext.getClassLoader(); Environment environment = conditionContext.getEnvironment(); BeanDefinitionRegistry registry = conditionContext.getRegistry();
String osName = environment.getProperty("os.name"); return osName != null; } }
|
在组件型注解或@Bean上使用
1 2 3 4 5 6 7 8 9 10 11
| @Conditional(MyConditional.class) @Configuration public class ExampleConfig { @Bean("beanA2") public BeanA beanA2() {
return new BeanA(); } }
|
@Import 引入组件
支持类型
@Import 支持的value为class,支持三种类型:
- 普通bean,被@Configuration注解作用的类也暂且叫做普通bean,Spring会根据该bean注解及接口等信息进行对应的操作,如遇到@Configuration则进行对应配置,遇到@Aspect时进行AOP代理等等
- ImportSelector接口实现类
- ImportBeanDefinitionRegistrar接口实现类
1 2 3 4 5 6 7
| public @interface Import {
Class<?>[] value(); }
|
ImportSelector接口实现类
1 2 3 4 5 6 7 8 9 10 11 12
| public class MyImportSelect implements ImportSelector {
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"ws.spring.insight.bean.ExampleBeanB"}; } }
|
ImportBeanDefinitionRegistrar接口实现类
1 2 3 4 5 6 7 8 9 10 11 12
| public class MyImportRegister implements ImportBeanDefinitionRegistrar {
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("testBean2",new RootBeanDefinition(BeanB.class)); } }
|
使用方式
搭配@Configuration使用
1 2 3 4 5 6 7 8
| @Import({ BeanA.class,// 1、普通类,通过bean的class导入,beanName为全类名 MyImportSelect.class,// 2、通过选择器导入 MyImportRegister.class// 3、通过注册器导入 }) @Configuration public class ExampleConfig2 { }
|
@PropertySource与@PropertySources
value-properties.properties的配置文件:properties配置文件的方式仅支持spel表达式
1 2 3
| admin.name=admin admin.age=18 admin.email=email
|
使用配置文件装载一个bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @PropertySource("classpath:value-properties.properties") @Component @AllArgsConstructor @NoArgsConstructor @Data public class Admin { @Value("${admin.name}") private String name; @Value("${admin.age}") private Integer age; @Value("${admin.email}") private String email; @Value("#{12*2}") private int number; }
|
@ConfigurationProperties(SpringBoot特有)
yml配置文件:yml支持松散绑定、支持JSR303数据校验、支持复杂类型填充、不支持spel表达式
1 2 3 4 5 6 7 8 9 10 11 12
| root-admin: username: rootadmin password: pwd123456 age: 10 email: 1245689668@qq.com birth: 2020/10/1 map: {k1: v1, k2: v2} list: - abd - 123 - CDF
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @ConfigurationProperties(prefix = "root-admin") @AllArgsConstructor @NoArgsConstructor @Data @Validated @Component public class RootAdmin {
private String username; private String password; private Integer age; @Email(message = "配置参数必须为邮箱") private String email; private Date birth; private Map<String,String> map; private List<String> list; }
|
Spring在创建带有@Validated注解(见下文)的bean的时候,就会对其属性进行JSR303数据校验。
FactoryBean
实现FactoryBean接口成为工厂bean,最终加入Spring IOC容器的bean有两个:
- bean名称 &myFactoryBean,实例是 MyFactoryBean 工厂bean
- bean名称 myFactoryBean,但实例是 ExampleBeanD 对象的实例,调用了getObject()方法。可通过其它方式修改bean名称,如@Component的value属性
工厂bean的名称 = 目标bean名称前 + &,通过bean名称获取工厂bean时,只需在bean名称前加“&”;
获取bean时,先获取工厂Bean再调用getObject()方法;bean工厂与bean的作用域相同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Component public class MyFactoryBean implements FactoryBean<ExampleBeanD> {
@Override public ExampleBeanD getObject() throws Exception {
return new ExampleBeanD(); }
@Override public Class<?> getObjectType() { return ExampleBeanD.class; }
@Override public boolean isSingleton() {
return true; } }
|
Bean初始化
实现InitializingBean, DisposableBean接口(官方不建议,与Spring框架强耦合)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Component public class ExampleInitBean implements InitializingBean, DisposableBean {
@Override public void afterPropertiesSet() throws Exception {
}
@Override public void destroy() throws Exception {
} }
|
@Bean中指定初始化方法与销毁方法(适用于导入第三方库的bean时)
1 2 3 4 5 6 7 8
| @Configuration public class AtBean {
@Bean(value = "exampleBean",initMethod = "init",destroyMethod = "disposable") public ExampleBeanA exampleBeanA() { return new ExampleBeanA(); } }
|
使用@PostConstruct和@PreDestroy标注初始化和销毁方法(推荐)
1 2 3 4 5 6 7
| @Component public class ExampleBeanE { @PostConstruct public void init() {} @PreDestroy public void disposable() {} }
|
初始化与销毁优先级
当一个bean中同时存在多个初始化方法时,如在@Bean中标注初始化方法与销毁方法、该bean又实现InitializingBean, DisposableBean接口、同时该bean使用了@PostConstruct和@PreDestroy注解标注方法。执行顺序如下:
@PostConstruct -> InitializingBean接口 -> @Bean(initMethod=””) -> @PreDestroy -> DisposableBean接口 -> @Bean(destroyMethod=””)
即:注解 > 接口 > @Bean标注
Bean实现xxxAware接口
bean实现Spring中xxxAware接口可以拿到对应的Spring组件,如图(仅展示部分)

BeanFactoryAware
BeanFactory是顶层接口,功能少,面向Spring框架,不建议使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class ExampleBeanFactoryBean implements BeanFactoryAware { @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)beanFactory; defaultListableBeanFactory.registerSingleton("exampleBean",new ExampleBeanG()); } }
|
ApplicationContextAware
ApplicationContext扩展了BeanFactory接口,功能丰富,面向开发者,建议使用;
setApplicationContext()方法调用时机:ApplicationContextAware是在spring初始化完bean后才注入上下文的
1 2 3 4 5 6 7 8 9 10 11 12
| @Component public class ExampleBeanApplicationContextAware implements ApplicationContextAware {
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Environment environment = applicationContext.getEnvironment(); environment.getProperty("os.name"); } }
|
EmbeddedValueResolverAware
提供String 解析器
1 2 3 4 5 6 7 8 9 10 11
| @Component public class ExampleBeanEmbeddedValueResolverAware implements EmbeddedValueResolverAware { @Override public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) { String str = stringValueResolver.resolveStringValue("aaa${os.name}===#{12*2}+${logging.level.root}"); System.out.println(str); } }
|
接口方法调用时机
xxxAware接口方法的调用时机:每个Aware接口一般都用对应的xxxProcessor来处理调用该接口bean的方法,如ApplicationContextAware对应ApplicationContextAwareProcessor。可以看到ApplicationContextAwareProcessor实现了BeanPostProcessor接口,即bean后置处理器,也就是在bean即将可用之前,处理一波。其它Aware接口类似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class ApplicationContextAwareProcessor implements BeanPostProcessor {
private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment()); }
if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver); }
if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext); }
if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext); }
if (bean instanceof MessageSourceAware) { ((MessageSourceAware)bean).setMessageSource(this.applicationContext); }
if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext); }
} }
|
Spring 钩子
BeanFactoryPostProcessor和BeanPostProcessor这两个接口都是初始化bean时对外暴露的入口之一;
BeanFactoryPostProcessor
bean工厂的bean属性后置处理容器,也就是说,Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其它的bean之前读取配置元数据,并有可能修改它。
1 2 3 4 5 6 7 8 9 10 11
| @Component public class ExampleBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
} }
|
BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,BeanFactoryPostProcessor的作用是在Spring Bean的定义信息已经加载但还没有初始化的时候执行postProcessBeanFactory()来处理一些额外的逻辑,而BeanDefinitionRegistryPostProcessor的作用是在BeanFactoryPostProcessor增加了一个前置处理,当一个Bean实现了该接口后,始化前先执行该接口的postProcessBeanDefinitionRegistry()方法,然后再执行其父类的方法postProcessBeanFactory()。这样就把一个Spring Bean的初始化周期更加细化,让我们在各个阶段有定制它的可能。
1 2 3 4 5 6 7 8 9 10 11
| @Component public class ExampleBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } }
|
BeanPostProcessor
bean属性后置处理器,方法也是见名知意,实现BeanPostProcessor接口可以在Bean(实例化之后)初始化的前后做一些自定义的操作,但是拿到的参数只有BeanDefinition实例和BeanDefinition的名称,也就是无法修改BeanDefinition元数据,这里说的Bean的初始化是:
1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
2)在bean定义的时候,通过init-method设置的方法
PS:BeanFactoryPostProcessor回调会先于BeanPostProcessor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Component public class ExampleBeanPostProcessor implements BeanPostProcessor {
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
|