首页 > 编程语言 >Spring源码分析-Bean实现

Spring源码分析-Bean实现

时间:2022-09-19 12:25:17浏览次数:74  
标签:java String Spring public Bean 源码 import ComponentScan class

实现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));
        }
    }
    

标签:java,String,Spring,public,Bean,源码,import,ComponentScan,class
From: https://www.cnblogs.com/ywjcqq/p/16707305.html

相关文章

  • OpenHarmony 3.2 Beta源码分析之MediaLibrary
     1.MediaLibrary介绍OpenAtomOpenHarmony(以下简称“OpenHarmony”)MediaLibrary媒体库提供了一系列易用的接口用于获取媒体文件元数据信息。MediaLibrary接口是OpenHa......
  • 源码安装apache脚本部署
    源码安装apache脚本部署[root@localhost~]#lsanaconda-ks.cfghttpd.tar.xz[root@localhost~]#tarxfhttpd.tar.xz解压存放脚本的压缩包[root@localhost~]#l......
  • springboot拦截器
    packagecom.module.interceptor;importlombok.Data;importlombok.extern.slf4j.Slf4j;importorg.springframework.context.annotation.Configuration;importorg......
  • springboot内置tomcat配置本地文件夹的映射路径
    例如要访问的本地路径是D盘下的PersonalHomePage目录的某个图片1importorg.springframework.context.annotation.Configuration;2importorg.springframework.web.......
  • Spring(三):IoC的本质
    一、图例  对照上面的图,我们回想上一篇中几个代码的实现,在没有set注入之前,代码运行完全由Service层控制,用户没有选择权,选择权在程序员手中;但是使用set注入之后,用户可......
  • springboot中解析JSON参数
    解析psot请求中的JSON参数Map<String,String>attrMap=newHashMap<String,String>();BufferedReaderstreamReader=null;try{streamReader=newBufferedRead......
  • Java【SpringBoot】——添加测试依赖
    在pom.xml添加依赖1<dependency>2<groupId>org.springframework.boot</groupId>3<artifactId>spring-boot-starter-test</artifactId>......
  • springboot集成mybatis获取插入数据的主键
    问题:我们想在插入一条数据后同时能够返回这条数据在表中的id,Mybatis提供了@SelectKey注解。student为数据表,主键自增SelectKey的四个属性:selectKey会将SELECTLAS......
  • bootstrap5源码解读
    ######################## 001:  (1)@charset "UTF-8":声明该css文件的编码为UTF-8:(2):root{}:在根元素html中声明自定义属性,这样其他任何元素都可使用这些自定义属......
  • SpringBoot集成Mybatis 实现InsertOrUpdate功能
    需求场景在项目开发过程中,难免会遇到这样的场景:对一张表,当数据不存在的时候,进行insert插入操作;数据存在的时候,进行update更新操作;下面就来使用Mybatis的InsertOrUpdate功......