1-4.约定优于配置设计范式及Spring Boot源码剖析

约定优于配置设计范式及Spring Boot源码剖析

一、Spring boot应用回顾

1. 约定优于配置

约定优于配置(Convention over Configuration),又称按约定编程,是一种软件设计规范。本质上是对系统、类库或框架中一些东西假定一个大众化合理的默认值(缺省值)。好处:大大减少了配置项

2. spring boot 于spring 关系

spring boot基于spring 4.0设计,支持省去applicationContext.xml;不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决

3.SpringBoot主要特性

  1. SpringBoot Starter:他将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven或Gradle构建中;

  2. 使编码变得简单,SpringBoot采用 JavaConfig的方式对Spring进行配置,并且提供了大量的注解,极大的提高了工作效率。

  3. 自动配置:SpringBoot的自动配置特性利用了Spring对条件化配置的支持,合理地推测应用所需的bean并自动化配置他们;

  4. 使部署变得简单,SpringBoot内置了三种Servlet容器,Tomcat,Jetty,undertow.我们只需要一个Java的运行环境就可以跑SpringBoot的项目了,SpringBoot的项目可以打成一个jar包。

4.全局配置文件

  1. 文件名:

    application.properties或者application.yml(可以使用其他,需要配置)

  2. 文件位置

image-20210812132643579

  1. 注意事项:

    • 如果同一个目录下,有application.yml也有application.properties,2.4之前版本默认先读取

    application.properties。,2.4及之后默认先读取yml。

    • 如果同一个配置属性,在多个配置文件都配置了,默认使用第1个读取到的,后面读取的不覆盖前面读取

    到的。

    • 创建SpringBoot项目时,一般的配置文件放置在“项目的resources目录下”
  2. 使用@ConfigurationProperties批量注入配置文件中属性

    • 实体类上添加@Component;@ConfigurationProperties注解

      //Person
      @Component //生成当前类的实例对象存到IOC容器中
      @ConfigurationProperties(prefix = "person")   //实现批量注入(set方法)
      public class Person {
          private int id;            //id
          private String name;      //名称
          private List hobby;       //爱好
          private String[] family; //家庭成员
          private Map map;
          private Pet pet;          //宠物
      }
      //pet
      public class Pet {
          // 类型
          private String type;
          // 名称
          private String name;
      }
      
    • 配置文件application.properties中配置要注入的信息

      image-20210812140310015

    • 或者在文件application.yml中配置

      image-20210812142644191

  3. spring boot测试用例

    @RunWith(SpringRunner.class)
    @SpringBootTest
    class MySpringbootApplicationTests {
    
        @Autowired
        private Person person;
        @Test
        void contextLoads() {
            System.out.println(person);
        }
    }
    

5.属性注入

  1. @Value单个属性注入
@Configuration//配置类,自动注入到IOC容器
public class JdbcConfiguration {
    @Value("${jdbc.url}")
    String url;

    @Value("${jdbc.driverClassName}")
    String driverClassName;

    @Value("${jdbc.username}")
    String username;

    @Value("${jdbc.password}")
    String password;
}
  1. @ConfigurationProperties放到类上批量注入
@Component
@ConfigurationProperties(prefix = "jdbc")
public class JdbcConfiguration {
    String url;
    String driverClassName;
    String username;
    String password;
}
  1. @ConfigurationProperties放到方法上注入(一般用于第三方对象赋值)
@Configuration
public class MyService {
    @ConfigurationProperties(prefix = "another")
    @Bean
    public AnotherComponent anotherComponent(){
        return new AnotherComponent();
    }
}
  1. 在配置文件中,属性是松散绑定的

first-name,firstName,first_name ,FIRSTNAME 都会被识别为一个字符串

6. 日志框架

  • 抽象层:SLF4J

  • 实现层:logback

  1. 统一日志框架使用步骤

    • 排除系统中的其他日志框架。

    • 使用中间包替换要替换的日志框架。

    • 导入我们选择的 SLF4J 实现。

  2. 使用

    Logger logger = LoggerFactory.getLogger(this.getClass());
    logger.info("info日志....");
    
  3. 配置

    #日志配置
    # 指定具体包的日志级别
    logging.level.com.lagou=trace
    
    # 指定控制台日志输出格式
    logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
    
    # 指定将日志信息输出到指定文件
    logging.file.name=my.log
    #logging.file.path=/var/log
    
    # 指定文件日志输出格式
    logging.pattern.file=%d{yyyy-MM-dd} ======= [%thread]====== %-5level %logger{50} - %msg%n
    
  • 源码:git clone -b master1 https://gitee.com/idse666666/my-springboot.git

二、源码解析

1. 依赖管理

1-1.为什么导入dependency时不需要指定版本?

spring-boot-starter-parent 通过继承 spring-boot-dependencies 从而实现了SpringBoot的版本依

赖管理,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了,这也

就是在 Spring Boot 项目中部分依赖不需要写版本号的原因

1-2.spring-boot-starter-parent父依赖启动器的主要作用是进行版本统一管理,那么项目运行依赖的JAR包是从何而来的?

