SpringBoot_第四章(自动装配原理分析)

目录

1:自动装配

1.1:未使用自动装配之前

1.2:初步了解自动装配

2:自动装配、按需加载

2.1:首先来了解springboot的启动类注解

2.2:@Import({Registrar.class}) 注解的源码

2.3:@Import({AutoConfigurationImportSelector.class})  注解的源码

2.4:自动装配含义

2.5:自动装配扩展

3:注解说明

3.1:@Component注解

3.2:@Configuration和@Bean注解 

3.3:@Import注解(自动装配的核心底层实现)

3.4:@ImportResource注解

3.5:@ConfigurationProperties和@EnableConfigurationProperties注解

3.6:@validation注解


1:自动装配

1.1:未使用自动装配之前

在传统的springmvc项目中,当我们需要使用mvc模块、mysql数据模块、redis缓存模块的时候。我们需要导入依赖的jar,然后在spring的配置文件中配置dataSource、sqlsessionFactory、internalResourceViewResolver(视图解析器)、multipartResolver(文件上传)、事务管理器等模块。把这些我们需要的模块变成bean,给spring管理。

在了解自动装配之前,我们首先来回顾一下以前的springMVC项目。在MVC中我们使用容器依赖的bean的时候需要在xml中配置声明才能使用,比如springmvc中的以下配置

在web.xml中配置dispatcherServlet和filter

在bean.xml配置视图解析器、文件上传multipartResolver、数据源等配置

没用使用自动装配之前,这些庞杂的web配置是每一个项目必须的。我们首先在pom中引入相关的jar。然后再xml中一遍一遍的配置这些东西。 十分复杂低效。

1.2:初步了解自动装配

springboot是一个脚手架工具,约定大于配置。我们只需要按照springboot的规范来开发,就能减少很多配置,当需要开发web项目的时候。

第一步:引入web包的starter启动器。这个包就包含了web的所需的主要功能,同时能导入springweb相关的依赖jar。比如spring,springmvc的包和tomcat的包。点击pom可查询。

  <!--springboot的web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

第二步: 我们启动springboot项目之后,就能看到所有的bean。这些bean在容器加载的时候就会把bean自动加载进来。

@SpringBootApplication(scanBasePackages = "com.thits")
@ImportResource(value = "bean.xml") //装配xml文件配置的bean

public class SpringBoot1Application {

    public static void main(String[] args) {
        //返回ioc容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringBoot1Application.class, args);
        //获取容器中的所有bean
        String[] beanDefinitionNames = run.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("bean的名字:"+beanDefinitionName);
        }
    }

}

截图可以看到控制台的各种bean已经被spring容器管理了。 比如multipartResolver、DispatcherServlet、视图解析器、事务管理器等。我们就可以直接使用了,不需要在xml中配置这些东西了。

 

2:自动装配、按需加载

2.1:首先来了解springboot的启动类注解

@SpringBootApplication
public class SpringBoot1Application {
    //程序的主入口
    public static void main(String[] args) {
        SpringApplication.run(SpringBoot1Application.class, args);
    }

}

