【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

 

posted @ 2020-08-18 22:17  emdzz  阅读(290)  评论(0编辑  收藏  举报