手动实现一个简单的Spring IoC容器,管理Bean
注:如果还没熟悉Java 反射的,建议先看一下:【Java高级】反射学习二——反射
1、方式一:简单版,初始化时,手动new 再设置进hashMap
- key:接口的class
- value:接口对应的实现类的实例
测试:直接通过key名从HashMap获取
2、方式二:改进版,通过配置文件+反射,初始化bean
配置文件内容:接口=实现类
通过类加载器读取配置文件内容,再反射实例化,设置进HashMap
3、方式三:注解+扫描 类路径下的所有文件(接口+实现类),反射实例化,放到一个HashMap 内存中 (IOC容器)
3.1 注解定义
自定义依赖注入 AutoWired注解
package com.xinzhi.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自动注入的注解
* @author zn
* @date 2020/4/2
**/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
}
自定义bean注解,只扫描标有该注解的类
package com.xinzhi.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author zn
* @date 2020/4/2
**/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
3.2 扫描文件解析注解,容器初始化
package com.xinzhi.reflect;
import com.xinzhi.Annotation.AutoWired;
import com.xinzhi.Annotation.Bean;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* @author zn
* @date 2020/4/2
**/
public class ApplicationContext<T> {
private HashMap<Class,Object> beanFactory = new HashMap<>();
private String filePath;
//获取容器的bean
public T getBean(Class clazz){
return (T)beanFactory.get(clazz);
}
//初始化容器:方式二,读取配置文件+反射
public void initContext(){
InputStream resource = ApplicationContext.class.getClassLoader()
.getResourceAsStream("config/bean.config");
Properties properties = new Properties();
try {
properties.load(resource);
Set<Object> keys = properties.keySet();
for (Object key : keys) {
beanFactory.put(Class.forName(key.toString()),
Class.forName(properties.getProperty(key.toString())).newInstance() );
}
} catch (Exception e) {
e.printStackTrace();
}
}
//初始化容器:方式三,扫描+反射
public void initContextByAnnotation() {
filePath = ApplicationContext.class.getClassLoader().getResource("").getFile();
//扫描加载类
loadOne(new File(filePath));
//属性注入
assembleObject();
}
//是不是给所有的字符赋值
private void assembleObject() {
for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){
//就是咱们放在容器的对象
Object obj = entry.getValue();
Class<?> aClass = obj.getClass();
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields){
AutoWired annotation = field.getAnnotation(AutoWired.class);
if( annotation != null ){
field.setAccessible(true);
try {
System.out.println("正在给【"+obj.getClass().getName()+"】属性【" + field.getName() + "】注入值【"+ beanFactory.get(field.getType()).getClass().getName() +"】");
field.set(obj,beanFactory.get(field.getType()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 加载一个文件夹下的类,递归
* @param fileParent
*/
private void loadOne(File fileParent) {
if (fileParent.isDirectory()) {
File[] childrenFiles = fileParent.listFiles();
if(childrenFiles == null || childrenFiles.length == 0){
return;
}
for (File child : childrenFiles) {
if (child.isDirectory()) {
//如果是个文件夹就继续调用该方法,使用了递归
loadOne(child);
} else {
//通过文件路径转变成全类名,第一步把绝对路径部分去掉
// D:\mytools
// com\xinzhi\dao\UserDao.class
String pathWithClass = child.getAbsolutePath().substring(filePath.length() - 1);
//选中class文件
if (pathWithClass.contains(".class")) {
// com.xinzhi.dao.UserDao
//去掉.class后缀,并且把 \ 替换成 .
String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
try {
Class<?> aClass = Class.forName(fullName);
//把非接口的类实例化放在map中
if(!aClass.isInterface()){
Bean annotation = aClass.getAnnotation(Bean.class);
if(annotation != null){
Object instance = aClass.newInstance();
//判断一下有没有接口
if(aClass.getInterfaces().length > 0) {
//如果有接口把接口的class当成key,实例对象当成value
System.out.println("正在加载【"+ aClass.getInterfaces()[0] +"】,实例对象是:" + instance.getClass().getName());
beanFactory.put(aClass.getInterfaces()[0], instance);
}else{
//如果有接口把自己的class当成key,实例对象当成value
System.out.println("正在加载【"+ aClass.getName() +"】,实例对象是:" + instance.getClass().getName());
beanFactory.put(aClass, instance);
}
}
}
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
}
}
}
}
链接:https://www.jianshu.com/p/881dff233d43
https://www.bilibili.com/video/BV1RA411t7bA?p=7
●阿里巴巴为什么能抗住90秒100亿?--服务端高并发分布式架构演进之路
●SpringCloud电商秒杀微服务-Redisson分布式锁方案
查看更多好文,进入公众号--撩我--往期精彩
一只 有深度 有灵魂 的公众号0.0