spring-boot-starter-web依赖启动器的主要作用是打包了Web开发场景所需的底层所有依赖(基于依赖传递,当前项目也存在对应的依赖jar包)

2.自动配置

2-1.Spring Boot到底是如何进行自动配置的,都把哪些组件进行了自动配置?
  • @SpringBootApplication:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan组合而成

  • @SpringBootConfiguration:SpringBoot 的配置类,标注在某个类上,表示这是一个 SpringBoot的配置类。

  • @EnableAutoConfiguration:Spring 中有很多以 Enable 开头的注解,其作用就是借助 @Import 来收集并注册特定场景相关的

    Bean ,并加载到 IOC 容器。

    • @Import:遍历各个组件META-INF目录中所有jar包下的spring.factories文件。收集需要配置的类,然后过滤或排除后装载到ioc容器中
  • @ComponentScan:主要是从定义的扫描路径中,找出标识了需要装配的类自动装配到spring 的bean容器中。

三、自定义starter

  • SpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。
  • 将独立于业务代码之外的功配置模块封装成一个个starter,复用的时候只需要将其在pom中引用依赖即可,再由SpringBoot为我们完成自动装配
  • 动态数据源,登录模块,基于AOP技术实现日志切面

1.SimpleBean

@EnableConfigurationProperties
@ConfigurationProperties(prefix = "simplebean")
public class SimpleBean {

   private int id;
   private String name;

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   @Override
   public String toString() {
      return "SimpleBean{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
   }
}

2.MyAutoConfiguration

@Configuration
public class MyAutoConfiguration {
   static {

      System.out.println("MyAutoConfiguration init.... ");
   }

   @Bean
   public SimpleBean simpleBean(){
      return new SimpleBean();
   }

}

3.在META-INF下建立spring.factories文件以便扫描到我们要注册的starter

image-20210816150122887

4.优化

  • 使用@ConditionalOnBean注解,只有ioc容器中注入了这个类才生效

image-20210816150339765

  • 自定义出EnableRegisterServer注解,在其上方使用@Import注解使ioc容器中创建configmarker类实例

image-20210816150602642

5.测试

  • 我们可以在另一项目中使用pom.xml引入

    <dependency>
        <groupId>com.lagou</groupId>
        <artifactId>zdy-spring-boot-starter</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
  • 配置yml

    simplebean:
      id: 1
      name: zdy
    
  • 测试注入

image-20210816150841425

image-20210816151144062

6.源码

git clone -b master2 https://gitee.com/idse666666/my-springboot.git

四、动态数据源配置

Spring内置了一个AbstractRoutingDataSource,它可以把多个数据源配置成一个Map,然后,根据不同的key返回不同的数据源。因为AbstractRoutingDataSource也是一个DataSource接口,因此,应用程序可以先设置好key, 访问数据库的代码就可以AbstractRoutingDataSource拿到对应的一个真实的数据源,从而访问指定的数据库

1.实现过程图解:

image-20210821154316971

2.配置两个数据源并注入到RoutingDataSource中:

image-20210821153323669

3.RoutingDataSource中创建子类并重写determineCurrentLookupKey方法

image-20210821153653187

4. 提供set和get方法获取存放在ThreadLocal方式获取当前线程key

image-20210821153914194

5.切面技术调用RoutingDataSourceUtil中的ThreadLocal的setkey

image-20210821154807822

6.源码

git clone -b master3 https://gitee.com/idse666666/my-springboot.git

五、缓存

1.重要概念和注解

Spring Cache 只负责维护抽象层,具体的实现由自己的技术选型来决定。将缓存处理和缓存技术
解除耦合。
每次调用需要缓存功能的方法时,Spring会检查指定参数的指定的目标方法是否已经被调用过,如
果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次
调用直接从缓存中获取。
使用Spring缓存抽象时我们需要关注以下两点:
① 确定那些方法需要被缓存 
② 缓存策略

image-20210821141838226

2.@Cacheable

将方法运行的结果进行缓存,以后再获取相同的数据时,直接从缓存中获取,不再调用方法

  • @Cacheable注解的属性

    image-20210822102559221

  • 可用的SpEL表达式见下表:

image-20210822102638368

  • 例:@Cacheable(cacheNames = {“emp”},key = “#id”, condition = “#id > 0”, unless = “#result == null”)缓存的名字为emp,key为id参数,当id>0,且返回结果不为NULL的数据

3.源码

git clone -b master4 https://gitee.com/idse666666/my-springboot.git
缓存,以后再获取相同的数据时,直接从缓存中获取,不再调用方法

  • @Cacheable注解的属性

    [外链图片转存中…(img-ztzFDcCh-1629621444536)]

  • 可用的SpEL表达式见下表:

[外链图片转存中…(img-pAFTKA9y-1629621444537)]

  • 例:@Cacheable(cacheNames = {“emp”},key = “#id”, condition = “#id > 0”, unless = “#result == null”)缓存的名字为emp,key为id参数,当id>0,且返回结果不为NULL的数据

3.源码

git clone -b master4 https://gitee.com/idse666666/my-springboot.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值