SpringBoot自动化原理

SpringBoot自动化原理

在了解SpringBoot之前我们先要了解SpringBoot的相关注解和流程
SpringBoot相关注解如图:
SpringBoot自动化原理_第1张图片
SpringBoot的启动流程如图:
SpringBoot自动化原理_第2张图片
1、在SpringBoot使用过程中,我们使用到某个模块的功能,为什么依赖场景有的要写版本号,有的不用写呢?
比如webmvc,junit,redis不需要,mybatis需要
我们的工程继承了SpringBoot的夫工程Spring-boot-starter(版本2.3.10.release)
这个工程提供了53个场景,每个场景都搭建好了环境,并进行了版本锁定(比如webmvc场景引入了需要spingmvc包和tomcat插件等,做好了适配)所以对于springboot中提供的场景,无需编写版本号
但是对于springboot中没有提供的场景,而是第三方定义的场景,就需要编写版本号
2、我们使用springboot之后,springboot做了什么,让我们省略了很多繁杂的配置
这就需要了解springboot的自动化配置原理了大致可以简单的描述为:
1)springboot启动的时候都会加载每个场景下的xx-starter的METAINF/spring.factories文件类似于java中的spi机制
2)这个文件下有自动装配类
3)自动装配类中有很多配置类
4)只要满足特定条件下的配置类会被spring加载到IOC
这一套流程为开发者省略了很多繁杂的配置,体现了springboot约定大于配置的思想
3、如果我们搞懂了springboot的自动化配置原理是不是可以自己定义一些场景了?
是的,而且我们开发的项目中也需要根据业务封装一些场景
但是学习springboot的自动化配置原理不是简单的事:
1)spi机制
2)各种注解,接口和类

【2】SpringBoot自动装配预览

SpringBoot自动化原理_第3张图片
SPI全程Service Provider Interface ,是java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。说白了,java的spi机制就是将一些类信息写在约定的文件中,然后由特定的类加载器加载解析文件获取资源;

SPI使用场景

场景 说明
数据库驱动 数据库驱动加载接口实现类的加载不同类型的数据库驱动
日志门面SLF4J接口实现类加载 SLF4J加载不同提供商的日志实现类
Spring Spring中大量使用了spi,比如对servlet3.0规范对ServletContainerInitializer的实现,自动类型转换Type Conversion SPI(Converter SPI、Formatter SPI)等
Dubbo Dubbo中也大量使用spi的方式实现框架的扩展,不过对java提供的原生spi做了封装,允许用户扩展实现Filter接口
SpringBoot 基于SPI思想实现自动装配

SpringBoot自动化原理_第4张图片
java SPI实际上是基于接口编程+策略模式+配置文件组合实现的动态加载机制;

SpringBoot高级场景依赖starter介绍

通过依赖能了解SpringBoot管理了那些starter
1.通过依赖spring-boot-dependencies搜索starter发现非常多的官方starter,并且已经帮助我们管理好了版本提供了53个场景依赖
2.项目中使用直接引入对应的starter即可,这个场景下所有的依赖就会自动导入到项目中,简化了繁琐的依赖。
3.引入starter不仅仅是帮助我们管理了依赖,还帮我们做了很多默认的配置信息,简化了大量的配置,使用更加的简单。
4.大多数场景启动器的底层依赖spring-boot-starter【为场景依赖提供spring的核心环境】

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
   <version>2.3.10.RELEASE</version>
   <scope>compile</scope>
</dependency>

1.为什么引入SpringBoot默认的场景依赖,无需书写版本号

因为父工程通过dependentManager标签进行了版本的锁定与声明;

2.再配置满足当前开发需要的前提,为什么建议使用默认的配置

1.基于约定优于配置思想,减少开发中的繁琐的配置
2.SpringBoot帮助我们解决了资源依赖间版本兼容和冲突等问题

02-SpringBoot2高级-自动化配置初体验

目的:以spring-boot-starter-web场景依赖中自动化配置原理为例讲解,能够理解web MVC自动化配置加入那些依赖,做了那些默认配置
SpringMvc配置流程
1、首先添加SpringMvc相关的依赖资源spring-webmvc.jar、jackson相关,servlet相关等;
2、定义springmvc.xml配置文件,进行如下的配置
1).扫描controller所在包;
2).配置annotation-driven支持mvc扩展功能
3).试图解析器
4).静态资源
5).拦截器
6).
【1.3】配置web.xml
1、初始化spring容器
2.初始化springmvc DispatcherServlet核心调度器
3.请求乱码过滤器
4.配置tomcat,部署项目
也就是说在我们开发业务代码前,就必须要准备好这些环境,否则业务功能无法实现。

web场景依赖原理分析

当我们基于springboot使用web场景依赖时,我们发现要搭建一个标准的mvc工程,只需要引入spring-boot-starter-web场景依赖即可,几乎无需做其他配置,在这个过程中SpringBoot为我们做了大量的自动化配置工作;
接下来我们就探索一下SpringBoot是如何帮助我们完成强大而又简单自动化配置的。
引入web开发场景启动器依赖:

<!--web开发的起步依赖   场景启动器依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

