Table of Contents
3 实现 ImportBeanDefinitionRegistrar 导入逻辑在继承类registerBeanDefinitions实现
本人最近理下spring源码,部分知识小碎知识点,记录一下,欢迎斧正,可能不太详细,勿喷!
@Configuration的原理
一个类加上@Configuration,类似于基于配置文件空配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
然后可以在类里边 添加 @Bean、@Import...等注解,可以理解为在上述空配置文件中添加元素
在加载基于注解的spring容器(如AnnotationConfigApplicationContext)时 ,会循环执行BeanFactoryPostProcessor postXXX方法,其中org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry会对@Bean等注解 解析并添加到BeanDefineMap中以便后续实例化
默认会解析一下五类注解
@PropertySource
@ComponentScan
@Import
@ImportResource
@Bean
@Autowired 和@Value 怎么自动注入的
step1
spring在解析@PropertySource时 会按照配置路径将.properties或者.yml文件解析到
org.springframework.core.env.MutablePropertySources#propertySourceList中,
step2
在createBean时populateBean()设置属性时,在循环执行InstantiationAwareBeanPostProcessor postXXX方法时,其中org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues方法就是用来注入加这两个注释的属性的,
step3
配置文件中配置的都是字符串,在注入属性时,spring会匹配适合对应类型转换的属性编辑器,如果有特殊需求,可自定义,属性编辑器,
eg.
public class DatePropertyEditor extends PropertyEditorSupport {
private String format = "yyyy-MM-dd";
public void setForrnat(String format) {
this.format = format;
}
@Override
public void setAsText(String argO) throws IllegalArgumentException {
System.out.println("argO:" + argO);
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date d = sdf.parse(argO);
this.setValue(d);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
注册到BeanFactory中
@Component
public class MyBeanFactoryAware implements BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory bf= (DefaultListableBeanFactory) beanFactory;
bf.registerCustomEditor(Date.class, DatePropertyEditor.class);
}
}
value注入
@Component
public class TestA {
@Value("2019-01-01")
private Date date;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx1 = new AnnotationConfigApplicationContext(MainConfig.class);
TestA testA = (TestA) ctx1.getBean("testA");
System.out.println(testA);
}
@Conditional实现原理
接上 "@Autowired 和@Value 怎么自动注入的"
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 在注入@Bean 会根据@Conditional配置判断,该Bean是否应该跳过, 类似的有一系列的注解@ConditionalOnClass..
eg.
@Configuration
public class MainConfig {
@Bean
@Conditional(value = MyCondition.class)
public MyLog getLog() {
return new MyLog();
}
}
public class MyCondition implements Condition {
/**
*
* @param context
* @param metadata
* @return 返回true Bean注入,否则不注入
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//判断容器中是否有myAspect的组件
if(context.getBeanFactory().containsBean("myAspect")) {
return true;
}
return false;
}
}
@Import
作用:向容器中导入Bean
@Import 有三种引入方式
@Import(value = {Person.class,MyImportSelector.class, MyBeanDefinitionRegister.class})
1 Bean以class形式导入
public class Person {
...
}
2 实现ImportSelector,返回Bean路径
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.testimport.compent.Dog"};
}
}
springBoot 的AutoConfiguration就是通过这种形式导入的,具体可以查阅 springBoot SPI机制
3 实现 ImportBeanDefinitionRegistrar 导入逻辑在继承类registerBeanDefinitions实现
public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
registry.registerBeanDefinition("cat",rootBeanDefinition);
}
}
通过以上三种形式,将导入的Bean 加入到BeanDefine中,以待容器刷新时注入