架构师内功心法-----手写springv2.0ioc与di

手写springv2.0ioc与di


简介

接上文,从serlvet到applicationContext。

  • 从v1.0.1servlet到applicationContext,做了如下调整:
  • 1.将ioc和di的功能放到了applicationContext
  • 2.增加了控制层方法参数的数据类型转换
  • 3.增加了控制层@MyRequestParam注解的required属性
  • 4.增加了懒加载注解

主要类如下:ApplicationContext 、BeanDefinitionReader、BeanDefinition、BeanWrapper、DefaultListableFactory
流程如下:DispatcherServlet通过ApplicationContext进行ioc和di过程,ApplicationContext 通过BeanDefinitionReader进行配置文件的读取,并解析成BeanDefinition,随后将BeanDefinition缓存到DefaultListableFactory,随后进行实例化。

实例化过程如下:根据beanName获取BeanDefinition,反射实例化Bean,封装成Beanwrapper,进行依赖注入,存入ioc。

di过程主要通过三级缓存解决了循环依赖的问题。

IoC

BeanDefinition Bean配置信息

public class MyBeanDefinition {
    /**
     * 类的beanName
     **/
    private String factoryBeanName;
    /**
     * 类的全限定名
     **/
    private String beanClassName;
    /**
     * 类是否懒加载
     **/
    private boolean lazyInit = false;

    public MyBeanDefinition(String factoryBeanName, String beanClassName, boolean lazyInit) {
        this.factoryBeanName = factoryBeanName;
        this.beanClassName = beanClassName;
        this.lazyInit = lazyInit;
    }

    public MyBeanDefinition(String factoryBeanName, String beanClassName) {
        this.factoryBeanName = factoryBeanName;
        this.beanClassName = beanClassName;
    }

    public String getFactoryBeanName() {
        return factoryBeanName;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public boolean isLazyInit() {
        return lazyInit;
    }
}

BeanWrapper Bean的包装类

public class MyBeanWrapper {
    /**
     * 类实例
     **/
    private Object wrappedInstance;
    /**
     * 类对象
     **/
    private Class<?> wrappedClazz;

    public Object getWrappedInstance() {
        return wrappedInstance;
    }

    public Class<?> getWrappedClazz() {
        return wrappedClazz;
    }

    public MyBeanWrapper(Object wrappedInstance, Class wrappedClazz) {
        this.wrappedInstance = wrappedInstance;
        this.wrappedClazz = wrappedClazz;
    }
}

BeanDefinitionReader BeanDefinition的读取与解析工具

public class MyBeanDefinitionReader {
    /**
     * 保存的配置文件
     **/
    private Properties contextConfig = new Properties();

    /**
     * 配置文件分隔符
     **/
    private static final String SPLITSYMBOL = ";";

    /**
     * 待注册到ioc的class
     **/
    private List<String> registerBeanClasses = new ArrayList<String>();

    public MyBeanDefinitionReader(String configs){
        //web.xml中获取配置文件路径后加载文件
        for (int i = 0; i < configs.split(SPLITSYMBOL).length; i++) {
            contextConfig.remove("scanPackage");
            doLoadConfig(configs.split(SPLITSYMBOL)[i]);
            //配置文件中获取属性后扫包
            doScan(contextConfig.getProperty("scanPackage"));
        }
    }

