Spring源码分析-Bean实现

实现Spring Bean功能

定义扫描路径

  • 创建ApplicationContext类

    package com.smile.spring;
    public class ApplicationContext {}
    
  • 采用配置类加注解实现配置功能

    1. 创建配置类
    package com.smile.main;
    public class ApplicationConfig {}
    
    1. 创建注解
    package com.smile.spring;
    
    import java.lang.annotation.Target;
    import java.lang.annotation.Retention;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.RetentionPolicy;
    
    /**
     * @author yiwenjie
     * 设置扫描的路径地址
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ComponentScan {
        String value() default "";
    }
    
  • 根据设定的路径,扫描指定文件

    package com.smile.spring;
    
    import java.io.File;
    import java.net.URL;
    
    /**
     * @author yiwenjie
     * 应用容器
     */
    public class ApplicationContext {
        /**
         * 配置文件类
         **/
        private Class configClass;
    
        /**
         * 加载配置文件
         **/
        public ApplicationContext(Class configClass) throws ClassNotFoundException {
            this.configClass = configClass;
    
            //判断配置文件中,是否存在ComponentScan注解
            if (!configClass.isAnnotationPresent(ComponentScan.class)) {
                throw new RuntimeException("配置文件异常");
            }
    
            //获取到ComponentScan注解
            //强制转换成ComponentScan注解
            ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
    
            //获取到ComponentScan注解定义的路径
            String scanPath = componentScan.value();
    
            if (scanPath == null || scanPath.length() == 0) {
                throw new RuntimeException("配置文件设置的路径地址异常");
            }
    
            //将设置的路由转换成文件路径的格式
            scanPath = scanPath.replace(".","/");
    
            //获取到类的加载器
            ClassLoader classLoader = ApplicationContext.class.getClassLoader();
    
            //根据类加载器,获取到扫描路径的绝对地址
            URL resource = classLoader.getResource(scanPath);
            if (resource == null) {
                throw new RuntimeException("路由地址异常");
            }
    
            //判断绝对地址是否是一个目录
            File fileDirectory = new File(resource.getPath());
    
            if (!fileDirectory.isDirectory()) {
                throw new RuntimeException("路由地址不是一个目录");
            }
    
            //获取到文件夹下所有文件
            for (File file : fileDirectory.listFiles()) {
                String fileName = file.getAbsolutePath();
    
                //判断文件是否以.class结尾
                if (fileName.endsWith(".class")) {
                    //将文件名转换成正常的文件类名描述
                    fileName = fileName.replace("/",".");
                    String className = fileName.substring(fileName.indexOf("com"),fileName.indexOf(".class"));
    
                    //获取到文件对应的Class类
                    Class fileClass = classLoader.loadClass(className);
    
                    //判断Class是否包含Component注解
                    if (fileClass.isAnnotationPresent(Component.class)) {
                        //获取到Component标识的bean名称
                        String beanName = ((Component) fileClass.getAnnotation(Component.class)).value();
                        System.out.println(beanName);
                    }
                }
            }
        }
    }
    
  • 创建UserService

    package com.smile.main;
    
    import com.smile.spring.Component;
    
    /**
     * @author yiwenjie
     */
    @Component("userService")
    public class UserService {
    }
    
  • 创建启动类Application

    package com.smile.main;
    
    import com.smile.spring.ApplicationContext;
    
    import java.lang.reflect.InvocationTargetException;
    
    /**
     * @author yiwenjie
     */
    public class Application {
        public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
            //解析配置文件
            ApplicationContext context = new ApplicationContext(ApplicationConfig.class);
        }
    }
    
  • 输出结果如下:

    image-20220915153223316

