• 【Spring之底层核心架构概念解析】



    前置准备测试对象User:

    
    public class User {
    
        public User(int flag, String uuid){
            System.out.println(flag+"----------"+uuid);
        }
    
        public User(){
            System.out.println("User 无参构造");
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    一、BeanDefinition

    BeanDefinition表示Bean的定义,其可记录Bean的特征,例如:

    1. Bean的类型:beanClass属性
    2. Bean的作用域:Scope属性
    3. Bean是否为懒加载:lazyinit属性

    在Spring中,定义一个bean的方式主要有:XML文件中使用bean标签来定义其bean属性,除此外,可以使用@Bean注解以及@Component等注解来定义注解,当然,也可以使用编程式来定义Bean,如下代码:

    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
    
            //定义一个BeanDefinition对象
            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
            //向BeanDefinition对象中添加对象信息
            beanDefinition.setBeanClass(User.class);
            beanDefinition.setScope("prototype");
            //将BeanDefinition对象加入到Spring容器中
            context.registerBeanDefinition("user",beanDefinition);
    
            System.out.println("Spring BeanDefinition 创建的user对象为:"+context.getBean("user"));
    
            UserService userService = (UserService) context.getBean("userService");
            userService.test();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    二、BeanDefinitionReader

    其表示BeanDefinition读取器,主要的读取方式有以下两种

    2.1、AnnotatedBeanDefinitionReader

    这个组件可以将某各类直接转换为BeanDefinition,并且会解析该类上的注解,测试代码如下:

    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
            //声明一个BeanDefinition读取器,并在这个读取器中传入Spring容器
            AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
    
            annotatedBeanDefinitionReader.register(User.class);
            System.out.println("BeanDefinition读取器AnnotatedBeanDefinitionReader创建bean为:"+context.getBean("user"));
    
            UserService userService = (UserService) context.getBean("userService");
            userService.test();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    2.2、XmlBeanDefinitionReader

    该接口主要是通过解析XML文件中的Bean标签进行BeanDefinition转换,代码如下:

    XML配置文件信息:
    在这里插入图片描述

    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
            //声明一个BeanDefinition读取器,并在这个读取器中传入Spring容器
            XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
    
            int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
            System.out.println("扫描到bean标签数量:"+i);
            System.out.println("BeanDefinition读取器XmlBeanDefinitionReader创建bean为:"+context.getBean("user"));
    
            UserService userService = (UserService) context.getBean("userService");
            userService.test();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    五、ClassPathBeanDefinitionScanner

    其为BeanDefinition资源扫描器,作用和BeanDefinitionReader类似,只是读取的方式是以指定路径的方式扫描类资源,对扫描到的类进行解析,是否包含其相关注解信息,例:如果类中包含@Component注解,就会将该类作为BeanDefinition对象放入到Spring容器中,代码如下:

    @Component
    public class UserService {
        public void test(){
            System.out.println("test--->Spring创建对象");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.refresh();
            //声明一个BeanDefinition读取器,并在这个读取器中传入Spring容器
            ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
    
            int scan = scanner.scan("com.practice.service");
            System.out.println("指定路径下,扫描到的bean资源数量:"+scan);
            System.out.println("ClassPathBeanDefinitionScanner扫描器创建bean为:"+context.getBean("userService"));
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    六、BeanFactory

    BeanFactory会负责创建Bean,并且提供获取Bean的API

    七、ApplicationContext

    ApplicationContext是BeanFactory的一种,其在Spring的源码中的定义为:
    在这里插入图片描述

    图中的ListableBeanFactory和HierarchicalBeanFactory都继承至BeanFactory,所以ApplicationContext也是具备BeanFactory具备的特性和功能,但是,ApplicationContext还具备额外的功能,例如,支持国际化、支持获取环境信息、支持事件发布和相关资源加载,其有两个实现类,如下介绍

    7.1、AnnotationConfigApplicationContext

    其源代码如下:
    在这里插入图片描述

    AnnotationConfigApplicationContext继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了其父类以及父接口以及父接口继承甚至更向上的接口所有的功能

    7.2、ClassPathXmlApplicationContext

    在这里插入图片描述
    其是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition

    八、类型转换

    在Spring中,有可能会存在一些类型转换的问题,其Spring中提供了一些技术来方便做类型转换操作,在Spring源码中,与存在许多类型转换的操作,类型转化主要有以下接口

    8.1、PropertyEditor

    这是JDK自带的类型转换工具类,具体使用如下:

    public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            User user = new User();
            user.setName(text);
            this.setValue(user);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) {
    
            StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();
            propertyEditor.setAsText("1");
            User value = (User) propertyEditor.getValue();
            System.out.println(value);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    8.2、ConversionService

    Spring中提供的类型转化服务,它比PropertyEditor更强大,其代码如下:

    public class StringToUserConverter implements ConditionalGenericConverter {
        @Override
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            return sourceType.getType().equals(String.class) &&
                    targetType.getType().equals(User.class);
        }
        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
            return Collections.singleton(new ConvertiblePair(String.class, User.class));
        }
        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor
                targetType) {
            User user = new User();
            user.setName((String)source);
            return user;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) {
    
            DefaultConversionService conversionService = new DefaultConversionService();
            conversionService.addConverter(new StringToUserConverter());
            User value = conversionService.convert("1", User.class);
            System.out.println(value);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    8.3、TypeConverter

    整合了PropertyEditor和ConversionService的功能,是Spring内部用的,如下:

    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) {
    
            SimpleTypeConverter typeConverter = new SimpleTypeConverter();
            typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());
            User value = typeConverter.convertIfNecessary("1", User.class);
            System.out.println(value);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    九、FactoryBean

    我们想一个Bean完完全全由我们来创造,可以通过FactoryBean来完成,如下:

    public class factoryBeanTest implements FactoryBean {
        @Override
        public Object getObject() throws Exception {
            UserService userService = new UserService();
            return userService;
        }
        @Override
        public Class<?> getObjectType() {
            return UserService.class;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    通过上面这段代码,我们自己创造了一个UserService对象,并且它将成为Bean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入

    十、ExcludeFilter和IncludeFilter

    这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器,如下:
    在这里插入图片描述

    在这里插入图片描述
    FilterType分为:
    1. ANNOTATION:表示是否包含某个注解
    2. ASSIGNABLE_TYPE:表示是否是某个类
    3. ASPECTJ:表示否是符合某个Aspectj表达式
    4. REGEX:表示是否符合某个正则表达式
    5. CUSTOM:自定义

    十一、MetadataReader、ClassMetadata、AnnotationMetadata

    在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类
    MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。代码如下示例:

    package com.practice.service;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class UserService {
        public void test(){
            System.out.println("test--->Spring创建对象");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    //Spring核心概念测试类
    public class TestSpringDemo {
        public static void main(String[] args) throws IOException {
    
            SimpleMetadataReaderFactory simpleMetadataReaderFactory = new
                    SimpleMetadataReaderFactory();
            // 构造一个MetadataReader
            MetadataReader metadataReader =
                    simpleMetadataReaderFactory.getMetadataReader("com.practice.service.UserService");
            // 得到一个ClassMetadata,并获取了类名
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            System.out.println(classMetadata.getClassName());
            // 获取一个AnnotationMetadata,并获取类上的注解信息
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            for (String annotationType : annotationMetadata.getAnnotationTypes()) {
                System.out.println(annotationType);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    注:SimpleMetadataReader去解析类时,使用的ASM技术。因为Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。

  • 相关阅读:
    2、HTML常用标签
    Java 华为真题-出租车计费
    Java设计模式之简单工厂模式(不属于23种设计模式)
    【Docker】学习笔记
    狂刷《Java权威面试指南(阿里版)》,冲击“金九银十”有望了
    【C/C++笔试练习】——printf在使用%的注意事项、for循环语句的三个条件、运算符优先级、删除公共字符
    Seatunnel系列之:深入理解Seatunnel,快速应用Seatunnel实现数据同步
    基于java+springboot+mybatis+vue+elementui的旅游景点门票购票网站
    【编程强训11】最近公共祖先+求最大连续bit数
    K8s进阶6——pod安全上下文、Linux Capabilities、OPA Gatekeeper、gvisor
  • 原文地址:https://blog.csdn.net/weixin_42070243/article/details/134331776