我们发现spring-boot-starter-web场景依赖帮我们做了很多事:
引入webmvc工程相关的依赖资源:
SpringBoot自动化原理_第5张图片
工程自动加载依赖资源
通过断点测试SpringIOC容器,我们发现SpringBoot几乎把MVC相关的所有资源自动加载到容器中了:
SpringBoot自动化原理_第6张图片
1)自动装配SpringMVC核心组件(包括核心3大组件和文件上传等组件)

引入SpringMVC全套组件;
自动装配好SpringMVC常用组件(三大组件,文件上传等)

2)自动配好web常见功能,如:字符编码问题,静态资源管理,错误页面处理组件等;
3)SpringBoot默认自动扫描启动类同级以及所有子目录下资源;

1.引导类所在包及其下面的所有子包里面的组件会被默认扫描,无需像以前开启注解扫描
2.如果想要改变扫描路径@SpringBootApplication(scanBasePackages="com.xx.xx")或者@ComponentScan指定扫描路径

4)基于约定优于配置思想自动配置Tomcat常规参数

端口号:8080
字符键:UTF-8
参考:org.springframework.boot.autoconfigure.web.ServerProperties配置类

核心源码分析

在spring-boot-autoconfigure.jar资源包下META-INF/spring.factories文件下配置:
SpringBoot自动化原理_第7张图片
以org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration类为例,通过翻阅源码:

@Configuration(proxyBeanMethods = false)//定义配置类
@Conditional(DefaultDispatcherServletCondition.class)//满足指定条件则装配
@ConditionalOnClass(ServletRegistration.class)//满足指定类存在则装配
@EnableConfigurationProperties(WebMvcProperties.class)//加载配置对象
protected static class DispatcherServletConfiguration {
//自动装配springMVC核心调度器
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
    dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
    dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
    dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
    return dispatcherServlet;
}
//.....
}  

SpringBoot引入web场景依赖后,有什么好处
1.大量依赖资源自动装配,避免繁杂的XML配置;
2.可以使开发人员的中心聚焦与=于业务开发,提高开发效率;

SpringBoot2高级-底层原理-@Configuration配置注解

掌握@Configuration注解的作用及新特性
@Configuration注解使用
注解的作用是替代原始springXML配置文件功能
思考:
配置类中被@Bean修饰的方法被配置类bean对象多次调用返回的bean是否是同一个bean?
演示:

package com.xxx.config;

import com.xxx.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;

//proxyBeanMethods = false:方法不会被代理 LITE模式 【多例模式】
@Configuration(proxyBeanMethods = false)
public class MyConfig {

    @Bean//方法默认被代理 FULL,实现单例模式
    public User myUser(){
        User user = new User().setId(1l).setBirthday(new Date()).setUserName("张三");
        return user;
    }
}

2)在引导类编写代码测试:

package com.xx;
import com.xx.config.MyConfig;
import com.xx.pojo.User;
import org.apache.tomcat.util.net.jsse.JSSEUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.Map;

/**
 * 编写引动类/启动类
 * @SpringBootApplication注解定义当前类为springboot的引导类
 */
@SpringBootApplication
public class SpringConfigurationApp {
    /**
     * main方法是springboot
     * 启动的入口
     * @param args
     */
    public static void main(String[] args) {
        //获取ioc容器
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringConfigurationApp.class, args);
        //key:bean名称  value:bean对象
        // 发现MyConfig被cglib动态代理了:从ioc容器检查指定的bena是否存在,如果存在,直接返回ioc容器中的bean FULL
        Map<String, MyConfig> beanInfo = ctx.getBeansOfType(MyConfig.class);
        System.out.println(beanInfo);
        Map<String, User> userInfo = ctx.getBeansOfType(User.class);
        System.out.println(userInfo);
        //获取myconfig对象
        MyConfig myConfig = ctx.getBean(MyConfig.class);
        User user1 = ctx.getBean(User.class);
        User user2 = myConfig.myUser();
        System.out.println(user1==user2);
    }
}

【2】proxyBeanMethods属性说明

@Configuration注解下proxyBeanMethods属性表示代理bean的方法属性【since spring5.2】
SpringBoot自动化原理_第8张图片
功能:
proxyBeanMethods=true :Full模式(默认),保证每个@Bean方法被调用多少次返回的组件都是单实例的;
proxyBeanMethods=false:Lite模式,每个@Bean方法被调用多少次返回的组件都是新创建的
演示:
1、默认proxyBeanMethods=true,springBoot会检查这个组件是否在容器中有,有则直接引用

默认proxyBeanMethods=true,springBoot会检查这个组件是否在容器中有,有则直接引用
User user3=myConfig1.getUser();
System.out.println(user1==user3);//true

2.修改proxyBeanMethods=false,则每调用一次Spring就会创建一个新的Bean对象
SpringBoot自动化原理_第9张图片
在执行结果则为false,证明两次获取的bean不是同一个bean

【3】小结

【1】在注解@Configuration修饰的配置类下,调用构建bean的方法时,如何实现单例或者多例模式?

 # 通过proxyBeanMethods属性指定:
1. proxyBeanMethods=true :full模式,也就是单例模式,每次方法被调用时不会立即创建,会先从IOC容器检查是否有指定类型的bean,如果有,则直接返回,如果没有,调用方法创建;<br>
2. proxyBeanMethods=false:lite模式,也就是多例模式,每次方法被调用,直接创建对象;

