首先创建两个注解一个创建对象,一个完成属性注入,然后创建bean容器接口(这里名字记为Application)定义一个方法返回对象,最后实现bean容器接口完成两个方法(1.返回对象 2.根据包规则加载bean)
(两个注解就不展示了)
//首先在实现Application的类中创建map集合来装bean对象,再实现接口方法
private Map<Class,Object> beanFactory = new HashMap<>();
@Override
public Object getBean(Class c1){
return beanFactory.get(c1)
}
然后创建有参构造,传递包路径,设置包扫描规则
根据递归判断当前包及其子包中哪个类有注解,把这个类通过反射实例化
public AnnotationApplicationContext(String beanPackage){
try{
//1.把.替换成\
Sting packagePath = basePackage.replaceAll("\\.", "\\\\");
//2.获取包的绝对路径,会返回一个枚举类
Eumeration<URL> urls = Thread.currentTread().getContextClassLoader(packagePath);
While(urls.hasMoreElements()) {
URL url = urls.nextElement();
String filePath = URLDecoder.decode(url,].getfile(),"utf-8");
//进行包扫描
LoadBean(new File(filePath));
}
}catch(Exception e){
throw new RuntimeException(e);
}
//属性注入(这里将@Di为注入注解)
loadDi();
}
这里为了后续获得包的名称方便,对包进行截取
private rootPath;
//在包扫描上面加上
rootPath = filePath.substring(0,filePath.length() - packagePath.length());
包扫描过程,实例化
过程:
1 判断当前是否是文件夹
2 获取文件夹里面所有内容
3 判断文件夹里面为空,直接返回
4 如果文件夹里面不为空,遍历文件夹所有内容
4.1 遍历得到每个File对象,继续判断,如果还是文件,递归
4.2 遍历得到File对象不是文件夹,那就是文件
4.3 得到包路径+类名称部分
4.4 判断当前文件类型是否.class
4.5 如果是.class类型,把路径\替换成. 把.class去掉
4.6 判断类上面是否有注解 ,如果有实例化过程
4.7 把对象实例化之后,放到map集合beanFactory
private void loadBean(File file) throws Exception{
//1 判断当前是否是文件夹
if(file.isDirectory()){
//2 获取文件夹里面所有内容
File[] childrenFiles = file.listFiles();
//3 判断文件夹里面为空,直接返回
if(childrenFiles == null || childrenFiles.length == 0){
retrun;
}
//4 如果文件夹里面不为空,遍历文件夹所有内容
//4.1 遍历得到每个File对象,继续判断,如果还是文件,递归
if(child.isDirectory()){
loadBean(child);
}else{
//4.2 遍历得到File对象不是文件夹,那就是文件
//4.3 得到包路径+类名称部分
String pathWithClass = child.getAbsolutePath().substring(rootPath
//4.4 判断当前文件类型是否.class
if(pathWithClass.contains(".class")){
//4.5 如果是.class类型,把路径\替换成. 把.class去掉
String allName = pathWithClass.replaceAll("\\\\",".")
.replace(".class","");
//4.6 判断类上面是否有注解 ,如果有实例化过程
//4.6.1 获取类的class
Class<?> c1 = Class.forName(allName);
//4.6.2 判断不是接口
if(!c1.isInterface()){
//4.6.3 判断类上面是否有注解 (假如是@Bean)
Bean annotation=c1.getAnnotation(Bean.class);
if(annotation != null){
//4.6.4 实例化
Object instance = c1.getConstructor().newInstance();
//4.7 把对象实例化之后,放到map集台beanFactory
//4.7.1 判断当前类如果有接口,让接口class作为map的key
if(c1.getInterfaces().length>0){
beanFactory.put(c1.getInterfaces()[0],instance);
}else{
beanFactory.put(c1,instance);
}
}
}
}
}
}
}
属性注入
实例化对象在beanFactory的map集合里面
1 遍历beanFactory的map集合
2 获取map集合每个对象(value),获取到每个对象属性
3 遍历得到每个对象属性数组,得到每个属性
4 判断属性上面是有@Di注解
如果私有属性,设置可以设置值
5 如果有@Di注解,把对象进行注入
private void loadDi(){
//实例化对象在beanFactory的map集合里面
//1 遍历beanFactory的map集台
Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();
for(Map.Entry<class,object>entry:entries){
//2 获取map集合每个对象(value),每个对象属性获取到
Object obj = entry.getvalue();
//获取对象Class
Class<?>c1 = obj.getclass();
//获取每个对象属性
Field[] declaredFields = c1.getDeclaredFields();
//3 遍历得到每个对象属性数组,得到每个属性
for(Field field:declaredFields){
//4 判断属性上面是否有@Di注解
Di annotation = field.getAnnotation(Di.class);
if(annotation != null){
//如果私有属性,设置可以设置值
field.setAccessible(true);
//5 如果有@Di注解,把对象进行设置(注入)
try{
field.set(obj,beanFactory.get(field.getType()));
}catch(IllegalAccessException e){
throw new RuntimeException(e);
}
}
}
}
}