在启动类中有一个注解就是@SpringBootApplication,他有三个子注解,子注解又有其他的注解,搞清楚这些注解的意思就能理解自动装配了。

  • @SpringBootApplication(有三个子注解,分比为1、2、3
  •         1:@SpringBootConfiguration    (有一个子注解:Configuaration)
  •                 1.1:@Configuaration    (有一个子注解:Component)
  •                         1.1.1:@Component (作用:就是启动类声明为bean
  •         2:@EnableAutoConfiguration    (开启自动注入:有两个子注解
  •                 2.1:@AutoConfigurationPackage  (自动配置包:有一个子注解,import
  •                         2.1.1:@Import({Registrar.class})      (没有子注解)
  •                 2.2:@Import({AutoConfigurationImportSelector.class})    (没有子注解)
  •         3:@ComponentScan  (组件扫描:没有子注解,作用:包扫描项目包路径

在这三个注解中,第一和第三都没有太大的意思,所以我们主要看第二个注解就好了。在第二个注解中使用了两个@import注解。就是这两个注解解释了自动装配的含义。

2.2:@Import({Registrar.class}) 注解的源码

 @Import({Registrar.class})源码的作用就是:主启动类注册到容器,也就是main方法所在的包下边,将所有的我们自己的代码中的配置注入的bean容器。

2.3:@Import({AutoConfigurationImportSelector.class})  注解的源码

源码的第一步就是实现ImportSelector接口的ImportSelector方法,根据类的全部限定名字把类注入到容器(参见import注解的用法),注入了那些类呢?接着看源码

此处源码是获取自动装配的配置类。获取了138个,在哪里获取接着看。 

 这里的代码就能看出来去哪里加载了这些自动装配的类,在factories文件中。

我们查看autoconfigure的jar下边的factories文件就能看到这些指定的自动装配类全类名了。

2.4:自动装配含义

springboot自动装配:

这就是自动装配,通过@SpringBootApplication注解的两个Import子注解 ,把spring-boot-autoconfigure-2.6.7.jar和其他包的spring.factories 文件中,EnableAutoConfiguration配置的所有类都装配到spring容器中了。

2.5:自动装配扩展原理(Condition按需加载)

springboot自动装配的扩展:两个疑难问题讲解

问题1:我们查看spring.factories中有当前版本支持的所有配置类,这些配置类都会注入bean吗?

答:并不是,之后我们需要导入相对的jar包,这个类是真是存在的,然后才可以自动装配这些bean。

举例说明:在spring.factories中有很多配置类,我们截取这几个来说明

举例1:我们没有配置DispatcherServlet,但是会通过自动装配,层层判断来自动创建出DispatcherServlet

 举例2:我们Aop的案例

问题2:在spring的IOC注入了这些138个配置类,我们怎么使用?

答:通过配置使用,约定大约配置。

比如我们使用文件上传。我们怎么知道配置文件上传的文件大小、文件路径等信息。在源码中我们可以看到怎么使用。约定大于配置

springboot默认创建StandardServletMultipartResolver,在源码中如下

 文件上传约定大约配置,我们都知道ConfigurationProperties注解的作用是绑定配置文件的值。这里就是约定大于配置。我们只需要按照约定来就行了

 

 

自动装配总结:

1:springboot默认加载spring.factories中指定的所有AutoConfiguration。

2:根据这些AutoConfiguration的源码,在里边的条件@conditional判断是否真正的使用这些类。

3:导入的对应jar话就使用这些类,并且在绑定的Properties根据前缀中指定,然后在配置文件中配置属性

这就是自动装配了。

3:注解说明

3.1:@Component注解

使用Component注解可以使一个类直接变成spring容器可以管理的bean,

我们知道@controller @service @Repository 的注解里边都有 Component,就是直接声明自己编写的代码是bean。法

3.2:@Configuration和@Bean注解 

@Configuration注解也是把类变成bean, @bean注解用来创建具体的bean,代码案例如下。

主要作用

1:是将第三方依赖的jar的指定类变成bean,在第三方中你没法修改代码加bean注解,可以使用此种方式(new  第三方类)

2:解决组件依赖,详细见代码注释

package com.thits.springboot1.configurations;

import com.thits.springboot1.pojo1.Dog;
import com.thits.springboot1.pojo1.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Configuration相当于配置文件bean.xml 用来装配第三方bean
 *      proxyBeanMethods 有两种模式
 *           full模式 proxyBeanMethods = true 容器中只有一个bean
 *           lite模式 proxyBeanMethods = false 获取bean的方法 每次获取的都是一个新的bean
 *
 *
 *  ConditionalOnBean(name="bean名字")
 *  对方bean存在 自己也就存在(处理依赖条件)
 *   跟方法顺序有关系
 *
 *
 *   ConditionalOnMissingBean
 *   对方bean不存在 自己也就存在(处理依赖条件)
 *   缺失了才能创建
 *
 *
 */
@Configuration(proxyBeanMethods=true)
public class ConfigurationBeans {
    /**
     * 方法名 就是容器中的bean的名字
     * 主要作用有两个:
     *
     * 1:引入了其他的jar。里边有些类我想让容器管理 变成bean
     *    我们无法直接需改人家的源码,加上注解。这个时候使用此方法来new对象,创建外部的bean
     *
     * 2:结合Configuration注解来实现组件依赖
     *   我们创建的user11bean依赖dog的bean,
     *   我们就可以设置proxyBeanMethods=true
     *   使用的都是容器中存在的单例dog的bean
     * @return
     */
    @Bean(name = "user11")
    @ConditionalOnMissingBean(name = {"dog1"})
    //Conditiona注解跟下边的两个方法顺序有关
    public User user1(){
        //user组件依赖dog组件
        Dog dog=dog1();
        return new User(1,"李四",dog);
    }

    @Bean
    public Dog dog1(){
        return new Dog();
    }


}


@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @Value("1")
    private int id;
    @Value("张三")
    private String name;

    private Dog dog;

}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dog {

    @Value("黄色")
    private String color;
    @Value("大黄狗")
    private String name;
}

扩展1:无论@Configuration(proxyBeanMethods=true)还是false,注入的话都是一个bean

   //返回ioc容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringBoot1Application.class, args);

        User bean1 = run.getBean("user11", User.class);
        User bean2 = run.getBean("user11", User.class);
        System.out.println("咱们使用@Autowired注入的bean,不论false还是true都是单例:"+(bean1==bean2));//true

扩展2:@Configuration(proxyBeanMethods=false)或者true,直接使用方法获调用取bean,才会出现容器检查bean是否存在的情况,用来解决组件依赖

   //bean的测试 通过方法获取,注意是直接调用方法
        System.out.println("===============获取@Configuration注解的bean================");
        ConfigurationBeans configurationBeans = run.getBean("configurationBeans", ConfigurationBeans.class);
        
        //获取ConfigurationBeans  @Configuration(proxyBeanMethods = false)
        //当true的时候 容器检查存在实例 这里是调用方法获取实例 返回容器中的实例 所以输出结果是相等 ture 
        //false的时候 容器不会检查是否存在实例 这里是调用方法每次方法获取实例 所以输出结果是不相等  false
        User user = configurationBeans.user1();
        User user1 = configurationBeans.user1();
        System.out.println(user);//通过方法获取bean
        System.out.println(user1);
        System.out.println("设置proxyBeanMethods比较:" + (user == user1));
        System.out.println();

3.3:@Import注解(自动装配的核心底层实现)

 Import注解的作用:也是注入第三方类让他变成容器管理的bean,比@Configuration结合@bean功能更加单一。但是更加暴力简单

实现1:@import(类.class) 直接指定类让容器管理

实现2:@import(选择器.class) 实现选择器,让选择器可以使用数组,把很多类都注入到容器中,这就是依赖注入的核心代码

3.4:@ImportResource注解

作用:我们可以使用ImportResource注解,来装配配置文件xml中的bean。

在springboot项目中,都是使用了注解,但是外部可能存在spring的XML文件里边声明了bean。导致无法使用,所用使用importresource注解来装配bean

用法案例:类和bean声明。 

 

测试代码:

3.5:@ConfigurationProperties和@EnableConfigurationProperties注解

@ConfigurationProperties作用:此注解的作用是,将spring的properties或者yml中配置的属性值,注入到bean中必须和@Component注解结合使用

@EnableConfigurationProperties作用:开启配置绑定,将类变成bean,然后结合@ConfigurationProperties 和@EnableConfigurationProperties(Person.class)使用

测试代码:

配置提示依赖代码包

 <!-- 自定义bean:person yml中的提示-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

3.6:@validation注解

作用:主要用来验证前端传递过来的数据,是否合乎规范

使用案例:

第一步:导入jar

  <!--JSR 303  效验-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

第二步:在实体类上使用注解validation,属性上使用其他的@notnull@max等注解,限制属性的范围

/**
 * 验证yml的值绑定
 */
@Data
@AllArgsConstructor
@NoArgsConstructor

@Component//定义为bean
@ConfigurationProperties(prefix = "person")//绑定配置文件属性
@Validated //jsr 303验证属性
public class PersonYml {

    @Max(value = 40,message = "年龄太大了")
    private int age;

    @NotNull(message = "名字不能为空")
    private String name1;

    @NotNull
    @Email(message = "邮箱格式不合法")
    private String email;

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date brith;

    @AssertFalse
    private boolean happy;
    private String[] like;

    private Cat cat;
    private Map<String,Object> maps;
    private List<Object> list;
}

测试代码见3.5的截图,里边有注释和测试。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值