手写IOC容器
仿写IOC容器前提,首先得了解IOC容器执行原理,如果对IOC容器没有做深入了解,可点击下方链接进行学习。
IOC执行原理:https://blog.csdn.net/qq_42477665/article/details/119085286?spm=1001.2014.3001.5502
IOC容器执行流程
编写流程如下:
序号 | 内容 |
---|---|
1 | 编写自定义的AnnotationConfigApplicationContext 类,解析某包下所有的class类 |
2 | 将带有@Component 注解的class 封装成BeanDefinition 对象,格式k->beanName v->class 类,最终将BeanDefinition 存放入Set 集合中 |
3 | 遍历Set 集合,从BeanDefinition 对象获取class类进行实例化,并填充属性值 |
4 | 将使用了@Autowired 注解的类进行自动装配 |
5 | 最终得到了完整对象 |
编写IOC容器所设计的核心类如下表
序号 | 类名 | 说明 |
---|---|---|
1 | MyAnnotationConfigApplicationContext | AnnotationConfigApplicationContext 容器 |
2 | MyTools | 解析获取包下所有的类的一个工具类 |
3 | BeanDefinition | 封装beanName 与class 类属性 |
4 | Component | 仿照Component 注解 |
5 | Value | 仿照Value 注解 |
6 | Autowired | 仿照Autowired 注解 |
7 | Qualifier | 仿照Qualifier 注解 |
MyAnnotationConfigApplicationContext
package com.zmy.example.custom;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class MyAnnotationConfigApplicationContext {
/**
* Bean容器
*/
private Map<String, Object> beanMap = new ConcurrentHashMap<>();
/**
* BeanName集合
*/
private List<String> beanNames = new ArrayList<>();
public MyAnnotationConfigApplicationContext(String basePack){
//遍历包,找到目标类(原材料)
Set<BeanDefinition> beanDefinitions = findBeanDefinitions(basePack);
//根据原材料创建bean
createBean(beanDefinitions);
//自动装载
autowiredBean(beanDefinitions);
}
/**
* 将class类封装成BeanDefinition
* 格式:name->beanName class->class类
* @param basePack
* @return BeanDefinition集合
*/
public Set<BeanDefinition> findBeanDefinitions(String basePack){
//获取basePack包下所有的class类
Set<Class<?>> classes = MyTools.getClasses(basePack);
Iterator<Class<?>> iterator = classes.iterator();
Set<BeanDefinition> beanDefinitions = new HashSet<>();
//遍历所有的class类
while (iterator.hasNext()){
//遍历这些类,找到添加了Component注解的类
Class<?> aClass = iterator.next();
Component component = aClass.getAnnotation(Component.class);
//如果使用了Component注解,那么可能存在注解value值不为空
if (component != null){
String beanName;
if (component.value() != null && !"".equals(component.value())){
beanName = component.value();
}else {
//获取类名首字母小写
String className = aClass.getName().replaceAll(aClass.getPackage().getName() + ".", "");
beanName = className.substring(0, 1).toLowerCase()+className.substring(1);
}
//封装成BeanDefinition对象
beanDefinitions.add(new BeanDefinition(beanName, aClass));
}
}
return beanDefinitions;
}
/**
* 实例化对象并填充属性
* @param beanDefinitions
*/
public void createBean(Set<BeanDefinition> beanDefinitions){
Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
//遍历beanDefinitions集合
while (iterator.hasNext()){
//获取BeanDefinition
BeanDefinition beanDefinition = iterator.next();
Class clazz = beanDefinition.getBeanClass();
String beanName = beanDefinition.getBeanName();
try {
//通过反射实例化对象
Object object = clazz.newInstance();
//遍历object对象所有的属性,寻找使用Value注解的属性并填充属性值
Field[] fields = clazz.getDeclaredFields();
for (Field declaredField : fields) {
//判断是否使用Value注解,使用则给属性进行填充值
Value valueAnnotation = declaredField.getAnnotation(Value.class);
if(valueAnnotation!=null){
String value = valueAnnotation.value();
String fieldName = declaredField.getName();
String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
Method method = clazz.getMethod(methodName,declaredField.getType());
//完成数据类型转换
Object val = null;
switch (declaredField.getType().getName()){
case "int":
val = Integer.parseInt(value);
break;
case "java.lang.Integer":
val = Integer.parseInt(value);
break;
case "java.lang.String":
val = value;
break;
case "java.lang.Float":
val = Float.parseFloat(value);
break;
}
//给属性进行填充值
method.invoke(object, val);
}
beanMap.put(beanName, object);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
/**
* 自动装配填充
* @param beanDefinitions
*/
private void autowiredBean(Set<BeanDefinition> beanDefinitions){
Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
while (iterator.hasNext()){
BeanDefinition beanDefinition = iterator.next();
String beanName = beanDefinition.getBeanName();
Class clazz = beanDefinition.getBeanClass();
//遍历clazz类所有的字段属性,寻找使用了Autowired与Qualifier注解的属性,并填充属性值
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
//判断是否使用了Autowired与Qualifier注解
Autowired autowired = field.getAnnotation(Autowired.class);
if (autowired != null){
try {
Qualifier qualifier = field.getAnnotation(Qualifier.class);
Object val = null;
if (qualifier != null){
//beanName
String name = qualifier.value();
//从Bean容器中获取bean对象
val = beanMap.get(name);
}else {
val = beanMap.get(field.getName());
}
//属性名称
String fieldName = field.getName();
//方法名称
String methodName = "set"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
Object object = beanMap.get(beanName);
Method method = clazz.getMethod(methodName, field.getType());
//进行属性填充
method.invoke(object,val);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
public Object getBean(String beanName){
return beanMap.get(beanName);
}
public String[] getBeanDefinitionNames(){
return beanNames.toArray(new String[0]);
}
public Integer getBeanDefinitionCount(){
return beanNames.size();
}
}
MyTools
package com.zmy.example.custom;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class MyTools {
public static Set<Class<?>> getClasses(String pack) {
// 第一个class类的集合
Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
// 是否循环迭代
boolean recursive = true;
// 获取包的名字 并进行替换
String packageName = pack;
String packageDirName = packageName.replace('.', '/');
// 定义一个枚举的集合 并进行循环来处理这个目录下的things
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
// 循环迭代下去
while (dirs.hasMoreElements()) {
// 获取下一个元素
URL url = dirs.nextElement();
// 得到协议的名称
String protocol = url.getProtocol();
// 如果是以文件的形式保存在服务器上
if ("file".equals(protocol)) {
// 获取包的物理路径
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
// 以文件的方式扫描整个包下的文件 并添加到集合中
findClassesInPackageByFile(packageName, filePath, recursive, classes);
} else if ("jar".equals(protocol)) {
// 如果是jar包文件
// 定义一个JarFile
System.out.println("jar类型的扫描");
JarFile jar;
try {
// 获取jar
jar = ((JarURLConnection) url.openConnection()).getJarFile();
// 从此jar包 得到一个枚举类
Enumeration<JarEntry> entries = jar.entries();
findClassesInPackageByJar(packageName, entries, packageDirName, recursive, classes);
} catch (IOException e) {
// log.error("在扫描用户定义视图时从jar包获取文件出错");
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
private static void findClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries, String packageDirName, final boolean recursive, Set<Class<?>> classes) {
// 同样的进行循环迭代
while (entries.hasMoreElements()) {
// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
JarEntry entry = entries.nextElement();
String name = entry.getName();
// 如果是以/开头的
if (name.charAt(0) == '/') {
// 获取后面的字符串
name = name.substring(1);
}
// 如果前半部分和定义的包名相同
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
// 如果以"/"结尾 是一个包
if (idx != -1) {
// 获取包名 把"/"替换成"."
packageName = name.substring(0, idx).replace('/', '.');
}
// 如果可以迭代下去 并且是一个包
if ((idx != -1) || recursive) {
// 如果是一个.class文件 而且不是目录
if (name.endsWith(".class") && !entry.isDirectory()) {
// 去掉后面的".class" 获取真正的类名
String className = name.substring(packageName.length() + 1, name.length() - 6);
try {
// 添加到classes
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// .error("添加用户自定义视图类错误 找不到此类的.class文件");
e.printStackTrace();
}
}
}
}
}
}
private static void findClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {
// 获取此包的目录 建立一个File
File dir = new File(packagePath);
// 如果不存在或者 也不是目录就直接返回
if (!dir.exists() || !dir.isDirectory()) {
// log.warn("用户定义包名 " + packageName + " 下没有任何文件");
return;
}
// 如果存在 就获取包下的所有文件 包括目录
File[] dirfiles = dir.listFiles(new FileFilter() {
// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
@Override
public boolean accept(File file) {
return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
}
});
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findClassesInPackageByFile(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));
// 这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// log.error("添加用户自定义视图类错误 找不到此类的.class文件");
e.printStackTrace();
}
}
}
}
}
BeanDefinition
package com.zmy.example.custom;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class BeanDefinition {
private String beanName;
private Class beanClass;
}
Component
package com.zmy.example.custom;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
String value() default "";
}
Value
package com.zmy.example.custom;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value() default "";
}
Autowired
package com.zmy.example.custom;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
}
Qualifier
package com.zmy.example.custom;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Qualifier {
String value() default "";
}
原文始发于微信公众号(行走318川藏线):手写IOC容器
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/20921.html