• 【SpringBoot】Re 01 补充学习


    对SpringBoot后续的再补充学习:

    使用IDEA创建项目不勾选任何组件

    默认的POM结构:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.2.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>cn.dai</groupId>
        <artifactId>spirngboot</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>spirngboot</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
    
            <!--  运行核心 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <!-- 测试环境支持 -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <build>
            <!-- 项目打包插件 -->
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>

    所谓的组件也就是一个个的组件坐标,我们可以自行配置。

    这里的一些常用组件可以在IDEA初始化项目之后放POM里面:

     <!-- 实体类简化辅助 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
    
            <!-- MVC支持 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- 热部署与开发帮助支持 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
    
            <!-- 配置文件依赖提示支持 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
            </dependency>

    BeanDefinition对象

    在之前的Spring理解是:

    一个类ClassA.java注解了SpringBean,或者使用了Spring的XML配置,通过注解和XML配置的信息

    我们就可以得到一个Bean对象,这个Bean对象由Spring管理和创建

    但是现在不一样,这个实例是由BeanDefinition创建而来:

    Bean定义对象存储了Bean对象的描述信息

    OriginClass.java 
            |
    BeanDefinition.java
            |
    BeanOriginClass.java

    所在位置:

    是一个接口,其实现类众多

    org.springframework.beans.factory.config.BeanDefinition

    属性:

    String getParentName(); 父类名称
    String getBeanClassName(); Bean的类名称
    getScope(); 获取对象模式,单利还是原型
    isLazyInit(); 是否懒加载
    ... 

    如何证明BeanDefinition创建

    首先是一个类A,标注了Spring组件:

    @Component
    public class ClassA {
        public ClassA() {
            System.out.println("A实例被创建");
        }
    }

    其次一个类B组合了类A也标注了组件

    但是类A属性不自动装配:

    @Component
    public class ClassB {
    
        private ClassA classA;
    
        public ClassB() {
            System.out.println("B实例被创建");
        }
    
        public ClassA getClassA() {
            return classA;
        }
    
        public void setClassA(ClassA classA) {
            this.classA = classA;
        }
    }

    注册配置:

    @Configurationpublic class TestConfiguration {
    
        @Bean
        public ClassB classB() {
            return new ClassB();
        }
    
        @Bean
        public ClassA classA() {
            return new ClassA();
        }
    }

    我们运行测试类很正常的发现在类B中的类A得到的是空

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = TestConfiguration.class)
    public class DefinitionTest {
    
        @Autowired
        private ClassB classB;
    
        @Test
        public void testSample() {
            System.out.println(classB.getClassA());
        }
    }

    结果:

    B实例被创建
    A实例被创建
    null
    
    Process finished with exit code 0

    我们可以通过定义对象去改变:

    @Component
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    //         GenericBeanDefinition classAGenericBeanDefinition = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("classB");
    //         classAGenericBeanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
    
            RootBeanDefinition classARootBeanDefinition = (RootBeanDefinition)configurableListableBeanFactory.getBeanDefinition("classB");
            classARootBeanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
        }
    }

    配置类加载:

    @Configuration
    @Import(MyBeanFactoryPostProcessor.class)
    public class TestConfiguration {
    
        @Bean
        public ClassB classB() {
            return new ClassB();
        }
    
        @Bean
        public ClassA classA() {
            return new ClassA();
        }
    }

    测试结果类A实例能够获取:

    B实例被创建
    A实例被创建。。。
    cn.dzz.bean.ClassA@587e5365
    
    Process finished with exit code 0

    但是注意类B需要提供对应的GETTER & SETTER

    在上面的定义修改中,Generic的实现类并不能被运行:

    Caused by: 
      java.lang.ClassCastException:
        org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$ConfigurationClassBeanDefinition
        cannot be cast to org.springframework.beans.factory.support.GenericBeanDefinition

    并不能强转为这个$ConfigurationClassBeanDefinition

    所以需要查看下面有哪些子实现类

    查看方式是点击这里:

    Bean构造器参数值注入 ConstructorArgumentValues 

    这里有一个配置的问题,我们的类注册只能这样注解才能让定义处理器生效

    就是让Spring以包扫描的方式进行

    @Configuration
    @ComponentScan("cn.dzz")
    public class TestConfiguration {
    }

    不能以Import方式和@Bean配置类写方法的方式进行导入

    类C的构造器声明:

    @Component
    public class ClassC {
    
        public ClassC() {
            System.out.println("无参数");
        }
    
        public ClassC(int i) {
            System.out.println("一个整数参数");
        }
    
        public ClassC(String i,int ii) {
            System.out.println("一个字符参数,一个整数参数");
        }
    
    }

    构造器方法注入定义修改

    @Component
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
             GenericBeanDefinition classAGenericBeanDefinition = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("classB");
             classAGenericBeanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
    
    //        RootBeanDefinition classARootBeanDefinition = (RootBeanDefinition)configurableListableBeanFactory.getBeanDefinition("classB");
    //        classARootBeanDefinition.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
    
    //        RootBeanDefinition classCRootBeanDefinition = (RootBeanDefinition)configurableListableBeanFactory.getBeanDefinition("classC");
    //        ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
    //        constructorArgumentValues.addIndexedArgumentValue(0,"哈哈哈");
    //        constructorArgumentValues.addIndexedArgumentValue(1,233);
    //        classCRootBeanDefinition.setConstructorArgumentValues(constructorArgumentValues);
    
            GenericBeanDefinition classCGenericBeanDefinition = (GenericBeanDefinition)configurableListableBeanFactory.getBeanDefinition("classC");
            ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
            constructorArgumentValues.addIndexedArgumentValue(0,"哈哈哈");
            constructorArgumentValues.addIndexedArgumentValue(1,233);
            classCGenericBeanDefinition.setConstructorArgumentValues(constructorArgumentValues);
        }
    }

    测试结果:

    A实例被创建
    B实例被创建
    一个字符参数,一个整数参数
    cn.dzz.bean.ClassA@2638011
    
    Process finished with exit code 0

    Scope定义的修改

     首先默认取两个对象测试:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = TestConfiguration.class)
    public class DefinitionTest {
    
        @Autowired
        private ClassB classB;
    
        @Autowired
        private ClassC classC01;
        @Autowired
        private ClassC classC02;
    
    
        @Test
        public void testSample() {
            System.out.println(classB.getClassA());
    
            System.out.println(classC01 == classC02);
        }
    }

    结果为True,因为我们知道Spring默认了Bean的Scope为单例Singleton

    A实例被创建
    B实例被创建
    一个字符参数,一个整数参数
    一个字符参数,一个整数参数
    cn.dzz.bean.ClassA@117e949d
    true
    
    Process finished with exit code 0

    但是在上面的自定义的定义处理器更改Scope为原型模式之后则为False了

    classCGenericBeanDefinition.setScope("prototype");

    结果:

    A实例被创建
    B实例被创建
    一个字符参数,一个整数参数
    一个字符参数,一个整数参数
    cn.dzz.bean.ClassA@117e949d
    false
    
    Process finished with exit code 0
  • 相关阅读:
    SpringCloud微服务初步认识
    SpringCloud-Hystrix:服务熔断与降级
    List接口下重要集合源码分析
    高频面试题:手写一个LRU
    Java基础面试题面经整理(持续更新)
    Redis高可用之主从复制
    Redis过期键删除和内存淘汰
    Redis持久化(RDB与AOF)
    了解Redis事务
    Redis入门与安装
  • 原文地址:https://www.cnblogs.com/mindzone/p/13423068.html
Copyright © 2020-2023  润新知