手写SpringIOC
Secular and rational guide you forward, progress is always full of pain.
talk is cheap, show me the code,make a better result.
目录
概述
Spring在后端基本完成了大一统,前面已经讲述了DB,JDBC,连接池组件,缓存,ORM组件,以及SpringMVC框架。如下我们将重点带来Spring系列框架组件的简要实现。
首先我们先考虑Spring,其中最重要的就是IOC和AOP。
需求:
需求整理如下:
1.由Spring来负责控制对象的生命周期和对象之间的关系。
2.将对象的控制权交给IOC容器,
3.所有的依赖关系被统一集中的管理起来了,清晰明了
4.每个类只需要关注直接的业务逻辑
设计思路
为了方面也为了规范,我们使用UML工具啦。
实现思路分析
1.扫描包下的类
取得某个接口下所有实现这个接口的类。以文件的形式来获取包下的所有Class
2.如果类存在注入bean所需的注解 将bean放入bean容器
根据beanid获取对应的bean,初始化依赖的属性
3.查看beanA中的属性 如果属性需要注入 就在bean容器中找到对应的beanB 并且注入到beanA的属性中
查找包路径下面所有添加注解的类 @IocService
拓展Demo实现
相关代码如下:
public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,
List<Class<?>> classes) {
// 获取此包的目录 建立一个File
File dir = new File(packagePath);
// 如果不存在或者 也不是目录就直接返回
if (!dir.exists() || !dir.isDirectory()) {
return;
}
// 如果存在 就获取包下的所有文件 包括目录
File[] dirfiles = dir.listFiles(new FileFilter() {
// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
public boolean accept(File file) {
return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
}
});
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,
classes);
} else {
// 如果是java类文件 去掉后面的.class 只留下类名
String className = file.getName().substring(0, file.getName().length() - 6);
try {
// 添加到集合中去
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
2.将bean放入bean容器
public ConcurrentHashMap<String,Object>initBean(List<Class>classes) throws IllegalAccessException,InstantiationException{
ConcurrentHashMap<String,Object> map = new ConcurrentHashMap<String, Object>();
String beanId="";
for(Class clazz :classes){
Object object = clazz.newInstance();
IocService annotation =(IocService)clazz.getDeclaredAnnotation(IocService.class);
if (annotation!=null){
//如果定义了name属性 以实现的name属性为主否则以默认的规则为主
String value = annotation.name();
if (value!=null && !value.equals("")){
beanId = value;
}
else {
beanId = toLowerCaseFirstOne(clazz.getSimpleName());
}
}
//存储值
map.put(beanId,object);
}
return map;
}
3.属性注入
/**
* 初始化依赖的属性
* @param object
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private void initAttribute(Object object)throws Exception{
//获取object的所有类型
Class<? extends Object> classinfo = object.getClass();
//获取所有的属性字段
Field[] fields = classinfo.getDeclaredFields();
//遍历所有字段
for(Field field : fields){
//查找字段上有依赖的注解
boolean falg = field.isAnnotationPresent(IocResource.class);
if (falg){
IocResource iocResource = field.getAnnotation(IocResource.class);
if (iocResource!=null){
//获取属性的beanid
String beanId = field.getName();
//获取对应的object
Object attrObject = getBean(beanId);
if (attrObject!=null){
//访问私有字段
field.setAccessible(true);
//赋值
field.set(object,attrObject);
continue;
}
}
}
}
}
实验效果:
分析:
1.
1.首先会加载实现类路劲
2.接着会获取bean
3.初始化bean
4.初始化依赖
小结:
主要讲述了SpringIOC原理和简单实现,里面有许多不足,请大家指正~
参考资料和推荐阅读
欢迎阅读,各位老铁,如果对你有帮助,点个赞加个关注呗!~