title: Spring 框架源码解读8
date: 2020/04/18 16:17
本节内容 & 思考题
- 实现 Spring 中包扫描 @Component 注解
<context:component-scan base-package="com.dist.ars.aop.test"/>
- 实现注解版实例工厂(@Configuration + @Bean 注解实现)
猜猜 @ComponentScan 和 xml 中的包扫描,Spring 是怎样实现的呢?
实现配置文件包扫描
1、@Component 注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
2、修改 json 文件格式
{
"beans": [
{
"name": "appleFactory",
"className": "cn.x5456.summer.AppleFactory"
},
{
"name": "initAnnotationBeanPostProcessor",
"className": "cn.x5456.summer.InitAnnotationBeanPostProcessor"
}
],
"componentScanPackages": [
"cn.x5456.summer"
]
}
3、修改 JsonBeanFactoryImpl
public class JsonBeanFactoryImpl extends ListableBeanFactoryImpl {
public JsonBeanFactoryImpl(String filePath) {
this.loadBeanDefinitions(filePath);
}
public JsonBeanFactoryImpl(String filePath, BeanFactory parentBeanFactory) {
super(parentBeanFactory);
this.loadBeanDefinitions(filePath);
}
private void loadBeanDefinitions(String filePath) {
String json = FileUtil.readUtf8String(filePath);
Map<String, Object> configMap = JsonUtils.toMap(json, String.class, Object.class);
List<Map<String, String>> beanDefinitionList = (List<Map<String, String>>) configMap.get("beans");
if (ObjectUtil.isNotEmpty(beanDefinitionList)) {
for (Map<String, String> map : beanDefinitionList) {
BeanDefinition bd = BeanUtil.mapToBeanIgnoreCase(map, DefaultBeanDefinition.class, true);
super.registerBeanDefinition(bd.getName(), bd);
}
}
// 读取包扫描路径
List<String> scanPackageNames = (List<String>) configMap.get("componentScanPackages");
if (ObjectUtil.isNotEmpty(scanPackageNames)) {
for (String packageName : scanPackageNames) {
Set<Class<?>> classes = ClassUtil.scanPackage(packageName);
for (Class<?> clazz : classes) {
// 判断是否具有 @Component 注解,并且本身不是注解
Component component = AnnotationUtil.getAnnotation(clazz, Component.class);
if (ObjectUtil.isNotNull(component) && !clazz.isAnnotation()) {
DefaultBeanDefinition bd = new DefaultBeanDefinition();
String beanName = StrUtil.isNotBlank(component.value()) ? component.value() : StrUtil.lowerFirst(clazz.getSimpleName());
bd.setName(beanName);
bd.setClassName(clazz.getName());
// TODO: 2020/4/18 参数列表
super.registerBeanDefinition(beanName, bd);
}
}
}
}
// 向 beanPostProcessors 中添加后置处理器
for (BeanPostProcessor beanPostProcessor : super.getBeansOfType(BeanPostProcessor.class).values()) {
super.addBeanPostProcessor(beanPostProcessor);
}
}
}
使用 BeanDefinitionRegistryPostProcessor 实现对配置类中 @Bean 注解的扫描
1、@Bean
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Bean {
/**
* 组件名称
*/
String value() default "";
/**
* 初始化方法
*/
String initMethod() default "";
/**
* 销毁方法
*/
String destroyMethod() default "";
}
2、新增 BeanDefinitionRegistry#registerBeanDefinition
public interface BeanDefinitionRegistry {
/**
* 注册 bd 到 bf
*/
void registerBeanDefinition(String name, BeanDefinition beanDefinition);
/**
* 根据 bdName 获取 bd
*/
BeanDefinition getBeanDefinition(String name);
}
3、ConfigurationClassPostProcessor
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
ListableBeanFactory bf = (ListableBeanFactory) registry;
for (String bdName : bf.getBeanDefinitionNames()) {
BeanDefinition classBeanDefinition = registry.getBeanDefinition(bdName);
String className = classBeanDefinition.getClassName();
Class<?> clazz = ReflectUtils.getType(className);
// 找到类上携带 @Configuration 的
Configuration configuration = AnnotationUtil.getAnnotation(clazz, Configuration.class);
if (ObjectUtil.isNotEmpty(configuration)) {
// 循环找方法中包含 @Bean 注解的
for (Method method : clazz.getMethods()) {
if (method.isAnnotationPresent(Bean.class)) {
BeanDefinition bdDef = new DefaultBeanDefinition();
Bean bean = method.getAnnotation(Bean.class);
String beanName = ObjectUtil.isNotEmpty(bean.value()) ? bean.value() : method.getName();
bdDef.setName(beanName);
bdDef.setFactoryBean(classBeanDefinition.getName());
bdDef.setFactoryMethod(method.getName());
bdDef.setInitMethod(bean.initMethod());
bdDef.setDestroyMethod(bean.destroyMethod());
// TODO: 2020/4/18 属性列表
registry.registerBeanDefinition(beanName, bdDef);
}
}
}
}
}
}
Spring 5.0
怎么放进去的
然后调用了这个方法
工厂方法怎么执行的
这部分我在 xml 文件配置工厂方法那里没有讲,因为我觉得 Spring 还是比较清晰的。