IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springboot ImportBeanDefinitionRegistrar注入bean -> 正文阅读

[Java知识库]springboot ImportBeanDefinitionRegistrar注入bean

简介

  • ImportBeanDefinitionRegistrar类只能通过其他类@Import的方式来加载,通常是启动类或配置类
  • 使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,则会调用接口方法,将其中要注册的类注册成bean。

使用自定义注解, 将bean注入到springboot容器中

项目结构

项目结构

类代码

自定义注解

/**
 * 自定义注解, 作用同spring @service注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyService {
    
    
}

需要被注入的类

/**
 * 被注入的类
 */
@MyService
public class UserService {

    public void print(){
        System.out.println("userService对象注入成功");
    }
}

启动类

@SpringBootApplication
@EnableAsync
@EnableScheduling
//在启动类上, 标记@Import注解, MyImportBeanDefinitionRegistrar类是ImportBeanDefinitionRegistrar子类
@Import({MyImportBeanDefinitionRegistrar.class})
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        UserService bean = context.getBean(UserService.class);
        bean.print();
    }
}

在启动类上标记@Import注解, 将MyImportBeanDefinitionRegistrar类设置为属性, 项目启动时, 会执行MyImportBeanDefinitionRegistrar类中的registerBeanDefinitions()方法

MyImportBeanDefinitionRegistrar

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        //自定义的扫描类MyClassPathBeanDefinitionScanner, 实现了ClassPathBeanDefinitionScanner接口
        // 当前MyClassPathBeanDefinitionScanner已被修改为扫描带有指定注解的类
        MyClassPathBeanDefinitionScanner scanner = new MyClassPathBeanDefinitionScanner(registry, false);
//        scanner.setResourceLoader(resourceLoader);
        scanner.registerFilters();
        scanner.doScan("com.hctrl");
    }
}

在该类中, 自定义了一个扫描器MyClassPathBeanDefinitionScanner, 通过给扫描器设置扫描的注解, 扫描的路径, 就会将该路径下的标有扫描注解的类进行注入

MyClassPathBeanDefinitionScanner

public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {

    public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
        super(registry, useDefaultFilters);
    }

    /**
     * @addIncludeFilter 将自定义的注解添加到扫描任务中
     * @addExcludeFilter 将带有自定义注解的类 ,不加载到容器中
     */
    protected void registerFilters () {
        /**
         *  addIncludeFilter  满足任意includeFilters会被加载
         *  注入@MyService注解标记的类
         */
        addIncludeFilter(new AnnotationTypeFilter(MyService.class));
        /**
         *  addExcludeFilter 同样的满足任意excludeFilters不会被加载
         *  可以配置过滤
         */
        // addExcludeFilter(new AnnotationTypeFilter(MyService.class));
    }

    /**
     * 重写类扫描包路径加载器,调用父类受保护的扫描方法 doScan
     * @param basePackages
     * @return
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        return super.doScan(basePackages);
    }
}

在自定义的扫描器中, 配置的扫描路基和注解
MyClassPathBeanDefinitionScanner类继承了spring提供的ClassPathBeanDefinitionScanner类, 顾名思义, 这个类就是用来扫描类, 将类转化为beanDefinition对象的
让我们进入MyImportBeanDefinitionRegistrar类的doScan方法进行源码追踪
在这里插入图片描述
在这里插入图片描述
ScannedGenericBeanDefinition对象是BeanDefinition接口的子类, 里面包含大量构建bean的属性
在这里插入图片描述

  private volatile Object beanClass;//bean的类型
    private String scope;//bean的作用范围
    private boolean abstractFlag;//是否是抽象类
    private boolean lazyInit;//是否延迟加载
    private int autowireMode; //自动注入模式
    private int dependencyCheck;//依赖检查,spring 3.0后弃用
    private String[] dependsOn; //表示这个bean,依赖于其它beans先实例化
    private boolean autowireCandidate;//设为false,则容器在自动装配时,将不考虑该bean(即这个bean不会作为其它bean自动装配的候选者),但是这个bean还可以自动装配其它bean
    private boolean primary;//自动装配出现多个bean时,将它作为首选者
    private final Map<String, AutowireCandidateQualifier> qualifiers;//用于记录Qualifier
    private boolean nonPublicAccessAllowed;//允许访问非公开的构造器和方法
    private boolean lenientConstructorResolution;//是否以宽松的模式解析构造函数,默认为true
    private String factoryBeanName;//指定工厂类和工厂方法
    private String factoryMethodName;
    private ConstructorArgumentValues constructorArgumentValues;//记录构造函数注入属性
    private MutablePropertyValues propertyValues;//普通属性集合
    private MethodOverrides methodOverrides; //方法重写的持有者
    private String initMethodName; //初始化方法
    private String destroyMethodName; //销毁方法
    private boolean enforceInitMethod; //是否执行初始化方法
    private boolean enforceDestroyMethod;//是否执行销毁方法
    private boolean synthetic;//是否是用户定义的而不是应用程序本身定义的,创建AOP时为true
    private int role;//定义这个bean的使用,application:用户,infrastructure:完全内部使用,与用户无关;support:某些复杂配置的一部分
    private String description;//bean的描述
    private Resource resource;//这个bean定义的资源。

beanDefinition创建方法

在这里插入图片描述

@Component注解类注入原理

ClassPathBeanDefinitionScanner是springboot提供的, 它默认会扫描和启动类同级目录下的所有文件下的类, 如果类上标记了@Component注解(或者@Component是他们元注解, 比如@Service, @Controller等)就会被注入到容器中
源码解析 :
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
至此, @Component标记的类全部注入完成, 只有就是对beanDefinition对象赋默认值

mybatis 通过ImportBeanDefinitionRegistrar将所有的Mapper对象注入到容器中

前提

创建一个项目, pom.xml包含

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

首先查看mybatis的自动装配
在这里插入图片描述
在这里插入图片描述
进入到MapperScannerConfigurer类中
在这里插入图片描述
可以看到, 该类实现了BeanDefinitionRegistryPostProcessor接口, 项目启动时会执行postProcessBeanDefinitionRegistry()方法
在这里插入图片描述

可以看出, 该方法的主要作用就是创建一个ClassPathMapperScanner扫描器, 用来扫描@Mapper注解
可以推断, ClassPathMapperScanner应该是ClassPathBeanDefinitionScanner的子类
在这里插入图片描述
之后在类启动时, ClassPathMapperScanner扫描器就会将指定路径下的, 所有标记@Mapper注解的类注入到容器中

这就是Mybatis对象注入的全部流程

== 问题 : @Mapper注解都是标记在接口上, 那么接口什么时候生成的代理对象呢? ==

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-16 11:13:45  更:2022-05-16 11:14:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:29:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码