-
控制反转是一种思想。
-
控制反转是为了降低程序耦合度,提高程序扩展力。
-
控制反转,反转的是什么?
-
- 将对象的创建权利交出去,交给第三方容器负责。
- 将对象和对象之间关系的维护权交出去,交给第三方容器负责。
自己写的 ApplicationContext 主要提供getBean方法
public interface ApplicationContext {
Object getBean(Class clazz);
}
然后创建实现类,原spring中的IOC就是用MAP来存储对象并且返回的,则我们也创建map来存储对象,主要就是应用FIle类和反射的思想,从类的字节码一步一步把对象构建出来
public class AnnotationApplicationContext implements ApplicationContext{
//创建map集合,放bean对象 模拟IOC对象的存储方式
private Map<Class,Object> beanFactory = new HashMap<>();
private static String rootPath;
//返回对象
@Override
public Object getBean(Class clazz) {
return beanFactory.get(clazz);
}
//设置包扫描规则
//当前包及其子包,那个类有@Bean注解,把这个类通过反射实例化
public AnnotationApplicationContext(String basePackage){
//basePackage = com.atguigu 我们需要把·换位斜杠,这样才符合路径规则
try {
String packagePath = basePackage.replaceAll("\\.","\\\\");
//通过该路径获得相应的绝对路径
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
while(urls.hasMoreElements()){
URL url = urls.nextElement();
String filePath = URLDecoder.decode(url.getFile(), "utf-8");
//获取绝对路径后,由于出了包可能会不同,但包前面的绝对路径都是相同的,则可以截取出来反复使用
rootPath = filePath.substring(0, filePath.length() - packagePath.length());
//包扫描
loadBean(new File(filePath));
}
}catch (Exception e){
throw new RuntimeException(e);
}
}
//包扫描的过程 实例化
private void loadBean(File file) throws Exception {
//1 判断当前是否文件夹
if(file.isDirectory()){
//2 获取文件夹里面所有内容
File[] childrenFiles = file.listFiles();
//3 判断文件夹里面为空,直接返回
if(childrenFiles == null || childrenFiles.length == 0){
return;
}
//4 如果文件里面不为空,遍历文件夹所有内容
for(File child : childrenFiles){
//4.1 遍历得到每个File对象,继续判断,如果还是文件夹,递归
if(child.isDirectory()){
loadBean(child);
}else{
//4.2 遍历得到的File对象不是文件夹,是文件,
//4.3 得到包路径+类名称部分 (字符串截取)
String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
//4.4 判断当前文件类型是否.class
if(pathWithClass.contains(".class")){
//4.5 如果是.class类型,把路径\替换成. 把.class去掉
String allName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
//com.atguigu.service.UserServiceImpl
//4.6 判断类型上面是否有注解 @Bean, 如果有实例化过程
//4.6.1 获取类的Class对象
Class<?> clazz = Class.forName(allName);
//4.6.2 判断不是接口
if(!clazz.isInterface()){
//4.6.3 判断上面是否有@Bean
Bean annotation = clazz.getAnnotation(Bean.class);
if(annotation != null){
//4.6.4 实例化
Object instance = clazz.getConstructor().newInstance();
//4.7 把对象实例化之后,放到map集合beanFactory
//4.7.1 当前类如果实现类接口,让接口class作为map的key
if(clazz.getInterfaces().length>0){
beanFactory.put(clazz.getInterfaces()[0],instance);
}else{
beanFactory.put(clazz,instance);
}
}
}
}
}
}
}
}
}