【2】在初次构建bean对象时FULL模式与LITE模式哪个执行效率相对较高?

1. LITE模式,因为构建对象时无需从IOC容器检查对象是否存在,相对效率高一些;
2. 这也是自动化装配类选择使用LITE模式的核心原因所在(项目启动快)

04-springBoot2高级-底层原理@Import注解使用1
目的:
@Import注解学习是为接下来的源码阅读做准备的;
理解@Import注解的作用及四种使用方式;
作用:
使用@Import导入的类会被Spring加载到IOC容器中
@Import提供4中用法:
1.直接导入一个类,实例化后作为一个Bean被IOC容器管理
2.导入配置类
3.导入ImportSelector实现类。一般用于加载配置文件中的类
4.导入ImportBeanDefinitionRegistrar实现类
实现:
【1】导入Bean

package com.xxx.xxx;

import com.xxx.xxx.pojo.User;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

import java.util.Map;

@SpringBootApplication
@Import(User.class)  
//会自动执行当前类的构造方法创建对象,存到IOC容器, bean名称为:类的全路径
public class SpringConfigurationApp {
  public static void main(String[] args) {
    ConfigurableApplicationContext applicationContext = SpringApplication.run(DataApplication.class, args);
	//获取bean的名称与对象对应的键值对对象
    Map<String, User> map = applicationContext.getBeansOfType(User.class);
    System.out.println(map);
    User user1 = applicationContext.getBean("com.itheima.sh.pojo.User", User.class);
    System.out.println(user1);
  }
}

【2】导入配置类
定义配置类:

package com.xxx.config;

import com.xxx.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;

@Configuration
public class MyConfig {
    @Bean//方法默认被代理 FULL,实现单例模式
    public User myUser(){
        User user = new User().setId(1l).setBirthday(new Date()).setUserName("张三");
        return user;
    }
}

导入配置类:

package com.xxx;
import com.xxx.config.MyConfig;
import com.xxx.config.MyImportBeanDefinitionRegistrar;
import com.xxx.config.MyImportSelector;
import com.xxx.pojo.User;
import org.apache.tomcat.util.net.jsse.JSSEUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

import java.util.Map;

/**
 * 编写引动类/启动类
 * @SpringBootApplication注解定义当前类为springboot的引导类
 */
@SpringBootApplication
//方式1:导入类最终实例化成bena为ioc容器维护 bean名称:类的全限定名称
//@Import(User.class)
//方式2:导入配置类 ,配置类下的@Configuration可以省略
@Import(MyConfig.class)
public class SpringConfigurationApp {
    public static void main(String[] args) {
        //获取ioc容器
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringConfigurationApp.class, args);
        //@Import(User.class) bean名称:类的全限定名称
        Map<String, User> userBean = ctx.getBeansOfType(User.class);
        System.out.println(userBean);
        User user = ctx.getBean("com.itheima.pojo.User", User.class);
        System.out.println(user);
    }
}

05-SpringBoot2高级-底层原理-@Import注解使用2

目的:注解@Import注解使用另外两种使用方式
步骤:
1.导入ImportSelector实现类。一般用于加载配置文件中的类
2.导入ImportBeanDefinitionRegistrar实现类
实现:
【1】导入ImportSelector实现类
场景:一般用用于批量导入第三方资源bean
1、编写ImportSelector接口的实现类MyImportSelector

package com.xxxx.config;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Set;

public class MyImportSelector implements ImportSelector {
    /**
     * @Import注解打到哪个类下,那么类下的注解元数据信息通过AnnotationMetadata注入到selectImports方法下
     * 实现批量导入
     * @param annotationMetadata
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        Set<String> sets = annotationMetadata.getAnnotationTypes();
        return new String[]{"com.itheima.pojo.User"};
    }
}

2、引导类导入

package com.xxx;
import com.xxx.config.MyConfig;
import com.xxx.config.MyImportBeanDefinitionRegistrar;
import com.xxx.config.MyImportSelector;
import com.xxx.pojo.User;
import org.apache.tomcat.util.net.jsse.JSSEUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

import java.util.Map;

/**
 * 编写引动类/启动类
 * @SpringBootApplication注解定义当前类为springboot的引导类
 */
@SpringBootApplication
//方式1:导入类最终实例化成bena为ioc容器维护 bean名称:类的全限定名称
//@Import(User.class)
//方式2:导入配置类 ,配置类下的@Configuration可以省略
//@Import(MyConfig.class)
//方式3:实现批量导入组件
@Import(MyImportSelector.class)
public class SpringConfigurationApp {
    /**
     * main方法是springboot
     * 启动的入口
     * @param args
     */
    public static void main(String[] args) {
        //获取ioc容器
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringConfigurationApp.class, args);
        //@Import(User.class) bean名称:类的全限定名称
          Map<String, User> userBean = ctx.getBeansOfType(User.class);
//        System.out.println(userBean);
//        User user = ctx.getBean("com.itheima.pojo.User", User.class);
//        System.out.println(user);
    }
}

【2】导入ImportBeanDefinitionRegistrar 接口实现类

1、编写 ImportBeanDefinitionRegistrar接口实现类:MyImportBeanDefinitionRegistrar

package com.xxx.config;