    /**
     * 解析配置文件,将所有需要注册成bean的class创建BeanDefinition=====可能存在相同beanName
     *
     * @param
     * @return  java.util.List<com.yjf.spring.mvcframework.v2.ioc.beans.config.MyBeanDefinition>
     **/
    public List<MyBeanDefinition> loadBeanDefinitions(){
        if (registerBeanClasses.isEmpty()) {
            return new ArrayList<>();
        }

        List<MyBeanDefinition> result = new ArrayList<>();
        for (String registerBeanClass : registerBeanClasses) {
            try{
                Class<?> clazz = Class.forName(registerBeanClass);
                //若为接口,则跳过
                if(clazz.isInterface()){
                    continue;
                }

                if (clazz.isAnnotationPresent(MyController.class) || clazz.isAnnotationPresent(MyService.class)) {
                    //默认beanName : 类名首字母小写
                    String beanName = StringUtil.firstCaseToLower(clazz.getSimpleName());
                    //自定义beanName
                    String defineBeanName = clazz.getAnnotation(MyService.class) == null ? clazz.getAnnotation(MyController.class).value() : clazz.getAnnotation(MyService.class).value();

                    //若为空,则使用默认beanName
                    if (!StringUtil.isEmpty(defineBeanName)) {
                        beanName = defineBeanName;
                    }

                    //是否懒加载
                    MyLazy myLazy = clazz.getAnnotation(MyLazy.class);
                    if(null != myLazy && myLazy.value() == true){
                        result.add(new MyBeanDefinition(beanName,registerBeanClass,true));
                    }else {
                        result.add(new MyBeanDefinition(beanName,registerBeanClass));
                    }
                }else {
                    continue;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return result;
    }

    /**
     * 将包路径转成文件路径,扫描文件夹,存下文件后缀名为class的全限定名
     *
     * @param scanPackage 包名
     * @return void
     **/
    private void doScan(String scanPackage) {
        String fileSuffix = scanPackage.replaceAll("\\.", "/");
        File root = new File(this.getClass().getClassLoader().getResource("").getPath(), fileSuffix);

        for (File file : root.listFiles()) {
            if (file.isDirectory()) {
                doScan(scanPackage + "." + file.getName());
            } else {
                if (!file.getName().endsWith(".class")) {
                    continue;
                }

                registerBeanClasses.add(scanPackage + "." + file.getName().replace(".class", ""));
            }
        }
    }

    /**
     * 通过Properties加载配置文件
     *
     * @param contextConfigLocation 配置文件路径
     * @return void
     **/
    private void doLoadConfig(String contextConfigLocation) {
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);

        try {
            contextConfig.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

BeanFactory 定义接口

public interface MyBeanFactory {
    Object getBean(String beanName);

    /**
     * 通过类的全限定名获取bean
     *
     * @param clazz
     * @return  java.lang.Object
     **/
    Object getBean(Class clazz);
}

DefaultListableBeanFactory 缓存待注册的BeanDefinition

public class MyDefaultListableBeanFactory implements MyBeanFactory {
    public Map<String, MyBeanDefinition> beanDefinitionMap = new HashMap<>();

    @Override
    public Object getBean(String beanName) {
        return null;
    }

    @Override
    public Object getBean(Class clazz) {
        return null;
    }

    /**
     * 缓存配置文件,检测是否存在相同beanName
     *
     * @param beanDefinitions
     * @return  void
     **/
    public void doRegisterBeanDefinition(List<MyBeanDefinition> beanDefinitions){
        for (MyBeanDefinition beanDefinition : beanDefinitions) {
            //存在同名类却未起别名
            if(beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())){
                throw new Error("The " + beanDefinition.getFactoryBeanName() + " already exists,please use alias!");
            }
            beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);
        }
    }
}

DispatcherServlet

public class MyDispatcherServlet extends HttpServlet {
    private MyApplicationContext myApplicationContext = null;

    /**
     * 键 : 请求url , 值 : 请求url对应的方法
     **/
    private Map<String, Method> handlerMapping = new HashMap<String, Method>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            dispatcher(req, resp);
        } catch (Exception e) {
            e.printStackTrace();
            resp.getWriter().write("500 Exception,Detail : " + Arrays.toString(e.getStackTrace()));
        }
    }

    /**
     * 运行阶段,根据url委派给具体的method
     * <p>
     * 1. 根据url取出method
     * 2. 参数赋值
     * 3. 反射调用方法
     * 4. 响应浏览器
     **/
    private void dispatcher(HttpServletRequest req, HttpServletResponse resp) throws IOException, InvocationTargetException, IllegalAccessException {
        //去除上下文
        String uri = req.getRequestURI().replace(req.getContextPath(),"").replaceAll("/+","/");

        if(!handlerMapping.containsKey(uri)){
            resp.getWriter().write("404 page not found!");
            return;
        }

        //取出方法
        Method method = handlerMapping.get(uri);
        //形参数组
        Parameter[] parameters = method.getParameters();
        //必须形参位置
        int[] indexes = new int[parameters.length];
        Arrays.fill(indexes,-1);
        //实参数组
        Object[] args = new Object[parameters.length];
        //控制层对象
        String defineBeanName = method.getDeclaringClass().getAnnotation(MyController.class).value();
        Object instance = StringUtil.isEmpty(defineBeanName) ? myApplicationContext.getBean(StringUtil.firstCaseToLower(method.getDeclaringClass().getSimpleName())) : myApplicationContext.getBean(defineBeanName);

        //形参名-->形参位置
        Map<String,Integer> paramIndexMapping = new HashMap<>(3);

        //先将形参名和形参位置建立联系,而后通过实参名获取实参名位置
        for (int i = 0; i < parameters.length; i++) {
            //获取参数注解
        //    Annotation[] parameterAnnotation = parameters[i].getAnnotations();

            //获取@MyRequestParam注解的值,若值存在,则paramIndexMapping中键为该值,若不存在,则paramIndexMapping中键为形参参数名
            MyRequestParam param = parameters[i].getAnnotation(MyRequestParam.class);
            if(null == param || StringUtil.isEmpty(param.value())){
                paramIndexMapping.put(parameters[i].getName(),i);
            }else {
                paramIndexMapping.put(param.value(),i);
                if(param.required() == true) {
                    indexes[i] = 1;
                }
            }

            //注入HttpServletRequest和HttpServletResponse
            if(parameters[i].getType() == HttpServletRequest.class){
                args[i] = req;
            }
            if(parameters[i].getType() == HttpServletResponse.class){
                args[i] = resp;
            }
        }

        //获取实参
        Enumeration<String> parameterNames = req.getParameterNames();
        while(parameterNames.hasMoreElements()){
            //实参参数名
            String paramKey = parameterNames.nextElement();
            //参数名对应的位置
            Integer integer = paramIndexMapping.get(paramKey);
            if (null != integer) {
                if (parameters[integer].getType().isArray()) {
                    args[integer] = convert(parameters[integer], req.getParameterValues(paramKey));
                } else {
                    args[integer] = convert(parameters[integer], req.getParameter(paramKey));
                }
            }
        }

        //判断必须参数在实参中是否存在
        for (int i = 0; i < indexes.length; i++) {
            int index = indexes[i];
            if(index == 1 && args[i] == null){
                throw new Error(parameters[i].getName() + " is required!");
            }
        }

        Object result = method.invoke(instance, args);
        resp.getWriter().write(String.valueOf(result));
    }

    /**
     * 转换实参值的数据类型
     *
     * @param param  形参
     * @param value  实参值
     * @return  java.lang.Object  转换后的实参
     **/
    private Object convert(Parameter param, String... value) {
        if (value == null || value.length == 0) {
            return null;
        }

        //单值
        if (value.length == 1) {
            Class<?> type = param.getType();
            IConvertStrategy convertStrategy = ConvertStrategyFactory.getConvertStrategy(type.getSimpleName());
            return convertStrategy.convertString(value[0]);
            //数组
        } else {
            Class<?> componentType = param.getType().getComponentType();
            IConvertStrategy convertStrategy = ConvertStrategyFactory.getConvertStrategy(componentType.getSimpleName());
            Object result = Array.newInstance(componentType, value.length);
            for (int i = 0; i < value.length; i++) {
                Array.set(result,i,convertStrategy.convertString(value[i]));
            }
            return result;
        }
    }

    @Override
    /**
     * spring初始化过程
     *
     * 1. 传入配置文件地址,上下文完成解析配置文件,ioc与di
     * 2. mvc,迭代ioc,将url和method进行映射 存储到handlerMapping : Map
     *
     * @param config
     * @return void
     **/
    public void init(ServletConfig config) throws ServletException {
        myApplicationContext = new MyApplicationContext(config.getInitParameter("contextConfigLocation"));

        //将url和method进行映射
        doInitHandlerMapping();

        System.out.println("init finish");
    }

    /**
     * 将url和method进行映射,迭代ioc,控制层存在@RequestMapping注解的公有方法需要进行映射
     *
     * @param
     * @return void
     **/
    private void doInitHandlerMapping() {
        if (myApplicationContext.getBeanDefinitionCount() == 0) {
            return;
        }

        for (String beanName : myApplicationContext.getBeanDefinitionNames()) {
            if(myApplicationContext.getBeanDefinitionByName(beanName).isLazyInit()){continue;}
            Object instance = myApplicationContext.getBean(beanName);
            Class<?> clazz = instance.getClass();

            if(!clazz.isAnnotationPresent(MyController.class)){
                continue;
            }

            String baseUrl = clazz.getAnnotation(MyRequestMapping.class) != null ? clazz.getAnnotation(MyRequestMapping.class).value() : "";
            //遍历控制层下所有公有方法
            for (Method method : clazz.getMethods()) {
                if(!method.isAnnotationPresent(MyRequestMapping.class)){
                    continue;
                }

                String pattern = "/" + baseUrl + "/" + method.getAnnotation(MyRequestMapping.class).value();
                String url = pattern.replaceAll("/+","/");

                if(handlerMapping.containsKey(url)){
                    throw new RuntimeException(url + " already exists,mapping exception!");
                }
                handlerMapping.put(url,method);
                System.out.println(String.format("Mapped %s--->%s",url,method));
            }
        }
    }
}

ApplicationContext

public class MyApplicationContext implements MyBeanFactory {
    private MyBeanDefinitionReader myBeanDefinitionReader;
    private MyDefaultListableBeanFactory myDefaultListableBeanFactory = new MyDefaultListableBeanFactory();

