手写Spring IOC,深入了解 Spring IOC原理

Spring IOC 在面试中经常出现的问题,通过刷面试题只能做到知其然不知其所以然,深入底层追问,然后就一脸懵逼,在此,手写一篇Spring IOC,帮你彻底理解什么叫控制反转

Spring IOC 操作有:配置文件方式,注解方式

本demo 采用注解方式:

  • 自定义注解
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
}
  • 定义BeanFactory
public interface BeanFactory {
    /**
     * 初始化 bean
     */
    void initBeans() throws InstantiationException, IllegalAccessException;

    /**
     * 按 bean ID 获取 bean
     * @param var1
     * @return
     */
    Object getBean(String var1) throws Exception;

    /**
     * 按 classes 获取 bean
     * @param var1
     * @param 
     * @return
     */
     T getBean(Class var1);
    
}
  • 创建ApplicationContext
public class ApplicationContext implements BeanFactory {

    volatile int num;
    /**
     * 1. 定义一个bean容器,用于存放bean
     * 2. 初始化 bean 并注入容器
     * 3. 初始化 properties
     */
    private String packageName;
    /**
     * 定义一个 bean 容器
     */
    private ConcurrentHashMap beans = null;

    public ApplicationContext(String packageName) throws Exception {
        beans = new ConcurrentHashMap<>();
        this.packageName = packageName;
        initBeans();
        initProperties();
    }

    private void initProperties() throws Exception {
        System.out.println( num++ + ", 开始初始化实例成员遍历");
        Set set = new HashSet<>();
        for (Map.Entry entry : beans.entrySet()) {
            Object bean = entry.getValue();
            if (!set.contains(bean)) { // 避免beanID和classes注册的 bean 实例化重复
                System.out.println( num++ + ", 检查属性上是否有注解");
                attrAssign(bean);
            }
        }
        System.out.println( num++ + ", 结束初始化实例成员遍历");
    }

    private void attrAssign(Object obj) throws Exception {
        // 通过反射 获取 Class
        Class classes = obj.getClass();
        Field[] fields = classes.getDeclaredFields();
        if (fields != null || fields.length > 0) {
            for (Field field : fields) {
                Autowired autowired = field.getAnnotation(Autowired.class);
                if (autowired != null) {
                    // 获取属性名称
                    String beanId = field.getName();
                    Object bean = getBean(beanId);
                    if (bean != null) {
                        field.setAccessible(true); // 允许访问私有变量
                        field.set(obj, bean);
                    }
                }
            }
        }
    }

    @Override
    public void initBeans() throws InstantiationException, IllegalAccessException {
        System.out.println( num++ + ", 开始初始化 bean");
        // 1. 加载 包路径下 的 类
        List> classes = ClassUtil.getClass(packageName);
        // 遍历需要注册为bean的类并注入到 bean 容器中
        findClassExistAnnotation(classes);
        if (beans == null || beans.isEmpty()) {
            System.out.println( num++ + ", 该路径下没有需要注册为bean的类");
        }
        System.out.println( num++ + ", 结束初始化 bean");
    }

    /**
     * 遍历需要注册为bean的类并注入到 bean 容器中
     * @param classes
     * @return
     */
    private void findClassExistAnnotation(List> classes) throws IllegalAccessException, InstantiationException {
        for (Class classInfo : classes) {
            Service service = classInfo.getAnnotation(Service.class);
            if (service != null) {
                System.out.println( num++ + ", 获取类名");
                String className = classInfo.getSimpleName();
                System.out.println( num++ + ", 转换类名第一个字母为小写");
                String beanId = toLowerCaseFirstOne(className);
                System.out.println( num++ + ", 通过class名称获取类的实例化对象");
                Object newInstance = classInfo.newInstance();
                System.out.println( num++ + ", 将实例化对象注入bean 容器");
                beans.put(beanId, newInstance);
                beans.put(classInfo, newInstance);
            }
        }
    }

    /**
     * bean 名首字母转小写
     * @param className
     * @return
     */
    private String toLowerCaseFirstOne(String className) {
        return Character.isLowerCase(className.charAt(0)) ? className : new StringBuffer().append(Character.toLowerCase(className.charAt(0))).append(className.substring(1)).toString();
    }

    @Override
    public Object getBean(String beanId) throws Exception {
        if (StringUtils.isEmpty(beanId)) {
            System.out.println( "beanId 参数不能为空");
            throw new Exception("beanId 参数不能为空");
        }
        Object object = beans.get(beanId);
        return object;
    }

    @Override
    public  T getBean(Class var1) {
        T o = (T) beans.get(var1);
        return o;
    }
} 
  
  •  创建需要注册为bean的对象
public interface OrderService {
    void getOrder();
}

@Service
public class OrderServiceImpl implements OrderService {
    @Override
    public void getOrder() {
        System.out.println(">>>>>>>>>>>>>>>>>>> 调用了 OrderServiceImpl.getOrder >>>>>>>>>>>>>>>>>>>>>>>>");
    }
}



public interface UserService {
    void findUserOrder();
}

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private OrderService orderServiceImpl;

    @Override
    public void findUserOrder() {
        orderServiceImpl.getOrder();
    }
}
  •  ClassUtil, 通过包路径获取对象

 

public class ClassUtil {
    public static List> getClass(String packageName) {
        List> classes = new ArrayList<>();
        boolean flag = true; //是否循环迭代
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String packagePath = packageName.replace(".", "/");
        try {
            Enumeration urls = classLoader.getResources(packagePath);
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                if (url == null) {
                    continue;
                }
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findAndAddClassesInPackageByFile(packageName, filePath, flag, classes);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classes;
    }

    private static void findAndAddClassesInPackageByFile(String packageName, String filePath, boolean flag, List> classes) {
        File dir = new File(filePath);
        if (!dir.exists() || !dir.isDirectory()) {
            System.out.println("此路径下没有文件");
            return;
        }
        File[] dirFiles = dir.listFiles(new FileFilter(){
            @Override
            public boolean accept(File pathname) {
                return flag && pathname.isDirectory() || pathname.getName().endsWith(".class");
            }
        });

        for (File file : dirFiles) {
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "/" + file.getName(), file.getAbsolutePath(), flag, classes);
            } else {
                String className = file.getName().substring(0, file.getName().length() -6);
                System.out.println("类名:" +className);
                try {
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 测试
public class DemoTest {

	public static void main(String[] args) throws Exception {
		ApplicationContext app = new ApplicationContext("com.pro.service.impl");
		UserServiceImpl userServiceImpl = (UserServiceImpl) app.getBean("userServiceImpl");
		UserServiceImpl userService = app.getBean(UserServiceImpl.class);
		userServiceImpl.findUserOrder();
		System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>");
		userService.findUserOrder();
	}
}

手写Spring IOC,深入了解 Spring IOC原理_第1张图片

 

你可能感兴趣的:(Java,bean,ioc,反射)