import com.xxxx.pojo.User;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata @Import注解作用的类下的元数据信息封装
     * @param registry 注册bean信息的注册对象
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //1.创建bena的定义信息
        AbstractBeanDefinition userDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        /**
         * 参数1:bean的名称
         * 参数2:bean的定义对象
         */
        registry.registerBeanDefinition("user",userDefinition);
    }
}

2、引导类测试

package com.xxx;
import com.xxxx.config.MyConfig;
import com.xxxx.config.MyImportBeanDefinitionRegistrar;
import com.xxxx.config.MyImportSelector;
import com.xxxx.pojo.User;
import org.apache.tomcat.util.net.jsse.JSSEUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

import java.util.Map;

/**
 * 编写引动类/启动类
 * @SpringBootApplication注解定义当前类为springboot的引导类
 */
@SpringBootApplication
//方式1:导入类最终实例化成bena为ioc容器维护 bean名称:类的全限定名称
//@Import(User.class)
//方式2:导入配置类 ,配置类下的@Configuration可以省略
//@Import(MyConfig.class)
//方式3:实现批量导入
//@Import(MyImportSelector.class)
//方式4:通过ImportBeanDefinitionRegistrar实现类完成导入,也能完成bena的批量导入
@Import(MyImportBeanDefinitionRegistrar.class)
public class SpringConfigurationApp {
    public static void main(String[] args) {
        //获取ioc容器
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringConfigurationApp.class, args);
        //@Import(User.class) bean名称:类的全限定名称
//        Map userBean = ctx.getBeansOfType(User.class);
//        System.out.println(userBean);
//        User user = ctx.getBean("com.itheima.pojo.User", User.class);
//        System.out.println(user);
        //@Import(MyConfig.class)
        User user2 = ctx.getBean("user",User.class);
        System.out.println(user2);
    }
}

【3】小结

使用@Import注解的4种方式?

1. 直接导入Bean
2. 导入配置类★
3. 导入ImportSelector 实现类。一般用于加载配置文件中的类   ★★
4. 导入ImportBeanDefinitionRegistrar实现类

06-SpringBoot2高级-底层原理-@Conditional衍生条件装配

目的:理解@Conditional衍生条件装配的作用
作用:条件装配,满足Conditional指定的条件,则进行组件注入,初始化Bean对象到IOC容器
SpringBoot自动化原理_第10张图片

【1】SpringBoot常用条件注解

ConditionalOnClass:工程环境中必须存在指定的字节码文件才初始化Bean
ConditionalOnMissingBean:IOC容器中没有对应Bean才初始化Bean
ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean

【2】代码演示

package com.itheima.config;

import com.itheima.pojo.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Date;

@Configuration
//【1】User类存在,那么当前的配置bean就会被加载到ioc容器下
//@ConditionalOnClass(name = {"com.itheima.pojo.User"})
//【2】与@ConditionalOnClass功能相反
//@ConditionalOnMissingClass(value = {"com.itheima.pojo.User"})
//【3】当指定类型的bean在ioc容器中不存在,那么生效
//@ConditionalOnMissingBean(type = {"com.itheima.pojo.User"})
//【4】属性:prefix指定配置文件前缀  name:指定后缀之后的key 如果存在则满足条件,注解作用的bean加载
//配合文件必须配置myredis.enable=true才能被创建
@ConditionalOnProperty(prefix = "myredis",name = "enable",havingValue = "true")
public class MyConfig {

    @Bean
    public User myUser(){
        User user = new User().setId(1l).setBirthday(new Date()).setUserName("张三");
        return user;
    }
}

测试:

package com.xxx;
import com.xxx.config.MyConfig;
import com.xxx.pojo.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class SpringConfigurationApp {

    public static void main(String[] args) {
        //获取ioc容器
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringConfigurationApp.class, args);
        User bean = ctx.getBean(User.class);
        System.out.println(bean);
    }
}

注意:条件注解不仅可以添加到类上也可以作用在方法之上;
【3】小结
1Spring提供的条件注解有什么作用?

spring提供的@ConditionalOnxxx注解作用:满足条件当前类或者Bean才有效,按需导入;

2.Spring常用条件注解有哪些,各有什么作用?

1. @ConditionalOnClass:项目环境中存在指定的字节码文件才初始化Bean对象
2. @ConditionalOnMissingBean:IOC容器中没有指定的Bean对象才初始化注解作用的Bean  
3. @ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean

07-SpringBoot2高级-底层原理-@ConfigurationProperties配置绑定

回顾 @ConfigurationProperties配置绑定 存在的目的是:
获取配置属性或者是配置文件指定前缀的属性信息,并且初始化Bean对象到 IOC 容器。
由此我们可以想:将来的配置我们可以放在配置文件中,通过这个注解来读取并封装成对象,这样避免了配置属性需要逐个注入获取的问题;
SpringBoot自动化原理_第11张图片

08-SpringBoot2高级-自动化配置原理-@SpringBootApplication入口分析

目的:能够理解SpringBoot自动化配置流程中@SpringBootApplication是一个组合注解,及每一个注解的作用能够知道作用。
讲解:
1、SpringBoot是一个组合注解
SpringBoot自动化原理_第12张图片
2、@SpringBootConfiguration注解作用

  • @SpringBootConfiguration是对@Configuration注解的包装,proxyBeanMethods 默认配置 true, full模式(单例Bean)
  • 标识是一个配置类,所以 引导类也是配置类 ;
    3、@ComponentScan注解作用
  • 组件扫描,默认扫描的规则 引导类所在的包及其子包所有带Spring注解的类
    问题:
    1、在SpringBoot引导类中可以使用@Bean 注解可以吗?
