容器:IOC
要自己手写实现@Bean注解和@Autowired注解,其实我们就是简单实现一下Spring Ioc
所以,我们先简单了解一下IOC
IOC 是 Inversion of Control 的简写,译为“控制反转”
*创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方*,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。
Spring通过IOC容器来管理所有对象的实例化和初始化。
如果想要深入研究IOC就请自行百度,这里就不细说了。
操作
实现@Be注解(仿@Bean)
@Bean注解的作用就是将目标对象放入容器中,交由spring来管理
实现思路:
1.我们肯定是通过ApplicationContext.getBean()来获取对象实例,所以我们得仿写这样一个接口,实现这个getBean()方法
2.扫描所有文件,看哪些类上有@Be
3.将有@Be标记的类放入一个Map中(spring容器底层也是一个Map)
public class ApplicationContextSubImpl implements ApplicationContextSub {
private static String rootPath;
// 仿spring,创建一个map用于存放Bean对象
private static HashMap<Class, Object> beanFactoryJoggle = new HashMap<>();
@Override
public Object getBean(Class clazz) {
return beanFactoryJoggle.get(clazz);
}
// 设置包扫描规则
// 传递包路径。看当前包下哪些类有@Be注解
public ApplicationContextSubImpl(String basePackage){
Enumeration<URL> urls = null;
try {
// 将"."转为“/"
String packagePath = basePackage.replaceAll("\\.", "\\\\");
// 获取所有包的绝对路径
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 (IOException e) {
e.printStackTrace();
}
}
public static void loadBean(File file){
// 1.判断当前是否是文件夹
if(file.isDirectory()){//true代表是文件夹
// 2.获取文件夹的所有内容
File[] files = file.listFiles();
// 3.判断文件夹里是否为空
if(files.length==0||files==null){
return;
}
// 4.如果文件夹不为空,遍历文件夹内容
for (File afile:files){
// 4.1.如果文件夹中还有文件夹,递归遍历,直到所有的都是file对象都是文件
if(afile.isDirectory()){
loadBean(afile);
}else {
// 4.2.得到包路径+类名称部分
String pathWithClass = afile.getAbsolutePath().substring(rootPath.length() - 1);
// 4.3.判断当前文件是否是.class文件
if (pathWithClass.contains(".class")) {
// 4.4.如果是.class文件,把"/"替换为"."去掉.class
String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
// 实例化对象
try {
Class<?> aClass = Class.forName(fullName);
// 判断是否是接口类
if(!aClass.isInterface()){
// 4.5.判断类上是否有@Bean注解
Be bean = aClass.getAnnotation(Be.class);
if(bean!=null){
// 实例化对象
Object instance = aClass.newInstance();
// 判断该类有没有接口
if(aClass.getInterfaces().length>0){
//如果有接口把接口的class当成key,实例对象当成value
System.out.println("正在加载【"+ aClass.getInterfaces()[0] +"】,实例对象是:" + instance.getClass().getName());
beanFactoryJoggle.put(aClass.getInterfaces()[0], instance);
}else {
//如果没有接口把自己的class当成key,实例对象当成value
System.out.println("正在加载【"+ aClass.getName() +"】,实例对象是:" + instance.getClass().getName());
beanFactoryJoggle.put(aClass, instance);
}
}
}
}catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
}
}
}
实现@Auto注解(仿Auto)
思路:
遍历map中的所有对象
遍历对象中所以属性
判断属性上哪些有@Auto注解
属性注入