WrapClass Enrichment 处理链与各种注解 — 开篇 (2.1)
本章代码对应的Tag 为:待定
前置说明: 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的取值表达式
先来实现几个注解
- @Service
- @AutoWired
- @Configruation
- @Value
为了缩减每一篇文章的长度,本章只实现前两个。Service、AutoWired为两个基本注解。
后续会单独写一章,来实现配置文件的自动注入,即:Configuration、Value这一对注解。
@Service注解
package zm.ioc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
/**
* Bean ID,当name为空时,使用class的全名作为BeanID
* @return
*/
String name() default "";
//指明是否时使用单例,默认不是单例
boolean isSinglet() default false;
}
@AutoWired注解
package zm.ioc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
}
最后,再创建两个测试用的Bean以及一个测试类
package zm.ioc.bean;
import org.apache.log4j.Logger;
import zm.ioc.annotation.AutoWired;
import zm.ioc.annotation.Service;
@Service
public class TestBeanA {
private static final Logger log = Logger.getLogger(TestBeanA.class);
@AutoWired
private TestBeanB testBeanB;
public void say(){
log.info("I'm Class A !!!");
testBeanB.say();
}
}
package zm.ioc.bean;
import org.apache.log4j.Logger;
import zm.ioc.annotation.Service;
@Service
public class TestBeanB {
private static final Logger log = Logger.getLogger(TestBeanB.class);
public void say(){
log.info("I'm Class B !!!");
}
}
特别注意!!!! 不熟悉java注解的读者,建议网上去查看下注解中 @Retention(RetentionPolicy.RUNTIME) 的说明 RetentionPolicy有多种类型,不在这里一一赘述了,当时有一点要明确,如果不是RUNTIME,那你可能会在自己写代码时发现,怎么都无法通过反射获取到该注解,你会非常郁闷!!
WrapClass Enrichment 处理链的实现 (核心)
WrapClass Enrichment 的核心工作目标:进一步的分析处理之前收集到的Class对象
包括:过滤掉非目标Class对象,分析各种注解,记录需要自动注入的Field
所以,上一步是“广撒网”,这一步是“挑重点”。
总结下: 就是要将上面被@Service标注的TestBeanA 、TestBeanB找出来,并且记录下TestBeanA里面,有一个叫做testBeanB的Field被 @AutoWired标注了
基本思路:
- 遍历所有Class对象
- 获取所有Class上的注解,并判断是否是目标Class(即,被@Service等注解标记的Class对象)
- 获取目标Class的所有Field上的注解,并判断是否需要进行自动注入
- 将上述结果使用WrapClass对象封装起来
- 额外步骤,在创建WrapClass的过程中,以Class对象为key,Set为Value记录下某个class的所有子类
其中第五步是为了实现 <T> List<T> getBeansByType(Class<T> superClass) 方法,通过某个父对象类,获取所有子类Bean对象的方法
先创建处理链的接口(其中WrapClass就只一个简单的包装类,等用到时在做介绍)
package zm.ioc.classCollector;
import java.util.Set;
import zm.ioc.ioc.pojo.WrapClass;
public interface ClassEnrichment {
/**
*
* @param wrapClass 等待被处理的对象
* @param wrapClassSet 处理完后,用于收集目标对象的容器
* @return true: 决定是否需要执行处理链的下一个处理器
*/
boolean enrich(WrapClass wrapClass,Set<WrapClass> wrapClassSet);
}
最后,只要去按需要,实现几个ClassEnrichment的子类并组成一个处理链就完工了,
你看,是不是很简单啊。(当然时开玩笑的啊,哈哈哈)