可以,因为@SpringBootApplication注解中@SpringBootConfiguration注解对@Configuration做了层包装,本质也是一个配置注解

2、为什么启动类路径下的Controller、service类添加Spring bean注解后,不需要添加注解扫描,就可以被加载?

SpringBooot通过@ComponentScan默认加载主类路径及其子包路径;

09-SpringBoot2高级-自动化配置原理-@EnableAutoConfiguration自动配置注解

目的:理解@EnableAutoConfiguration自动化配置核心实现注解
讲解:
本章节我们将通过注解源码阐述SpringBoot加载【工程内部资源】和【第三方starter资源】的加载机制;

【1】@EnableAutoConfiguration浅析

通过查看源码,我们发现@EnableAutoConfiguration也是一个组合注解。
SpringBoot自动化原理_第13张图片

【2】@AutoConfigurationPackage注解作用

作用:利用Registrar给容器中导入一系列组件
SpringBoot自动化原理_第14张图片
点击 Registrar 进入到源码的 register 方法,添加 断点,测试
SpringBoot自动化原理_第15张图片
通过 debug 程序,我们发现@AutoConfigurationPackage注解底层会将SpringBoot启动类所在路径封装到BasePackage 类,并注册到IOC容器中,这样配合@ComponentScan注解完成加载启动类同级以及所有子目录下的资源被加载;

总之,@AutoConfigurationPackage核心作用是确定@ComponentScan注解扫描包的范围;

【3】@Import(AutoConfigurationImportSelector.class)注解作用

作用:是利用selectImports方法中的 getAutoConfigurationEntry 方法给容器中批量导入相关组件;
调用流程分析:

  1. 调用AutoConfigurationImportSelector类中的selectImports方法;
  2. selectImports方法底层调用getAutoConfigurationEntry()方法获取可自动装配的配置类信息集合;
  3. getAutoConfigurationEntry()方法调用getCandidateConfigurations(annotationMetadata, attributes)方法获取所有基于META-INF/spring.factories文件下的自动配置类的集合;【127个自动装配的信息】
  4. 底层利用Spring工厂加载器调用 loadSpringFactories()方法扫描当前系统中所有META-INF/spring.factories文件,并加载获取自动配置类信息;
    SpringBoot自动化原理_第16张图片
    默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    当然,spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
    SpringBoot自动化原理_第17张图片
    通过这个配置文件加载的自动配置:当前版本(2.3.10)是有127个默认的自动化配置
    SpringBoot自动化原理_第18张图片
    5.获取所有META-INF/spring.factories下的自动装配的配置类后,然后根据是否满足装配条件进行过滤:
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//根据本工程的配置,过滤不满足@ConditionlOnxxx
configurations = getConfigurationClassFilter().filter(configurations);

小结:
【1】SpringBoot默认自动加载的配置文件路径是哪里?

当前项目系统路径下的所有META-INF/spring.factories文件

【2】简述SpringBoot自动装配流程?

1. 通过@Import注解调用AutoConfigurationImportSelector类中的selectImports方法;
2. selectImports方法底层调用getAutoConfigurationEntry()方法获取可自动装配的配置类信息集合;
3. getAutoConfigurationEntry()方法调用getCandidateConfigurations(annotationMetadata, attributes)方法获取所有基于META-INF/spring.factories文件下的自动配置类的集合;
4. 底层利用Spring工厂加载器调用 loadSpringFactories()方法扫描当前系统中所有META-INF/spring.factories文件,并加载获取自动配置类信息;
5. 根据@Conditional条件过滤,获取最终自动装配类,最后被IOC容器加载;

10-SpringBoot2高级-自动化配置原理-条件装配过滤示例

目的:

  • 能够理解所有的自动化配置虽然会全部加载,底层有大量的@ConditionalOnXXX,有很多自动配置类并不能完全开启。
  • 如果配置生效了,则会加载默认的属性配置类,实现默认的对应场景的自动化配置
    讲解:
    1、以上通过 META-INF/spring.factories 配置文件找到所有的自动化配置类,但 是不是全部的生效的呢?很显然是不可能全部都生效的。
    2、以 RedisAutoConfiguration 为例讲解, 进入到 RedisAutoConfiguration 自动化配置类。
//定义当前注解作用类是配置类 proxyBeanMethods = false使用后lite模式,项目启动快
@Configuration(proxyBeanMethods = false)
//RedisOperations这个类存在,则满足加载条件 也就是说工程需要引入spring-data-redis-2.3.9.RELEASE.jar
@ConditionalOnClass(RedisOperations.class)
//开启配置属性类的加载,RedisProperties类被加载到IOC容器下
@EnableConfigurationProperties(RedisProperties.class)//配置属性bean通过构造器方式注入到工厂bean下
//导入满足条件的工厂配置类,sringboot推荐使用 Lettuce, 性能最好
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

	@Bean
    //如果IOC容器中不存在名称为redisTemplate的bean,那么该方法就满足条件
    //好处:为客户端充足的扩展,如果我们自定义了redisTempalte,那么springboot就不会自动装配
	@ConditionalOnMissingBean(name = "redisTemplate")
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

    //StringRedisTemplate仅操纵数据类型是string的场景
	@Bean
	@ConditionalOnMissingBean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
}