    /**
     * ioc容器
     **/
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<>();

    /**
     * 三级缓存====AOP
     **/
    private Map<String, Object> factoryBeanObjectCache = new HashMap<>();

    public MyApplicationContext(String configs) {
        //加载配置文件到工具类
        myBeanDefinitionReader = new MyBeanDefinitionReader(configs);

        //工具类解析配置文件返回配置信息
        List<MyBeanDefinition> myBeanDefinitions = myBeanDefinitionReader.loadBeanDefinitions();

        //缓存配置信息到工厂
        myDefaultListableBeanFactory.doRegisterBeanDefinition(myBeanDefinitions);

        //加载非懒加载bean
        doInstance();
    }

    private void doInstance() {
        //获取待注册bean
        Map<String, MyBeanDefinition> beanDefinitionMap = this.myDefaultListableBeanFactory.beanDefinitionMap;

        for (Map.Entry<String, MyBeanDefinition> stringMyBeanDefinitionEntry : beanDefinitionMap.entrySet()) {
            String beanName = stringMyBeanDefinitionEntry.getKey();
            if (!stringMyBeanDefinitionEntry.getValue().isLazyInit()) {
                getBean(beanName);
            }
        }
    }

    @Override
    public Object getBean(String beanName) {
        Map<String, MyBeanDefinition> beanDefinitionMap = this.myDefaultListableBeanFactory.beanDefinitionMap;

        //获取beanDefinition
        MyBeanDefinition myBeanDefinition = beanDefinitionMap.get(beanName);

        if(this.factoryBeanInstanceCache.containsKey(beanName)){
            return this.factoryBeanInstanceCache.get(beanName).getWrappedInstance();
        }

        //反射实例化
        Object instance = instantiateBean(beanName, myBeanDefinition);

        //包装Bean
        MyBeanWrapper myBeanWrapper = new MyBeanWrapper(instance, instance.getClass());

        //依赖注入
        populateBean(myBeanWrapper);

        //保存到ioc容器中
        this.factoryBeanInstanceCache.put(beanName, myBeanWrapper);

        //将当前类的全限定名和类实例存入ioc
        this.factoryBeanInstanceCache.put(myBeanDefinition.getBeanClassName(), myBeanWrapper);

        //将当前类实现的接口注册到ioc,键:接口全限定名 值: 当前类对象;存在多个实现类的时候移除注册
        try {
            for (Class<?> clazzInterface : Class.forName(myBeanDefinition.getBeanClassName()).getInterfaces()) {
                if (factoryBeanInstanceCache.containsKey(clazzInterface.getName())) {
                    this.factoryBeanInstanceCache.remove(clazzInterface.getName());
                }else {
                    this.factoryBeanInstanceCache.put(clazzInterface.getName(), myBeanWrapper);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return myBeanWrapper.getWrappedInstance();
    }

    private void populateBean(MyBeanWrapper myBeanWrapper) {
        Object wrappedInstance = myBeanWrapper.getWrappedInstance();
        Class<?> wrappedClazz = myBeanWrapper.getWrappedClazz();

        //获取类对象下所有字段,根据是否存在注解@MyAutowired决定是否进行依赖注入
        for (Field field : wrappedClazz.getDeclaredFields()) {
            if (!field.isAnnotationPresent(MyAutowired.class)) {
                continue;
            }

            //自定义beanName
            String defineBeanName = field.getAnnotation(MyAutowired.class).value();
            //默认以字段类型首字母小写作为beanName
            String beanName = StringUtil.firstCaseToLower(field.getType().getSimpleName());
            //类全限定名作为beanName
            String fullBeanName = field.getType().getName();

            //暂存默认beanName
            String simpleBeanName = beanName;
            //标志defineBeanName是否为空
            boolean flag = true;
            if (!StringUtil.isEmpty(defineBeanName)) {
                beanName = defineBeanName;
                flag = false;
            }
            if (!flag) {
                if (null == factoryBeanInstanceCache.get(beanName)) {
                    beanName = simpleBeanName;
                }
            }
            if (null == factoryBeanInstanceCache.get(beanName)) {
                beanName = fullBeanName;
            }

            ReflectUtil.fieldSetting(field, wrappedInstance, factoryBeanInstanceCache.get(beanName) == null ? null : factoryBeanInstanceCache.get(beanName).getWrappedInstance());
        }
    }

    private Object instantiateBean(String beanName, MyBeanDefinition myBeanDefinition) {
        try {
            Class<?> clazz = Class.forName(myBeanDefinition.getBeanClassName());
            Object instance = clazz.newInstance();

            //如果是代理对象,触发AOP的逻辑

            this.factoryBeanObjectCache.put(beanName, instance);

            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Object getBean(Class clazz) {
        return getBean(clazz.getName());
    }

    public int getBeanDefinitionCount(){
        return this.myDefaultListableBeanFactory.beanDefinitionMap.size();
    }

    public String[] getBeanDefinitionNames(){
        return this.myDefaultListableBeanFactory.beanDefinitionMap.keySet().toArray(new String[]{});
    }

    public MyBeanDefinition getBeanDefinitionByName(String beanName){
        return this.myDefaultListableBeanFactory.beanDefinitionMap.get(beanName);
    }
}

DI

循环依赖:多个类之间形成依赖闭环。eg: A{B b} B{A a}
跟手写spring1.0不同,1.0中是所有类先进行实例化存入ioc,再进行DI,因此不会出现循环依赖问题。而2.0中是一边实例化一边di,因此会出现di时其他类还未创建的情况。
当只存在一级缓存时,由于类A还在进行依赖注入,并没有存入一级缓存,所以当B注入A时无法完成,形成依赖死循环。
就解决循环依赖而言,两级缓存就可以解决,可能考虑到功能扩展及aop的其它问题,spring中使用了三级缓存。

构造器注入循环依赖无法解决。

public A{
	public A(){
		new B();
	}
}
public B{
	public B(){
		new A();
	}
}

解决循环依赖的关键在于类A实例化后di之前的对象应该保留曝光出来,使得类B可以注入A。
而构造器循环依赖无法实例化任何一个对象,形成依赖死循环。

非单例循环依赖无法解决。

三级缓存存的都是单例对象。

BeanDefinition

public class MyBeanDefinition {
    /**
     * 类的beanName
     **/
    private String factoryBeanName;
    /**
     * 类的全限定名
     **/
    private String beanClassName;
    /**
     * 类是否懒加载
     **/
    private boolean lazyInit = false;

    public MyBeanDefinition(String factoryBeanName, String beanClassName, boolean lazyInit) {
        this.factoryBeanName = factoryBeanName;
        this.beanClassName = beanClassName;
        this.lazyInit = lazyInit;
    }

    public MyBeanDefinition(String factoryBeanName, String beanClassName) {
        this.factoryBeanName = factoryBeanName;
        this.beanClassName = beanClassName;
    }

    public String getFactoryBeanName() {
        return factoryBeanName;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public boolean isLazyInit() {
        return lazyInit;
    }

    public boolean isSingleton(){
        return true;
    }
}

BeanDefinitionReader

public class MyBeanDefinitionReader {
    /**
     * 保存的配置文件
     **/
    private Properties contextConfig = new Properties();

    /**
     * 配置文件分隔符
     **/
    private static final String SPLITSYMBOL = ";";

    /**
     * 待注册到ioc的class
     **/
    private List<String> registerBeanClasses = new ArrayList<String>();

    public MyBeanDefinitionReader(String configs) {
        //web.xml中获取配置文件路径后加载文件
        for (int i = 0; i < configs.split(SPLITSYMBOL).length; i++) {
            contextConfig.remove("scanPackage");
            doLoadConfig(configs.split(SPLITSYMBOL)[i]);
            //配置文件中获取属性后扫包
            doScan(contextConfig.getProperty("scanPackage"));
        }
    }

    /**
     * 解析配置文件,将所有需要注册成bean的class创建BeanDefinition=====可能存在相同beanName
     *
     * @param
     * @return java.util.List<com.yjf.spring.mvcframework.v2.ioc.beans.config.MyBeanDefinition>
     **/
    public List<MyBeanDefinition> loadBeanDefinitions() {
        if (registerBeanClasses.isEmpty()) {
            return new ArrayList<>();
        }

        List<MyBeanDefinition> result = new ArrayList<>();

        for (String registerBeanClass : registerBeanClasses) {
            try {
                Class<?> clazz = Class.forName(registerBeanClass);
                //若为接口,则跳过
                if (clazz.isInterface()) {
                    continue;
                }

                if (clazz.isAnnotationPresent(MyController.class) || clazz.isAnnotationPresent(MyService.class)) {
                    //默认beanName : 类名首字母小写
                    String beanName = StringUtil.firstCaseToLower(clazz.getSimpleName());
                    //自定义beanName
                    String defineBeanName = clazz.getAnnotation(MyService.class) == null ? clazz.getAnnotation(MyController.class).value() : clazz.getAnnotation(MyService.class).value();

                    //若为空,则使用默认beanName
                    if (!StringUtil.isEmpty(defineBeanName)) {
                        beanName = defineBeanName;
                    }

                    //是否懒加载
                    MyLazy myLazy = clazz.getAnnotation(MyLazy.class);
                    if (null != myLazy && myLazy.value() == true) {
                        for (Class<?> clazzInterface : clazz.getInterfaces()) {
                            result.add(new MyBeanDefinition(clazzInterface.getName(), registerBeanClass,true));
                        }
                        result.add(new MyBeanDefinition(beanName, registerBeanClass, true));
                    } else {
                        result.add(new MyBeanDefinition(beanName, registerBeanClass));
                        for (Class<?> clazzInterface : clazz.getInterfaces()) {
                            result.add(new MyBeanDefinition(clazzInterface.getName(), registerBeanClass));
                        }
                    }
                } else {
                    continue;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    /**
     * 将包路径转成文件路径,扫描文件夹,存下文件后缀名为class的全限定名
     *
     * @param scanPackage 包名
     * @return void
     **/
    private void doScan(String scanPackage) {
        String fileSuffix = scanPackage.replaceAll("\\.", "/");
        File root = new File(this.getClass().getClassLoader().getResource("").getPath(), fileSuffix);

        for (File file : root.listFiles()) {
            if (file.isDirectory()) {
                doScan(scanPackage + "." + file.getName());
            } else {
                if (!file.getName().endsWith(".class")) {
                    continue;
                }

                registerBeanClasses.add(scanPackage + "." + file.getName().replace(".class", ""));
            }
        }
    }

    /**
     * 通过Properties加载配置文件
     *
     * @param contextConfigLocation 配置文件路径
     * @return void
     **/
    private void doLoadConfig(String contextConfigLocation) {
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);

        try {
            contextConfig.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ApplicationContext

/** 循环依赖:存在依赖闭环

  • eg: A{B b} B{A a}
  • getBean(A) -> A实例化(标记创建中) (三级缓存持有该对象) ->注入B-> getBean(B) -> 实例化B(标记创建中)(三级缓存持有该对象) -> 注入A -> getBean(A) -> 三级缓存取得对象 -> B初始化完成(取消标记) -> 存入一级缓存 -> A初始化完成 (取消标记) -> 存入一级缓存
    */
public class MyApplicationContext implements MyBeanFactory {
    private MyBeanDefinitionReader myBeanDefinitionReader;
    private MyDefaultListableBeanFactory registry = new MyDefaultListableBeanFactory();

    /**
     * ioc容器
     **/
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache = new HashMap<>();

    /**
     * 正在创建中的对象beanName
     * 执行创建对象流程但还未初始化完成的bean带有该标记
     * 不存在循环依赖的类创建对象时直接就放入一级缓存了,因此一级缓存中没有的bean且该bean存在标记时代表该类为循环依赖类
     **/
    private Set<String> singletonCurrentlyInCreation = new HashSet<>();

    /**
     * 一级缓存====保存初始化完成的bean
     **/
    private Map<String, Object> singletonObject = new HashMap<>();
    /**
     * 二级缓存====保存已创建对象但还未注入属性的bean,该容器存的都是循环依赖对象
     **/
    private Map<String, Object> earlySingletonObject = new HashMap<>();

    /**
     * 三级缓存====AOP
     **/
    private Map<String, Object> factoryBeanObjectCache = new HashMap<>();

    public MyApplicationContext(String configs) {
        //加载配置文件到工具类
        myBeanDefinitionReader = new MyBeanDefinitionReader(configs);

        //工具类解析配置文件返回配置信息
        List<MyBeanDefinition> myBeanDefinitions = myBeanDefinitionReader.loadBeanDefinitions();

        //缓存配置信息到工厂
        registry.doRegisterBeanDefinition(myBeanDefinitions);

        //加载非懒加载bean
        doInstance();
    }

    private void doInstance() {
        //获取待注册bean
        Map<String, MyBeanDefinition> beanDefinitionMap = this.registry.beanDefinitionMap;

        for (Map.Entry<String, MyBeanDefinition> stringMyBeanDefinitionEntry : beanDefinitionMap.entrySet()) {
            String beanName = stringMyBeanDefinitionEntry.getKey();
            if (!stringMyBeanDefinitionEntry.getValue().isLazyInit()) {
                getBean(beanName);
            }
        }
    }

    @Override
    public Object getBean(String beanName) {
        Map<String, MyBeanDefinition> beanDefinitionMap = this.registry.beanDefinitionMap;

        //获取beanDefinition
        MyBeanDefinition myBeanDefinition = beanDefinitionMap.get(beanName);
        if(myBeanDefinition == null) {return null;}

        if(null != getSingleton(beanName,myBeanDefinition)){
            return getSingleton(beanName,myBeanDefinition);
        }

        //标记对象创建中
        singletonCurrentlyInCreation.add(beanName);

        //反射实例化
        Object instance = instantiateBean(beanName, myBeanDefinition);

        //包装Bean
        MyBeanWrapper myBeanWrapper = new MyBeanWrapper(instance, instance.getClass());

        //依赖注入
        populateBean(myBeanWrapper);

        singletonCurrentlyInCreation.remove(beanName);
        singletonObject.put(beanName,instance);
        earlySingletonObject.remove(beanName);

        //保存到ioc容器中
        this.factoryBeanInstanceCache.put(beanName, myBeanWrapper);

        return myBeanWrapper.getWrappedInstance();
    }

    private Object getSingleton(String beanName,MyBeanDefinition myBeanDefinition) {
        //从一级缓存取bean
        Object singletonObject = this.singletonObject.get(beanName);

        //一级bean为null,存在两种情况:bean从未创建过或者bean正在创建中,通过标记容器判断
        if(null == singletonObject && singletonCurrentlyInCreation.contains(beanName)){
            //存在循环依赖
            //从二级缓存取bean
            singletonObject = earlySingletonObject.get(beanName);
            if(null == singletonObject){
                //从三级缓存取bean
                singletonObject = instantiateBean(beanName,myBeanDefinition);

                //二级缓存放入
                earlySingletonObject.put(beanName,singletonObject);
                //三级缓存移除
                factoryBeanObjectCache.remove(beanName);
            }
        }


        return singletonObject;
    }

    private void populateBean(MyBeanWrapper myBeanWrapper) {
        Object wrappedInstance = myBeanWrapper.getWrappedInstance();
        Class<?> wrappedClazz = myBeanWrapper.getWrappedClazz();

        //获取类对象下所有字段,根据是否存在注解@MyAutowired决定是否进行依赖注入
        for (Field field : wrappedClazz.getDeclaredFields()) {
            if (!field.isAnnotationPresent(MyAutowired.class)) {
                continue;
            }

            //自定义beanName
            String defineBeanName = field.getAnnotation(MyAutowired.class).value();
            //默认以字段类型首字母小写作为beanName
            String beanName = StringUtil.firstCaseToLower(field.getType().getSimpleName());
            //类全限定名作为beanName
            String fullBeanName = field.getType().getName();

            //暂存默认beanName
            String simpleBeanName = beanName;
            //标志defineBeanName是否为空
            boolean flag = true;
            if (!StringUtil.isEmpty(defineBeanName)) {
                beanName = defineBeanName;
                flag = false;
            }
            if (!flag) {
                if (null == getBean(beanName)) {
                    beanName = simpleBeanName;
                }
            }
            if (null == getBean(beanName)) {
                beanName = fullBeanName;
            }

            ReflectUtil.fieldSetting(field, wrappedInstance, getBean(beanName));
        }
    }

    private Object instantiateBean(String beanName, MyBeanDefinition myBeanDefinition) {
        if(myBeanDefinition.isSingleton() && this.factoryBeanObjectCache.containsKey(beanName)){
            return this.factoryBeanObjectCache.get(beanName);
        }

        try {
            Class<?> clazz = Class.forName(myBeanDefinition.getBeanClassName());
            Object instance = clazz.newInstance();

            //如果是代理对象,触发AOP的逻辑

            if(myBeanDefinition.isSingleton()){
                if(!StringUtil.firstCaseToLower(Class.forName(myBeanDefinition.getBeanClassName()).getSimpleName()).equals(beanName)){
                    this.factoryBeanObjectCache.put(StringUtil.firstCaseToLower(Class.forName(myBeanDefinition.getBeanClassName()).getSimpleName()), instance);
                }
                this.factoryBeanObjectCache.put(beanName, instance);
                this.factoryBeanObjectCache.put(myBeanDefinition.getBeanClassName(), instance);
            }

            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Object getBean(Class clazz) {
        return getBean(clazz.getName());
    }

    public int getBeanDefinitionCount() {
        return this.registry.beanDefinitionMap.size();
    }

    public String[] getBeanDefinitionNames() {
        return this.registry.beanDefinitionMap.keySet().toArray(new String[]{});
    }

    public MyBeanDefinition getBeanDefinitionByName(String beanName) {
        return this.registry.beanDefinitionMap.get(beanName);
    }
}
Spring Security是Spring框架的一个重要项目之一,用于提供身份验证授权功能。它是一个功能强大且高度可定制的框架,可以帮助开发人员保护应用程序的安全性。 Spring Security提供了一套丰富的安全性特性,包括用户身份验证、基于角色的访问控制、方法级的安全性、记住我功能、单点登录等。它还支持多种认证方式,如数据库认证、LDAP认证、OAuth认证等。 通过Spring Security,开发人员可以轻松地实现应用程序的安全性需求,并提供可扩展的解决方案,以满足不同场景下的安全性要求。同时,Spring Security还其他Spring项目完美配合,如Spring Boot、Spring Data等,提供了更好的开发体验集成能力。 可以通过查阅Spring官方文档项目网站来获取更多关于Spring Security的详细信息使用示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【翻译 Spring 5.0.4.RELEASE】Spring Framework Overview Version 5.0.4.RELEASE](https://blog.csdn.net/wengcheng_k/article/details/79491300)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Spring认证考试指南](https://download.csdn.net/download/Spring_Learning/86399248)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值