SpringBoot(高级原理分析)(上)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: SpringBoot(高级原理分析)(上)

①. 自动配置

①. condition

1>. condition


①. 什么是Condition?

1.什么是condition?


  • ①. condition是在Spring4.0增加的条件判断功能,通过这个功能可以实现选择性的创建Bean操作


  • ②. 自定义条件


自定义条件:

(1).定义条件类:自定义实现Condition接口,重写matches方法,在matches方法中进行逻辑判断,返回boolean值。matches方法两个参数:

context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等

metadata:元数据对象,用于获取注解属性

(2).SpringBoot提供的常见条件注解:

ConditionalOnProperty:判断配置文件是否有对应属性和值才初始化Bean

ConditionalOnClass:判断坏境中是否有对应字节码文件才初始化Bean

ConditionalOnMissingBean:判断坏境中没有对应Bean才初始化Bean

上面这些可以在如下找到:

image.png


②. 案例1

2. 案例1


  • ①. 需求:在Spring的IOC容器中有一个User的Bean,现要求:

    导入Jedis坐标后,加载该Bean,没导入,则不加载


  • ②. 具体代码实现:

image.png

@Configuration
public class UserConfig {
    @Bean
    @Conditional(UserCondition.class)
    public User getUser(){
        return new User();
    }
}
package com.itheima.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class UserCondition implements Condition {
    /*
    * matches()方法
    * 如果返回值是true,那么会创建相对应的对象
    * 如果方法返回值是false,那么则不会创建相对应的对象
    * 1.conditionContext:上下文对象。用于获取坏境,IOC容器,ClassLoader对象
    * 2.annotatedTypeMetadata:注解的元对象。可以用于获取注解定义的属性值
    * */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        /*
         * 需求: 1.导入Jedis坐标后创建bean
         * 思路: 判断redis.clients.jedis.Jedis;文件是否存在
         * */
        /*
        Environment environment = conditionContext.getEnvironment();
        environment.getProperty();
        * */
        boolean flag=true;
        try {
            Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            flag=false;
        }
        return flag;
    }
}


③. 案例2

3. 案例2


  • ①. 需求:在Spring的IOC容器中有一个User的Bean,现要求:

    将类的判断定义为动态的判断哪个字节码文件可以动态指定(ConditionOnClass)


  • ②. 代码演示:


image.png

@Configuration
public class UserConfig {
    @Bean
    //@Conditional(UserCondition.class)
    @ConditionOnClass("redis.clients.jedis.Jedis")
    public User getUser(){
        return new User();
    }
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(UserCondition.class)
public @interface ConditionOnClass {
    String[]value();
}
public class UserCondition implements Condition {
    /*
    * matches()方法
    * 如果返回值是true,那么会创建相对应的对象
    * 如果方法返回值是false,那么则不会创建相对应的对象
    * 1.conditionContext:上下文对象。用于获取坏境,IOC容器,ClassLoader对象
    * 2.annotatedTypeMetadata:注解的元对象。可以用于获取注解定义的属性值
    * */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        /*
         * 需求: 1.导入Jedis坐标后创建bean
         * 思路: 判断redis.clients.jedis.Jedis;文件是否存在
         * */
        /*
        Environment environment = conditionContext.getEnvironment();
        environment.getProperty();
        * */
       /* boolean flag=true;
        try {
            Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            flag=false;
        }
        return flag;*/
        //2.需求:导入通过注解属性值value指定坐标后创建Bean
        //获取注解属性值 value
        Map<String, Object> map = annotatedTypeMetadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        System.out.println(map);
        String[]value = (String[]) map.get("value");
        boolean flag=true;
        try {
            for (String className : value) {
                Class<?> cls = Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            flag=false;
        }
        return flag;
    }
}


②. 监听机制


2>.监听机制(了解)


  • SpringBoot的web坏境中默认使用tomcat作为内置服务器,其实SpringBoot提供了4中内置服务器供我们选择,我们可以很方便的进行切换。


  • spring-boot-autoConfigure–》web–》embedded

image.png


  • ③. 代码演示如下(如要切换jetty):


<dependencies>
        <!--移除tomcat的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--引入jetty的依赖-->
        <dependency>
            <artifactId>spring-boot-starter-jetty</artifactId>
            <groupId>org.springframework.boot</groupId>
        </dependency>
    </dependencies>


③. @Enable * 注解原理


3>. @Enable * 注解原理


①. 问题的提出:SpringBoot工程是否可以直接获取jar包中定义的Bean?

不能,ComponentScan只能扫描引导类所在包及子包


②. 解决方案:

(1).使用@ComponentScan进行包扫描

(2).@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器

(3).可以对@Import进行封装,这样就可以不需要知道@Import()里面填写什么东西


④. @Import

4>. @Import


①. 导入Bean


②. 导入配置类


③. 导入ImportSelector实现类,一般用于加载配置文件中的类

//这是工程和User类是同一个工程,@Import 则是另一个工程
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //这里的 "com.itheima.domain.User" 是全限类名
        return new String[]{"com.itheima.domain.User"};
    }
}
@SpringBootApplication
//@Import(User.class)
@Import(MyImportSelector.class)
public class SpringbootApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);
        User user= context.getBean(User.class);
        /*Map<String, User> map = context.getBeansOfType(User.class);
        System.out.println(map);*/
        System.out.println(user);
    }
}


  • ④. 导入ImportBeanDefinitionRegistrar 的实现类(了解)


⑤. @EnableAutoConfiguration

5>. @EnableAutoConfiguration 掌握


①. EnableAutoConfiguration 中的@Import 在SpringBoot中流程分析:

image.png

image.png

image.png

  • ②. @EnableAutoConfiguration注解内部使用@Import({AutoConfigurationImportSelector.class})来加载配置类


  • ③. 配置文件位置:META-INF/spring.factories,该配置文件中定义了大量的配置类,当SpringBoot应用启动时,会自动加载这些配置类,初始化Bean


  • ④. 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
安全 Java 数据安全/隐私保护
SpringBoot实现二维码扫码登录的原理与详细步骤
SpringBoot实现二维码扫码登录的原理与详细步骤
81 1
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
44 0
|
2月前
|
缓存 Java Maven
Spring Boot自动配置原理
Spring Boot自动配置原理
48 0
|
3月前
|
NoSQL Java 测试技术
字节二面:Spring Boot Redis 可重入分布式锁实现原理?
字节二面:Spring Boot Redis 可重入分布式锁实现原理?
158 1
|
3月前
|
消息中间件 缓存 监控
spring boot 高级篇
spring boot 高级篇
103 1
|
3月前
|
消息中间件 存储 安全
RabbiMQ原理与SpringBoot使用
RabbiMQ原理与SpringBoot使用
38 0
|
1月前
|
前端开发 搜索推荐 Java
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
|
3月前
|
监控 Java 应用服务中间件
SpringBoot3 快速入门及原理分析
SpringBoot3 快速入门及原理分析
|
10天前
|
Java 容器 Spring
Springboot自动配置原理
Springboot自动配置原理
|
26天前
|
Java API 开发者
springboot 多线程的使用原理与实战
在Spring Boot中实现多线程,主要依赖于Spring框架的@Async注解以及底层Java的并发框架。这里将深入剖析Spring Boot多线程的原理,包括@Async注解的工作方式、任务执行器的角色以及如何通过配置来调整线程行为。
33 5