3、RedisProperties 属性对象,用于加载默认的配置,如果配置文件配置了该属性,则配置文件就生效。
SpringBoot自动化原理_第19张图片
4、LettuceConnectionConfiguration 是当前版本默认使用的Redis的连接池(性能较好)
SpringBoot自动化原理_第20张图片
SpringBoot工程中没有引入的starter,是否能被加载到工程内?为什么?

自动装配配置类中只有满足conditional条件的配置类,才会被加载到IOC容器中;

11-SpringBoot2高级-自动化配置原理-总结

SpringBoot自动化配置流程总结:

  • SpringBoot启动找到自动化配置包下 META-INF/spring.factories 内的EnableAutoConfiguration配置列表;
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值;
  • 生效的配置类就会给容器中装配很多组件;
  • 只要容器中有这些组件,相当于这些功能就有了
    总之SpringBoot加载所有META-INF/spring.factories文件下的自动装配类,然后通过条件过滤获取可被装配的配置类,然后配置类被spring加载到IOC容器下;

二、SpringBoot自定义starter (掌握)

12-SpringBoot2高级-自定义starter-步骤分析

**需求:**自定义heima-redis-spring-boot-starter场景启动依赖,并成功集成到新项目下;
**技术要求:**基于Spring环境使用Jedis和RedisTemplate构建redis场景依赖工程;
步骤:
【1】创建 wunian-redis-spring-boot-starter 工程模块,打包方式为jar,添加相关依赖;

依赖清单 说明
spring-boot-starter 为自定义redis场景依赖提供spring核心环境
spring-boot-configuration-processor 辅助配置文件时提示说明
spring-data-redis spring整合redis的中间包,提供RedisTemplate等核心API
jedis java底层连接redis服务的客户端技术
lombok 方便配置属性类setter方法生成

【2】添加配置属性类;
​ 作用:将工程中关于redis的配置信息封装到一个配置类下,方便获取配置参数;
【3】添加自动配置类;
​ 作用:加入条件装配信息,动态构建操纵redis的RedisTemplate对象;
【4】在工程resources下定义META-INF/spring.factories 文件,让SpringBoot自动识别并加载;
​ 操作:将自定义的配置类定义在该文件中,使得SpringBoot识别加载;
【5】在测试模块中引入自定义的 heima-redis-spring-boot-starter 依赖,测试;

13-SpringBoot2高级-自定义starter-实现

【1】构建starter工程

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.10.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <java.version>1.8</java.version>
    <redis.version>2.3.9.RELEASE</redis.version>
</properties>
<packaging>jar</packaging>
<dependencies>
    <!--为场景依赖提供spring的基础环境-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!--开发配置提醒-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <!--spring整合redis的整合包-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <scope>compile</scope>
    </dependency>
    <!--引入jedis客户端依赖-->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

【2】添加配置属性类

package com.xxx.pros;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 自动化默认属性配置类:读取配置文件下的数据映射配置对象
 */
@Data
@ConfigurationProperties(prefix = "myredis.config")
public class MyRedisProps {
    //定义redis host主机地址
    private String host="localhost";
    //端口号
    private Integer port=6379;
    //定义数据库 0~15
    private Integer db=0;
}

【3】添加条件配置类

package com.xxx.redis;

import com.xxx.pros.MyRedisProps;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 定义redis自动装配类
 */
@Configuration(proxyBeanMethods = false)
//必须使用jedis,且必须引入spring-data-redis.jar,完成对redis的操作
@ConditionalOnClass(name = {"redis.clients.jedis.Jedis","org.springframework.data.redis.core.RedisOperations"})
@EnableConfigurationProperties(MyRedisProps.class)
public class MyRedisAutoConfiguration {

    private MyRedisProps myRedisProps;

    /**
     * 构造器注入MyRedisProps类型的bean
     * @param myRedisProps
     */
    public MyRedisAutoConfiguration(MyRedisProps myRedisProps) {
        this.myRedisProps = myRedisProps;
    }

