3.4 my spring bean工厂(IoC、DI)
- 加载类
- 解析类
- 获得类
3.4.0 分析
3.4.1 扫描指定包下的所有类
package com.czxy.bean;import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;public class MyBeanFactory {private static String classpath = new File(MyBeanFactory.class.getClassLoader().getResource("").getPath()).getPath();/*** 初始化方法* @param packageName*/public static void init(String packageName) {//1 扫描 指定包 下面的所有内容(接口、类)// 1.1 获得 指定包 所在的位置,以文件File形式File packageFile = packageToFile(packageName);// 1.2 根据 包的位置 获得所有的类List<String> classNameList = getAllClassName(packageFile);System.out.println(classNameList);//2 处理类}/*** com.czxy --> com/czxy* @param packageName* @return*/private static File packageToFile(String packageName) {return new File(classpath , packageName.replace(".", "/"));}/*** 获得指定包所有内容,如果是类* @param dir* @return*/private static List<String> getAllClassName(File dir) {List<String> list = new ArrayList<>();if(dir == null) {return list;}for(File file: Objects.requireNonNull(dir.listFiles())) {if(file.isFile()) {list.add(pathToClassName(file.getPath()));} else {List<String> subList = getAllClassName(file);list.addAll(subList);}}return list;}/**** @param path* @return A.B.C*/private static String pathToClassName(String path) {// 取消前缀String newPath = path.replace(classpath + "\\", "");if(newPath.endsWith(".class")) {//处理类String tempPath = newPath.replace("\\", ".");return tempPath.substring(0, tempPath.length() - 6);} else {return newPath;}}
}
在程序运行时,执行bean工厂初始化
3.4.2 创建bean实例(IoC)
Bean工厂
*
package com.czxy.bean;import com.czxy.annotation.MyMapper;
import com.czxy.annotation.MyRestController;
import com.czxy.annotation.MyService;
import com.czxy.boot.MybatisHandler;import java.io.File;
import java.lang.reflect.Proxy;
import java.util.*;public class MyBeanFactory {private static String classpath = new File(MyBeanFactory.class.getClassLoader().getResource("").getPath()).getPath();private static Map<Class, Object> objectMap = new HashMap<>();/*** 初始化方法* @param packageName*/public static void init(String packageName) {try {//1 扫描 指定包 下面的所有内容(接口、类)// 1.1 获得 指定包 所在的位置,以文件File形式File packageFile = packageToFile(packageName);// 1.2 根据 包的位置 获得所有的类List<String> classNameList = getAllClassName(packageFile);//2 处理类:创建实例(IoC)// 2.1 遍历所有的类文件for(String className: classNameList) {// 2.2 获得类对应Class对象Class beanClass = Class.forName(className);// 2.3 根据注解创建实例// 2.3.1 如果有@RestController,创建controllerboolean isController = beanClass.isAnnotationPresent(MyRestController.class);if(isController) {// 直接创建对象objectMap.put(beanClass, beanClass.newInstance());}// 2.3.2 如果有@Service,创建Service,需要获得接口boolean isService = beanClass.isAnnotationPresent(MyService.class);if(isService) {// 如果有接口,接口-->实现类。 如果没有接口, 实现类-->实现类Class[] interfaces = beanClass.getInterfaces();if(interfaces.length == 0) {// 没有接口objectMap.put(beanClass, beanClass.newInstance());} else {// 有接口objectMap.put(interfaces[0], beanClass.newInstance());}}// 2.3.3 如果有@Mapper,创建代理boolean isMapper = beanClass.isAnnotationPresent(MyMapper.class);if(isMapper) {// 创建Map对应的代理类// 1) 参数// 1.1) 类加载器ClassLoader loader = MyBeanFactory.class.getClassLoader();// 1.2) 接口们Class[] interfaces = new Class[] {beanClass};// 1.3) 处理类MybatisHandler mybatisHandler = new MybatisHandler(beanClass);// 2) 工具创建objectMap.put(beanClass, Proxy.newProxyInstance(loader, interfaces, mybatisHandler));}}} catch (Exception e) {throw new RuntimeException(e);}System.out.println(objectMap);}/*** com.czxy --> com/czxy* @param packageName* @return*/private static File packageToFile(String packageName) {return new File(classpath , packageName.replace(".", "/"));}/*** 获得指定包所有内容,如果是类* @param dir* @return*/private static List<String> getAllClassName(File dir) {List<String> list = new ArrayList<>();if(dir == null) {return list;}for(File file: Objects.requireNonNull(dir.listFiles())) {if(file.isFile()) {list.add(pathToClassName(file.getPath()));} else {List<String> subList = getAllClassName(file);list.addAll(subList);}}return list;}/**** @param path* @return A.B.C*/private static String pathToClassName(String path) {// 取消前缀String newPath = path.replace(classpath + "\\", "");if(newPath.endsWith(".class")) {//处理类String tempPath = newPath.replace("\\", ".");return tempPath.substring(0, tempPath.length() - 6);} else {return newPath;}}
}
-
代理类处理类
package com.czxy.boot;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;public class MybatisHandler implements InvocationHandler {private Class beanClass;public MybatisHandler(Class beanClass) {this.beanClass = beanClass;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理类的处理类执行了");//1 获得方法名String methodName = method.getName();//2 处理 toString 方法if("toString".equals(methodName)) {return "myProxy";}return null;} }
3.4.3 依赖关系
package com.czxy.bean;
import com.czxy.annotation.MyMapper;
import com.czxy.annotation.MyRestController;
import com.czxy.annotation.MyService;
import com.czxy.boot.MybatisHandler;
import javax.annotation.Resource;
import javax.annotation.Resources;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.*;
public class MyBeanFactory {
private static String classpath = new File(MyBeanFactory.class.getClassLoader().getResource("").getPath()).getPath();private static Map<Class, Object> objectMap = new HashMap<>();/*** 初始化方法* @param packageName*/
public static void init(String packageName) {try {//1 扫描 指定包 下面的所有内容(接口、类)// 1.1 获得 指定包 所在的位置,以文件File形式File packageFile = packageToFile(packageName);// 1.2 根据 包的位置 获得所有的类List<String> classNameList = getAllClassName(packageFile);//2 处理类:创建实例(IoC)// 2.1 遍历所有的类文件for(String className: classNameList) {// 2.2 获得类对应Class对象Class beanClass = Class.forName(className);// 2.3 根据注解创建实例// 2.3.1 如果有@RestController,创建controllerboolean isController = beanClass.isAnnotationPresent(MyRestController.class);if(isController) {// 直接创建对象objectMap.put(beanClass, beanClass.newInstance());}// 2.3.2 如果有@Service,创建Service,需要获得接口boolean isService = beanClass.isAnnotationPresent(MyService.class);if(isService) {// 如果有接口,接口-->实现类。 如果没有接口, 实现类-->实现类Class[] interfaces = beanClass.getInterfaces();if(interfaces.length == 0) {// 没有接口objectMap.put(beanClass, beanClass.newInstance());} else {// 有接口objectMap.put(interfaces[0], beanClass.newInstance());}}// 2.3.3 如果有@Mapper,创建代理boolean isMapper = beanClass.isAnnotationPresent(MyMapper.class);if(isMapper) {// 创建Map对应的代理类// 1) 参数// 1.1) 类加载器ClassLoader loader = MyBeanFactory.class.getClassLoader();// 1.2) 接口们Class[] interfaces = new Class[] {beanClass};// 1.3) 处理类MybatisHandler mybatisHandler = new MybatisHandler(beanClass);// 2) 工具创建objectMap.put(beanClass, Proxy.newProxyInstance(loader, interfaces, mybatisHandler));}}//3 处理类:依赖注入// 2.1 变量ObjectMapfor(Map.Entry<Class, Object> entry : objectMap.entrySet()) {// 获得map中对象对应的ClassClass beanClass = entry.getValue().getClass();// 2.2 获得所有的字段(含私有)Field[] fieldList = beanClass.getDeclaredFields();// 2.3 遍历字段for(Field field: fieldList) {// 2.4 判断字段是否有@Resourceboolean isResource = field.isAnnotationPresent(Resource.class);if(isResource) {// 2.5 如果有注解,获得类型Class<?> fieldType = field.getType();// 2.6 根据类型,从objectMap获得对应的对象Object obj = objectMap.get(fieldType);// 2.7 设置访问权限field.setAccessible(true);// 2.8 设置对象field.set(entry.getValue(), obj);}}}} catch (Exception e) {throw new RuntimeException(e);}System.out.println(objectMap);
}/*** com.czxy --> com/czxy* @param packageName* @return*/
private static File packageToFile(String packageName) {return new File(classpath , packageName.replace(".", "/"));
}/*** 获得指定包所有内容,如果是类* @param dir* @return*/
private static List<String> getAllClassName(File dir) {List<String> list = new ArrayList<>();if(dir == null) {return list;}for(File file: Objects.requireNonNull(dir.listFiles())) {if(file.isFile()) {list.add(pathToClassName(file.getPath()));} else {List<String> subList = getAllClassName(file);list.addAll(subList);}}return list;
}/**** @param path* @return A.B.C*/
private static String pathToClassName(String path) {// 取消前缀String newPath = path.replace(classpath + "\\", "");if(newPath.endsWith(".class")) {//处理类String tempPath = newPath.replace("\\", ".");return tempPath.substring(0, tempPath.length() - 6);} else {return newPath;}
}
}