• 【05】Spring源码-手写篇-手写Bean配置


    在这里插入图片描述

    Spring源码手写篇-Bean定义配置化

    一、Bean定义配置分析

      我们前面实现了手写IoC和AOP的功能,但是我们在使用的时候发现我们的调用代码还是非常的繁琐,会给应用者很不好的体验。

    image.png

      上面的代码很直观的看到重复代码很多,要用户设置的内容也很多,低效而且容易出错,这时我们可以看看在Spring中是怎么处理的呢?

    一种是通过XML的配置文件方式

    
    <beans>
        <bean id="abean" class="com.study.spring.samples.ABean">
            <constructor-arg type="String" value="abean01" />
            <constructor-arg ref="cbean" />
        bean>
    
        <bean id="cbean" class="com.study.spring.samples.CBean">
            <constructor-arg type="String" value="cbean01" />
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    一种是通过注解的方式来处理

    @Component
    public class AController{
    
        @Autowired
        private Acc ac;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1. XML方式实现

    基于XML方式实现我们需要做什么操作呢?

    • 定义XML规范
    • 要写代码来解析XML,完成Bean定义的注册

    2.注解方式实现

    基于XML方式实现我们需要做什么操作呢?

    • 定义一套注解
    • 要写代码来扫描、解析注解、完成Bean定义注册。

    二、Bean定义配置实现

    1. XML方法设计

      xml方式的流程如下:

    image.png

    我们可以自己写一个解析器,专门来解析对应的xml文件

    image.png

    2. 注解方式设计

    2.1 定义相关的注解

      然后我们来看看需要定义的注解有哪些。

    • 类要不要配置为Bean @Component
    • BeanName Scope和Primary @Scope @Primary
    • 工厂方法 工厂Bean @Bean
    • 初始化方法、销毁方法 @PostConstruct @PreDestory
    • 构造参数依赖 @Autowired @Value
    • 属性依赖 @Qualifier

    image.png

    2.2 扫描解析注册操作

      我们定义了相关注解后,谁来实现扫描注解、解析注解并完成Bean定义注册呢

    image.png

    先来看如何实现扫描操作

    image.png

    实现的逻辑应该是递归找出包目录下的所有的.class 文件。

        public void scan(String... basePackages) throws Throwable {
            if (basePackages != null && basePackages.length > 0) {
                for (String p : basePackages) {
    				/*
    				 1 递归扫描包目录下的.class文件
    				 2 组合包路径+class文件名 得到全限定类名
    				 3 ClassLoad.load("类名") 得到 Class 对象
    				 4 解析Class上的注解,获得Bean定义信息,注册Bean定义
    				 */
    
                    //1 递归扫描包目录下的.class文件
                    Set<File> classFiles = this.doScan(p);
                    //2 得到Class对象,并解析注解、注册Bean定义
                    this.readAndRegisterBeanDefintion(classFiles);
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    然后看看如何来解析类注解

    image.png

        private void readAndRegisterBeanDefintion(Set classFiles) throws BeanDefinitionRegistException {
            for (File classFile : classFiles) {
                String className = getClassNameFromFile(classFile);
                try {
                    //加载类
                    Class clazz = this.getClass().getClassLoader().loadClass(className);
                    Component component = clazz.getAnnotation(Component.class);
                    if (component != null) {// 标注了@Component注解
                        String beanName = component.value();
                        if (StringUtils.isBlank(beanName)) {
                            beanName = this.generateBeanName(clazz);
                        }
                        GenericBeanDefinition bd = new GenericBeanDefinition();
                        bd.setBeanClass(clazz);
    
                        //处理Scope
                        Scope scope = clazz.getAnnotation(Scope.class);
                        if (scope != null) {
                            bd.setScope(scope.value());
                        }
                        //处理primary
                        Primary primary = clazz.getAnnotation(Primary.class);
                        if (primary != null) {
                            bd.setPrimary(true);
                        }
    
                        // 处理构造方法,在构造方法上找@Autowired注解,如有,将这个构造方法set到bd;
                        this.handleConstructor(clazz, bd);
    
                        //处理方法上的注解(找出初始化、销毁、工厂方法)
                        this.handleMethod(clazz, bd, beanName);
    
                        // 处理属性依赖
                        this.handlePropertyDi(clazz, bd);
    
                        // 注册bean定义
                        this.registry.registerBeanDefinition(beanName, bd);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    3.ApplicationContext

      通过上面的设计,我们可以实现注解的方式来定义,但是给用户的整体体验还是不是很好,这时我们可以通过外观模式,为框架定义一个更简单的统一使用界面

    image.png

    组合为:

    image.png

  • 相关阅读:
    Dubbo-聊聊通信模块设计
    Spring5应用之AOP概念详解
    小学期-中期总结报告
    Idea创建springboot工程的时候,发现pom文件没有带<parent>标签
    摸鱼大数据——Kafka——kafka tools工具使用
    2023最新SSM计算机毕业设计选题大全(附源码+LW)之java双笙映画ou5oj
    怒啃 24 小时,终于搞懂上下文切换!
    Python四大数据结构整理
    echarts快速实现迁徙地图
    Nginx内置变量详解
  • 原文地址:https://blog.csdn.net/qq_38526573/article/details/126752265