    @Bean
    //容器中不存在名称为redisTemplate的bean则创建
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate redisTemplate(){
        //1.创建连接工程
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
        connectionFactory.setHostName(myRedisProps.getHost());
        connectionFactory.setPort(myRedisProps.getPort());
        connectionFactory.setDatabase(myRedisProps.getDb());
        //1.创建RedisTemplate对象
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        //2.设置对象序列化支持
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

【4】定义spring.factories

​ 在resources下定义META-INF/spring.factories 文件,并配置自动装配信息,让SpringBoot自动加载:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.redis.MyRedisAutoConfiguration

【5】安装自定starter

​ maven安装到本地仓库,方便其它工程引用

14-SpringBoot2高级-自定义starter-集成到新项目

目的:验证自定义starter是否可以使用
实现:
【1】新建 boot_xxxedis 项目中引入依赖

<!--1、引入SpringBoot父工程-->
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.3.10.RELEASE</version>
</parent>


<dependencies>
  <!--web 启动器  SpringBoot对web的支持-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
  </dependency>

  <dependency>
    <groupId>com.itheima.sh</groupId>
    <artifactId>heima-redis-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
  </dependency>

</dependencies>

【2】定义yml配置

myredis:
  config:
    host: 127.0.0.1
    port: 6379
    db: 1

【2】测试

package com.xxx;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
public class TestMyStarter {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void test1(){
        redisTemplate.opsForValue().set("name","lisi");
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println(name);
    }
}

三、SpringBoot健康监控

15-SpringBoot2高级-监控-健康监控服务

目的:能够理解健康监控actuator的作用
背景:
在一些大型的业务应用中,工程会根据业务模块做微服务拆分,后期每一个微服务在云上部署以后,都需要对其进行监控、追踪、审计、控制等操纵,这会给维护人员带来很大的运维压力。
SpringBoot对此就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。
实现:
1、被监控工程中引入Actuator依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、启动项目,访问 http://localhost:80/actuator/**
SpringBoot自动化原理_第21张图片
3、暴露所有监控信息为HTTP

management:
  endpoints:
    enabled-by-default: true #暴露所有端点信息
    web:
      exposure:
        include: '*'  #以web方式暴露

  endpoint:
    health:
      enabled: true   # 开启健康检查详细信息
      show-details: always

访问 http://localhost:80/actuator 会发现内容多了,里面的地址分别都可以访问,记录的是对应的健康监测的信息。

16-SpringBoot2高级-监控-Admin可视化

目的:能够搭建 可视化监控平台
讲解:

【1】Admin可视化介绍

SpringBoot Admin 有两个角色,客户端(Client)和服务端(Server)。
SpringBoot自动化原理_第22张图片
Spring Boot Admin为注册的应用程序提供以下功能:

  • 显示健康状况
  • 显示详细信息,例如
    • JVM和内存指标
    • micrometer.io指标
    • 数据源指标
    • 缓存指标
  • 显示内部信息
  • 关注并下载日志文件
  • 查看JVM系统和环境属性
  • 查看Spring Boot配置属性
  • 支持Spring Cloud的可发布/ env-和// refresh-endpoint
  • 轻松的日志级别管理
  • 与JMX-beans交互
  • 查看线程转储
  • 查看http-traces
  • 查看审核事件
  • 查看http端点
  • 查看预定的任务
  • 查看和删除活动会话(使用spring-session)
  • 查看Flyway / Liquibase数据库迁移
  • 下载heapdump
  • 状态更改通知(通过电子邮件,Slack,Hipchat等)
  • 状态更改的事件日志(非持久性)

快速入门:https://codecentric.github.io/spring-boot-admin/2.3.1/#getting-started

实现:

以下为创建服务端和客户端工程步骤:

【1】搭建Server端

1、创建 admin_server 模块,引入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.10.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-server</artifactId>
        <version>2.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

2、开启注解支持

package com.xxx.sh;

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableAdminServer
public class AdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminApplication.class, args);
    }
}

注意端口修改为:9999

【3】搭建Client端

1、在任意服务里面引入依赖

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>2.3.1</version>
</dependency>

2、配置文件

# 执行admin.server地址
spring:   
  boot:
    admin:
      client:
        url: http://localhost:9999  # admin 服务地址
        instance:
          prefer-ip: true   # 显示IP
  application:
    name: boot_data  # 项目名称
    
management:
  endpoints:
    enabled-by-default: true #暴露所有端点信息
    web:
      exposure:
        include: '*'  #以web方式暴露

  endpoint:
    health:
      enabled: true   # 开启健康检查详细信息
      show-details: always

【4】启动服务端和客户端测试

启动服务,访问admin Server http://localhost:9999/
SpringBoot自动化原理_第23张图片

四、SpringBoot项目部署

SpringBoot 项目开发完毕后,支持两种方式部署到服务器

  • jar包部署
1. 将要部署的项目打成jar包
		1). 注意: 导入springboot打包插件
2. 丢到linux系统上
  	 	1). 注意mx在连接linux的时候,如果连不上,查看services.msc中vm开头的服务有没都启动
3. 在linux上启动项目 
		1). java -jar xx.jar
			前端启动,界面不能关闭
		2). linux防火墙默认只开放22端口
			I. 安装软件的时候,开放了8080,3306,6379
			II. 要么开放9999,要么关闭防火墙
				systemctl stop firewalld
		3). 后端启动
			(启动时不在终端打印日志,在文件中打印,默认文件名 nohup.out)
			nohup java -jar xx.jar &
4. 在windows上用浏览器访问
	http://192.168.109.122:9999/
	
5. linux命令
	1). pwd : print working directory 打印当前工作路径
	2). ps -ef | grep java  : 查看当前系统中包含有java关键字的进程
	3). cat 文件 : 查看

war包部署

1. 将要部署的项目打成war包
	1). spring-boot-starter-web环境要排除tomcat.jar
		(运行起来用linux系统中的tomcat软件)
	2). 引入servlet的jar包,不然编译会报错
	3). 插件中声明打war包不需要web.xml,不然会报错
	4). 打包方式为war
	5). 修改启动类(继承SpringBootServletInitializer重写configure方法)
2. 丢到linux系统的tomcat/webapps目录下
	
