Springboot原理

SpringBoot原理

1、配置优先级

在SpringBoot项目当中支持的三类配置文件:

  • applicaiton.properties
  • application.yml
  • application.yml

在SpringBoot项目当中,如果需要配置一个属性,可以通过这三种方式当中的任意一种来配置,那如果项目当中通知存在这三种配置文件,且都配置了同一种属性,如:Tomcat端口号,那哪一份配置文件会生效呢?

  • application.properties

    server.port=8080

  • application.yml

    server:

    ​ port: 8081

  • application.yaml

    server:

    ​ port: 8082

测试:

  • properties、yaml、yml三种配置文件同时存在时:

    img

    properteis、yml、yaml三种配置文件中,优先级最高的是properteis

  • yaml、yml两种配置文件同时存在

    img

    配置文件优先级排名(从高到低):

    1. properties配置文件
    2. yml配置文件
    3. yaml配置文件

注意:虽然SpringBoot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置(yml是主流)

在SpringBoot项目当中除了以上3中配置文件外,SpringBoot为了增强程序的扩展性,除了支持配置文件的配置方式以外,还支持另外两种常见的配置方式:

  1. Java系统属性配置(格式:-Dkey=value)

    -Dserver.port=9000
    
  2. 命令行参数(格式:–key=value)

    --server.port=10010
    

优先级(从低到高):

  • application.yaml
  • application.yml
  • application.properties
  • java系统属性
  • 命令行参数

Bean管理

获取Bean

默认情况下,SpringBoot项目在启动的时候会自动创建IOC容器(也称为Spring容器),并且在启动的过程中会自动的将bean对象都创建好,存放在IOC容器当中,应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以。

而在Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象。

  1. 根据name获取bean

    Object getBean(String name)
    
  2. 根据类型获取bean

    <T> T getBean(Class<T> requiredType)
    
  3. 根据name获取bean(带类型转换)

    <T> T getBean(String name, Class<T> requiredType)
    

控制器:DeptController

@Slf4j
@RestController
@RequestMapping("/depts")
public class DeptController {
    @Autowired
    private DeptService deptService;

    public DeptController(){
        System.out.println("DeptController constructor.....");
    }

    @GetMapping
    public Result list() {
        log.info("查询所有部门数据");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        // 日志记录
        log.info("根据id删除部门");
        deptService.delete(id);
        return Result.success();
    }

    @PostMapping
    public Result add(@RequestBody Dept dept) {
        // 日志信息
        log.info("新增部门:{}", dept);
        // 调用service层添加功能
        deptService.insert(dept);
        return Result.success();
    }
}

业务实现类:DeptServiceImpl

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;
    // 查询所有的部门数据
    @Override
    @MyLog // 自定义注解(表示:当前方法属于目标方法)
    public List<Dept> list() {
        List<Dept> deptList = deptMapper.list();
        return deptList;
    }

    // 根据id删除部门信息
    @Override
    @MyLog // 自定义注解(表示:当前方法属于目标方法)
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {
        // 根据部门id删除部门信息
        deptMapper.deleteById(id);
    }

    @Override
    @MyLog // 自定义注解(表示:当前方法属于目标方法)
    public void insert(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }
}

Mapper接口:

@Mapper
public interface DeptMapper {

    // 查询所有部门数据
    List<Dept> list();
    // 根据id删除部门数据
    void deleteById(Integer id);
    // 新增部门信息
    void insert(Dept dept);
}

测试类:

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private ApplicationContext applicationContext;

    // 获取bean对象
    @Test
    void testGetBean() {
        // 根据bean的名称获取
        DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
        System.out.println(bean1);

        // 根据bean的类型获取
        DeptController bean2 = applicationContext.getBean(DeptController.class);
        System.out.println(bean2);

        // 根据bean的名称及类型获取
        DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
        System.out.println(bean3);
    }

}

程序运行后控制台日志:

img

输出的bean对象地址值是一样的,默认情况下,IOC中的bean对象是单例

Bean作用域

在Spring中支持五中作用域,后三种在web环境才生效:

作用域说明
singleton容器内同名称的bean只有一个实例(单例)(默认)
prototype每次使用该bean时会创建新的实例(非单例)
request每次请求范围内会创建新的实例(web环境中,了解)
session每个会话范围内会创建新的实例(web环境中,了解)
application每个应用范围内会创建新的实例(web环境中,了解)

设置一个bean的作用域:

  • 可以借助Spring中的@Scope注解来进行配置作用域

img

注意事项

  1. singleton
    • IOC容器中的bean默认使用的作用域:singleton(单例)
    • 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)
  2. prototype
    • prototype的bean,在每一次使用该bean的时候都会创建一个新的实例
    • 实际开发当中,绝大部分的bean是单例的,也就是说绝大部分bean不需要配置scope属性

第三方Bean

在pom.xml文件中,引入dom4j:

<!--Dom4j-->
<dependency>
	<groupId>org.dom4j</groupId>
	<artifactId>dom4j</artifactId>
	<version>2.1.3</version>
</dependency>

如果需要第三方bean时,通常会单独定义一个配置类

@Configuration // 配置类(在配置类中对第三方bean进行集中的配置管理)
public class CommonConfig {

    // 声明第三方bean
    @Bean // 将当前方法的返回值对象交给IOC容器管理,成为IOC容器bean
    // 通过@Bean注解的name/value属性指定bean名称,如果未指定,默认是方法名
    public SAXReader reader(DeptService deptService) {
        System.out.println(deptService);
        return new SAXReader();
    }
}

