WrapClass Enrichment 处理链与各种注解 — 过滤和解析 (2.2)
本章代码对应的Tag 为:v1.1.0
前置说明: IOC的总体流程
- 扫包,获取被目标注解标注的Class
- 如 @Service 、@Configuration等
- 分析上一步得到的Class
- 获取类上注解的相关的值
- 例如,获取@Service(isSinglet = true) 中是否是单例的布尔值
- 获取该类(以及父类)中被 目标注解标注的Field
- 如 @Autowired 、 @Value等
- 获取类上注解的相关的值
- 使用反射,并依据上述获取到的所有Class、注解信息实现 getBean系列方法
- 按BeanId获取
- 按class name获取
- 按某个接口,批量获取
注:以上所有注解,只有名称沿用了spring ioc中的命名。所以,发现有用法与你平时接触的不一致时,请不要惊讶。
本来打算一篇文章写完的,不过写着写着发现,有点长,就决定分几篇文章慢慢写了,这一篇,就当作WrapClass处理链的开篇吧。
WrapClass Enrichment的目的
- 找出所有需要被框架管理的Class,也就是那些被@Service、@Configuratoin标注的类
- 找出这些Bean里面,有哪些Field需要被自动注入
- 找出Configuration类注解中的的配置文件名称、路径
- 找出Configuration类中,有那些Field是被Value标注的,以及Value的取值表达式
创建WrapClass Enrichment Chian
package zm.ioc.classCollector;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import zm.ioc.pojo.WrapClass;
public class ClassEnrichmentChian {
// 后面再回来初始化这个List
private List<ClassEnrichment> enrichmentChian;
private ClassEnrichmentChian(){
}
public Set<WrapClass> doEnrichment(Collection<Class<?>> clazzes){
Set<WrapClass> wrapClasses = new HashSet<>();
if( CollectionUtils.isEmpty(clazzes)){
return wrapClasses;
}
//遍历class对象,每一个对象都要被处理链处理一遍
for(Class<?> clazz : clazzes){
WrapClass wrapClass = WrapClass.build(clazz);
for(ClassEnrichment classEnrichment : this.enrichmentChian){
classEnrichment.enrichment(wrapClass, wrapClasses);
}
}
return wrapClasses;
}
}
处理链的核心流程已经写完了,后续就是按需实现 ClassEnrichment 子类了。
注意,后面在回过来 List<ClassEnrichment> enrichmentChian 这个列表
处理链中的第一个环节,过滤
说白了,就是检查每个class对象是否有@Service注解.
下面看代码(省略了核心代码之外的内容,完整代码请注意看本文开头标记的gitee中的代码)
public class BeanClassFilter implements ClassEnrichment {
private static final Logger log = Logger.getLogger(BeanClassFilter.class);
public static final Set<Class<? extends Annotation>> BEAN_ANNOTATIONS = new HashSet<>();
static{
BEAN_ANNOTATIONS.add(Service.class);
log.debug(String.format("The Initialization of Annotations "+
"of IOC Beans finished.[%s]", BEAN_ANNOTATIONS));
}
@Override
public boolean enrich(WrapClass wrapClass, Set<WrapClass> wrapClassSet) {
boolean shouldContinue = false;
BeanDefinitionInfo beanIdentifyInfo = this.findBeanDefinitionInfo(wrapClass);
if(beanIdentifyInfo == null || !beanIdentifyInfo.isBeanClass){
shouldContinue = false;
}else{
wrapClass.setBeanId(beanIdentifyInfo.getBeanId());
wrapClass.setSinglet(beanIdentifyInfo.isSinglet());
wrapClassSet.add(wrapClass);
}
return shouldContinue;
}
}
处理链中的第一个环节,寻找@AutoWired注解的Field
原理同上,都是检查注解,看代码
package zm.ioc.classCollector;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import zm.ioc.annotation.AutoWired;
import zm.ioc.pojo.WrapClass;
import zm.ioc.pojo.WrapField;
public class AutoWiredFieldEnrichment implements ClassEnrichment{
private static final Logger log = Logger.getLogger(AutoWiredFieldEnrichment.class);
public static Set<Class<? extends Annotation>> AUTOWIRED_ANNOTATIONS;
static{
AUTOWIRED_ANNOTATIONS = new HashSet<>();
AUTOWIRED_ANNOTATIONS.add(AutoWired.class);
}
@Override
public boolean enrich(WrapClass wrapClass, Set<WrapClass> wrapClassSet) {
// 其他非主要逻辑: 略
for(Field field : fields){
//获取需要自动注入的注解
Annotation iocAnno = this.getIocAnno(field,AUTOWIRED_ANNOTATIONS);
if( iocAnno == null){
continue;
}
WrapField autoWiredField = new WrapField(field, wrapClass);
autoWiredField.setIocAnno(iocAnno);
wrapClass.addAutoWiredField(autoWiredField);
}
return true;
}
}
测试一下
public static void main(String[] args) {
ClassCollector classCollector = ClassCollector.CLASS_COLLECTOR;
// URL xmlpath =
String rootPath = System.getProperty("user.dir") + "/target/classes/";
log.info("Class collect start ! Root path is " + rootPath);
Set<Class<?>> clazzes = classCollector.collect(rootPath);
Set<WrapClass> wrapClasses = ClassEnrichmentChian.doEnrichment(clazzes);
wrapClasses.stream().forEach((c)->log.info(c));
}
测试结果如下:
[23/02/12 21:31:08:060]-zm.ioc.classCollector.ClassEnrichmentTest:19:WrapClass [beanId=, isSinglet=false, originClass=class zm.ioc.demo.bean.DemoService, autoWriedFields=[zm.ioc.pojo.WrapField@515f550a]]
[23/02/12 21:31:08:062]-zm.ioc.classCollector.ClassEnrichmentTest:19:WrapClass [beanId=, isSinglet=false, originClass=class zm.ioc.demo.bean.BeanA, autoWriedFields=[]]
注意看第一行日志中的 autoWiredFields,已正确找到。