3. 启动tomcat,就会加载我们的项目
	1). bin目录 
		./startup.sh
	2). 访问
    	http://192.168.109.122:8080/war包名字/controller虚拟路径

17-SpringBoot2高级-服务部署-jar包部署

目的:能够使用Jar包方式部署SpringBoot项目
实现:
1、引入打包插件依赖

<build>
  <!--声明jar包名称-->
  <finalName>boot_data</finalName>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

2、打包,复制出Jar使用,java -jar 运行程序
SpringBoot自动化原理_第24张图片
复制到任意Linux目录:
SpringBoot自动化原理_第25张图片
正常访问;
注意事项:
​ 1.项目运行必须依赖 JDK 环境;
2. 注意linux的防火墙9999端口需要开放,或者简单点也可以关闭防火墙

​ systemctl stop firewalld
​ 3. 启动springboot项目时,默认占用一个终端,如果终端窗口关闭,服务进程结束,如何解决?

nohup java -jar boot_data.jar &
nohub java -jar boot-data.jar > 1.log
# 加了nohup后,即使关掉命令窗口,后台程序boot-data.jar也会一直执行

18-SpringBoot2高级-服务部署-war包部署

目的:能够使用war包方式部署SpringBoot项目
步骤:
1、更改打包方式为 war
SpringBoot自动化原理_第26张图片
2、配置打包插件


<dependency>
  <groupId>org.springframework.bootgroupId>
  <artifactId>spring-boot-starter-webartifactId>
  <exclusions>
    <exclusion>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-tomcatartifactId>
    exclusion>
  exclusions>
dependency>

<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>servlet-apiartifactId>
    <version>2.5version>
    <scope>providedscope>
dependency>

<build>
  
  <finalName>boot_datafinalName>
  <plugins>
    <plugin>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-maven-pluginartifactId>
    plugin>
      
      <plugin>
          <groupId>org.apache.maven.pluginsgroupId>
          <artifactId>maven-war-pluginartifactId>
          <configuration>
              <failOnMissingWebXml>falsefailOnMissingWebXml>
          configuration>
      plugin>
  plugins>
build>

3、修改引导类 继承 SpringBootServletInitializer

package com.xxx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;

/*
*   启动类要继承SpringBootServletInitializer
*   并重写configure方法
* */
@SpringBootApplication
public class HelloApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {

        SpringApplication.run(HelloApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(HelloApplication.class);
    }
}

4、配置tomcat,war复制到 webapps 目录下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjuYzX69-1644246254860)(assets/image-20210504160435002.png)]

5、启动tomcat

./startup.sh

6、浏览器访问:http://192.168.200.150:8080/boot_data

实际开发中用哪一种?

​ 如果你的工程用户访问量少(不会面临3高问题:高可用 高并发 高性能),那么推荐使用jar包部署方式,因为部署简单;

​ 如果工程面临3高问题,那么推荐使用war包部署,因为使用外部的tomcat,可以做到最大程度的参数自定义(方便tomcat的优化==》运维人员介入)

总结

【1】如何实现被@Configuration修饰的类中的方法产生的bean是单例还是多例?

proxyBeanMethods=true: Full模式,单例模式,底层被 cglib代理,先从IOC容器中检查当前的bean是否存在,如何存在,则直接返回bean对象,否则创建;
proxyBeanMethods=false:LITE模式,多例模式

【2】Import注解导入bean的4种方式

1.直接导入某个类,作为换一个bean被ioc容器管理
2.导入配置类(配置类可以不写@Configuration注解)
3.导入实现ImportSelector接口的实现类(批量导入)
4.导入实现ImportBeanDefinitionRegistrar接口的实现类(批量注册bean信息,完成导入)

【3】常用的条件装配注解有哪些?

@ConditionalOnBean: 容器中存在bean则创建
@ConditionalOnMissingBean: 容器中不存在bean则创建
@ConditionalOnClass:判断某个类必须存在,才创建
@ConditionalOnMissingClass:判断某个类不必须存在,才创建
@ConditionalOnProperty(prefix="前缀",name="名称",havingvalue="必须是指定的值")配置文件中必须存在指定的key和value值则创建

【4】自定装配的原理:

1)SpringBoot基于SPI思想约定工程以启动加载工程系统环境下META-INF/spring.factories文件获取可自动装配的配置类信息;
2)SringBoot引入了条件装配的概念,这些自动装配类只加载满足条件的配置类;
3)通过自动装配的配置类,将相关的资源加入IOC容器,容器中有了这些bean资源,就有了指定的功能;

【5】自定义starter流程

1.定义一个maven工程,打包方式jar,然后引入spring-boot-starter.jar提供spring核心环境依赖;
2.定义属性配置类,一般使用@ConfigurationProperties注解映射yml中的配置信息;
3.定义自动装配的配置类,主要注解:
	类上:
		@Configuration(proxyBeanMethods=false):加载快
		@ConditionalOnxxx:条件装配条件
		@EnableConfigurationProperties:将属性配置类加载到IOC容器下
	方法上:
    	@Bean
    	@ConditionalOnxxx:满足条件,则方法被执行,构建对应的bean对象
4.在resources包下定义META-INF/spring.factories文件
		eg:
		org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
		com.myredis.config.MyRedisAutoConfiguration
5.打包		

你可能感兴趣的:(SpringBoot高级原理,spring,boot,自动化,java)