测试类:

@SpringBootTest
class DemoApplicationTests {

    @Autowired
   private SAXReader saxReader;

    @Test
    public void testThirdBean() throws DocumentException {
        Document document = saxReader.read(this.getClass().getClassLoader().getResource("test.xml"));
        Element rootElement = document.getRootElement();
        String name = rootElement.element("name").getText();
        String age = rootElement.element("age").getText();

        System.out.println(name + ":" + age);
    }

}

执行测试方法后,控制台输出日志:

Tom : 18

在方法上加上一个@Bean注解,Spring容器在启动的时候,会自动的调用这个方法,并将方法的返回值声明为Spring容器当中的Bean对象。

注意

  • 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名
  • 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配

关于Bean需要保持的一个原则:

  • 如果在项目当中自己定义的类,想将这些类交给IOC容器管理,直接使用@Component以及它的衍生类注解来声明即可

  • 如果这个类不是自己定义的,而是引入第三方依赖当中提供的类,而且还想将这个类交给IOC容器管理,此时就需要在配置类中定义一个方法,在方法上加一个@Bean注解,通过这种方式来声明第三方的bean对象

SpringBoot原理

介绍

Spring是目前世界上最流行的Java框架,它可以帮助我们更加快速、更加容易的来构建Java项目。而在Spring家族当中提供了很多优秀的框架,而所有框架都是基于一个基础框架二点SpringFramework(也就是Spring框架)。但是直接基于Spring框架进行项目的开发,会比较繁琐。

主要体现在两个地方:

  • 在pom.xml中依赖配置比较繁琐,在项目开发时,需要自己去找到对应的依赖,还需要找到依赖它配套的依赖以及对应的版本,否则就会出现版本冲突问题。
  • 在使用Spring框架进行项目开发时,需要在Spring的配置文件中做大量的配置,这就造成了Spring框架入门难度较大,学习成本较高

基于Spring存在的问题,官方在Spring框架4.0版本之后,又推出了一个全新的框架:SpringBoot

通过SpringBoot来简化Spring框架的开发。直接基于SpringBoot来构架Java项目,会让项目开发更加简单,更加快捷

SpringBoot框架之所以用起来更加简单、快捷,是因为SpringBoot框架底层提供了两个重要的功能:一个是起步依赖,一个是自动配置

通过SpringBoot所提供的起步依赖,就可以大大的简化pom文件当中依赖的配置,从而解决了Spring框架当中依赖配置繁琐的问题

通过自动配置的功能就可以大大的简化框架在使用时bean的声明以及bean的配置。只需要引入程序开发时所需要的起步依赖。

起步依赖

假如没有使用SpringBoot,用的是Spring框架进行web程序的开发,此时就需要引入web程序开发所需要的一些依赖

img

spring-webmvc依赖:这是spring框架进行web程序开发所需要的依赖

servlet-api依赖:Servlet基础依赖

jackson-databind依赖:JSON处理工具包

如果要使用AOP,还需要引入aop依赖:aspect依赖

项目中所引入的这些依赖,还需要保证版本匹配,否则就可能会出现版本冲突问题

但是如果使用SpringBoot的话,就只需要引入web开发的起步依赖:springboot-starter-web

img

结论:起步依赖的原理就是Maven的依赖传递

  • 在SpringBoot提供的这些起步依赖当中,以提供了当前程序开发所需要的所有常见依赖
  • 如:springboot-starter-web,这是web开发的常见依赖,在web开发的起步依赖当中,就集成了web开发中常见的依赖:json、web、webmvc、tomcat等。只需要引入这一个依赖,其他的依赖都会自动的通过maven的依赖传递进来

自动配置

SpringBoot的自动配置就是当Spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要手动声明,从而简化了开发,省去了繁琐的配置操作

@Configuration底层就是@Component,所以配置类最终也是SpringIOC容器当中的一个bean对象

在IOC容器中除了自己定义的bean以外,还有很多配置类,这些配置类都是SpringBoot在启动的时候加载进来的配置类,这些配置类加载进来之后,它会生成很多的bean对象。当要使用这些配置类生成的bean对象时,可以使用@Autowired就自动注入了。

源码小结

自动配置原理源码入口就是@SpringBootApplication注解,在这个注解中封装了3个注解,分别是:

  • @SpringBootConfiguration
    • 声明当前类是一个配置类
  • @ComponentScan
    • 进行组件扫描(SpringBoot中默认扫描的就是启动类所在的当前包及其子包)
  • @EnableAutoConfiguration
    • 封装了@Import注解(Import注解中指定了一个ImportSelector接口的实现类)
    • 在实现类重写的selectImports()方法,读取当前项目下所有依赖jar包中METAINF/spring.factories、METAINF/spring/org.springframework.boot.autoconfigure.AutoConfigurat ion.imports两个文件里面定义的配置类(配置类中定义了@Bean注解标识的方法)
@Conditional

条件装配注解:@Conditional

  • 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象到Spring的IOC容器中
  • 位置:方法、类
  • @Conditional本身是一个父注解,派生出大量的子注解:
    • @ConditionalOnClass:判断环境中有对应字节码文件,才注册到IOC容器
    • @ConditionalOnMissingBean:判断环境中没有对应的bean(类型或名称),才注册bean到IOC容器中
    • @ConditionalOnProperty:判断配置文件中有对应属性和值,才注册bean到IOC容器
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值