创建Bean

  • 创建BeanDefinition类,用来记录bean的信息

    package com.smile.spring;
    
    /**
     * @author yiwenjie
     * Bean定义类
     */
    public class BeanDefinition {
        /**
        * 记录bean的类型,是单例,还是非单例
        **/
        private String type;
    
        /**
         * 保存Class信息
         **/
        private Class context;
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public Class getContext() {
            return context;
        }
    
        public void setContext(Class context) {
            this.context = context;
        }
    }
    
  • 创建Scope注解来标识类是单例,还是多例模式

    package com.smile.spring;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author yiwenjie
     * 标明实例类型
     */
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Scope {
        String value() default "singleton";
    }
    
  • 创建

    package com.smile.spring;
    
    import java.io.File;
    import java.lang.reflect.InvocationTargetException;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Objects;
    
    /**
     * @author yiwenjie
     * 应用容器
     */
    public class ApplicationContext {
        /**
         * 配置文件类
         **/
        private Class configClass;
    
        /**
         * 用来保存bean
         **/
        private HashMap<String,BeanDefinition> beanDefinitionHashMap = new HashMap<>();
    
        /**
         * 用来保存单例的类
         **/
        private HashMap<String,Object> singletonBeanHashMap = new HashMap<>();
    
        /**
         * 加载配置文件
         **/
        public ApplicationContext(Class configClass) throws ClassNotFoundException {
            this.configClass = configClass;
    
            //判断配置文件中,是否存在ComponentScan注解
            if (!configClass.isAnnotationPresent(ComponentScan.class)) {
                throw new RuntimeException("配置文件异常");
            }
    
            //获取到ComponentScan注解
            //强制转换成ComponentScan注解
            ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
    
            //获取到ComponentScan注解定义的路径
            String scanPath = componentScan.value();
    
            if (scanPath == null || scanPath.length() == 0) {
                throw new RuntimeException("配置文件设置的路径地址异常");
            }
    
            //将设置的路由转换成文件路径的格式
            scanPath = scanPath.replace(".","/");
    
            //获取到类的加载器
            ClassLoader classLoader = ApplicationContext.class.getClassLoader();
    
            //根据类加载器,获取到扫描路径的绝对地址
            URL resource = classLoader.getResource(scanPath);
            if (resource == null) {
                throw new RuntimeException("路由地址异常");
            }
    
            //判断绝对地址是否是一个目录
            File fileDirectory = new File(resource.getPath());
    
            if (!fileDirectory.isDirectory()) {
                throw new RuntimeException("路由地址不是一个目录");
            }
    
            //获取到文件夹下所有文件
            for (File file : fileDirectory.listFiles()) {
                String fileName = file.getAbsolutePath();
    
                //判断文件是否以.class结尾
                if (fileName.endsWith(".class")) {
                    //将文件名转换成正常的文件类名描述
                    fileName = fileName.replace("/",".");
                    String className = fileName.substring(fileName.indexOf("com"),fileName.indexOf(".class"));
    
                    //获取到文件对应的Class类
                    Class fileClass = classLoader.loadClass(className);
    
                    //判断Class是否包含Component注解
                    if (fileClass.isAnnotationPresent(Component.class)) {
                        //获取到Component标识的bean名称
                        String beanName = ((Component) fileClass.getAnnotation(Component.class)).value();
    
                        //初始化一个BeanDefinition类
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setContext(fileClass);
    
                        //判断是否存在Scope注解
                        //默认情况下给予单例的模式
                        if (fileClass.isAnnotationPresent(Scope.class)) {
                            beanDefinition.setType(((Scope) fileClass.getAnnotation(Scope.class)).value());
                        } else {
                            beanDefinition.setType("singleton");
                        }
    
                        //将生成好的beanDefinition保存到beanMap中
                        beanDefinitionHashMap.put(beanName,beanDefinition);
                    }
                }
            }
    
            //实例出所有的单例bean
            beanDefinitionHashMap.forEach((k,v) -> {
                if (v.getType().equals("singleton")) {
                    try {
                        singletonBeanHashMap.put(k,v.getContext().getConstructor().newInstance());
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
        /**
         * 创建bean
         **/
        public Object createBean(String beanName,BeanDefinition beanDefinition) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
            //判断需要实例化的类是不是单例
            if ("singleton".equals(beanDefinition.getType())) {
                return singletonBeanHashMap.get(beanName);
            }
    
            return beanDefinition.getContext().getConstructor().newInstance();
        }
    
        /**
         *  获取到bean
         **/
        public Object getBean(String beanName) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
            return createBean(beanName,beanDefinitionHashMap.get(beanName));
        }
    }
    
posted @ 2022-09-19 12:06  易文杰  阅读(51)  评论(0)    收藏  举报