SpringBoot自动化原理

SpringBoot自动化原理

在了解SpringBoot之前我们先要了解SpringBoot的相关注解和流程
SpringBoot相关注解如图:
在这里插入图片描述
SpringBoot的启动流程如图:
在这里插入图片描述
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自动装配预览

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

SPI使用场景

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

在这里插入图片描述
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工程相关的依赖资源:
在这里插入图片描述
工程自动加载依赖资源
通过断点测试SpringIOC容器,我们发现SpringBoot几乎把MVC相关的所有资源自动加载到容器中了:
在这里插入图片描述
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文件下配置:
在这里插入图片描述
以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】
在这里插入图片描述
功能:
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对象
在这里插入图片描述
在执行结果则为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<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);
        //@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容器
在这里插入图片描述

【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 容器。
由此我们可以想:将来的配置我们可以放在配置文件中,通过这个注解来读取并封装成对象,这样避免了配置属性需要逐个注入获取的问题;
在这里插入图片描述

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

目的:能够理解SpringBoot自动化配置流程中@SpringBootApplication是一个组合注解,及每一个注解的作用能够知道作用。
讲解:
1、SpringBoot是一个组合注解
在这里插入图片描述
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也是一个组合注解。
在这里插入图片描述

【2】@AutoConfigurationPackage注解作用

作用:利用Registrar给容器中导入一系列组件
在这里插入图片描述
点击 Registrar 进入到源码的 register 方法,添加 断点,测试
在这里插入图片描述
通过 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文件,并加载获取自动配置类信息;
    在这里插入图片描述
    默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    当然,spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
    在这里插入图片描述
    通过这个配置文件加载的自动配置:当前版本(2.3.10)是有127个默认的自动化配置
    在这里插入图片描述
    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 属性对象,用于加载默认的配置,如果配置文件配置了该属性,则配置文件就生效。
在这里插入图片描述
4、LettuceConnectionConfiguration 是当前版本默认使用的Redis的连接池(性能较好)
在这里插入图片描述
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-redisspring整合redis的中间包,提供RedisTemplate等核心API
jedisjava底层连接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/**
在这里插入图片描述
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)。
在这里插入图片描述
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项目部署

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 运行程序
在这里插入图片描述
复制到任意Linux目录:
在这里插入图片描述
正常访问;
注意事项:
​ 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
在这里插入图片描述
2、配置打包插件

<!-- 注意:需要将web依赖中的tomcat移除 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<!--如果保存:Error:(13,8) java: 无法访问javax.servlet.ServletException-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>provided</scope>
</dependency>

<build>
  <!--jar 包名称-->
  <finalName>boot_data</finalName>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
      <!-- 声明打包时,不需要web.xml -->
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-war-plugin</artifactId>
          <configuration>
              <failOnMissingWebXml>false</failOnMissingWebXml>
          </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.打包		
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值