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自动装配之@Import4种用法及源码分析(10) -> 正文阅读

[Java知识库]SpringBoot自动装配之@Import4种用法及源码分析(10)

作者:language-java

目录

前言

1、@Import用法分类

2、@Import各用法详解

1、导入Bean

2、导入配置类(上篇讲过)

?3、导入 ImportSelector 实现类

4、导入ImportBeanDefinitionRegistrar实现类


前言

????????上一篇介绍了@Enable*注解,底层实际上是用到了@Import注解,上一篇只简单讲了@Import导入配置类的用法,本文将详细讲解@Import四种用法。

1、@Import用法分类

① 导入Bean;
② 导入配置类;
③ 导入 ImportSelector 实现类,一般用于加载配置文件中的类;
④ 导入 ImportBeanDefinitionRegistrar 实现类。

2、@Import各用法详解

1、导入Bean

????????沿用上篇中的两个模块springboot-enablespringboot-embedded,两个模块的具体代码本次不再重新贴出,需要的请移步SpringBoot自动配置之@Enable*注解源码分析(9)现在修改springboot-enable的启动类如下:

package com.itlean;

import com.embedded.domain.User;
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)//直接导入三方jar中的对象
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //此处不能用别名获取了,因为SpringBoot注入IOC容器的时候不一定就叫user,要根据类型获取
        User user = context.getBean(User.class);
        System.out.println(user);
        //获取IOC中所有User类型的对象
        Map<String, User> users = context.getBeansOfType(User.class);
        System.out.println(users);
    }
}

启动后,输出如下,说明导入成功:

2、导入配置类(上篇讲过)

springboot-embedded新增加对象:

package com.embedded.domain;

/**
 * @describe:
 * @author: weny.yang
 * @date: 2021-09-08 21:01
 */
public class Role {
}

配置类UserConfig.java中新增一个Role的Bean配置:

package com.embedded.config;

import com.embedded.domain.Role;
import com.embedded.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @describe:
 * @author: weny.yang
 * @date: 2021-09-08 20:39
 */

//@Configuration 注意:调用方使用@Import导入配置类方式情况下,此处(三方jar配置Bean的配置类)可以不加@Configuration注解
public class UserConfig {

    @Bean
    public User user(){
        return new User();
    }
    @Bean
    public Role role(){
        return new Role();
    }
}

修改springboot-enable的启动类如下:

package com.itlean;

import com.embedded.config.UserConfig;
import com.embedded.domain.Role;
import com.embedded.domain.User;
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(UserConfig.class)//直接导入三方jar中的对象的配置类
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //此处不能用别名获取了,因为SpringBoot注入IOC容器的时候不一定就叫user,要根据类型获取
        User user = (User)context.getBean("user");
        System.out.println(user);
        Role role = (Role)context.getBean("role");
        System.out.println(role);
        //获取IOC中所有User类型的对象
        Map<String, User> users = context.getBeansOfType(User.class);
        System.out.println(users);
        Map<String, Role> roles = context.getBeansOfType(Role.class);
        System.out.println(roles);
    }
}

????????导入一个配置类,可以注入多个Bean,另外,调用方使用@Import导入配置类方式情况下,三方jar配置Bean的配置类可以不加@Configuration注解,启动后,输出如下,说明导入成功:

3、导入 ImportSelector 实现类

ImportSelecto是一个接口,我们先来看一下源码:

package org.springframework.context.annotation;

import java.util.function.Predicate;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }
}

????????ImportSelecto接口源码类中有String[] selectImports(AnnotationMetadata var1);方法,该方法返回值是Bean的全限定路径名,这个方法需要我们来实现它,下面我们在springboot-embedded模块中自定义一个名为MyImportSelecto.java的实现类:

package com.embedded.config;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @describe:
 * @author: weny.yang
 * @date: 2021-09-08 21:21
 */
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //入参为要创建的Bean的全限定路径名
        return new String[]{"com.embedded.domain.User","com.embedded.domain.Role"};
    }
}

修改springboot-enable的启动类如下:

package com.itlean;

import com.embedded.config.MyImportSelector;
import com.embedded.config.UserConfig;
import com.embedded.domain.Role;
import com.embedded.domain.User;
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(MyImportSelector.class)//直接导入三方jar中的对象的ImportSelector接口的实现类MyImportSelector配置类
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //此处不能用别名获取了,因为SpringBoot注入IOC容器的时候不一定就叫user,要根据类型获取
        User user = (User)context.getBean(User.class);
        System.out.println(user);
        Role role = (Role)context.getBean(Role.class);
        System.out.println(role);
        //获取IOC中所有User类型的对象
        Map<String, User> users = context.getBeansOfType(User.class);
        System.out.println(users);
        Map<String, Role> roles = context.getBeansOfType(Role.class);
        System.out.println(roles);
    }
}

启动后,输出如下:

????????说明注入成功,到这,有些伙伴可能说了,这种方式不是比前两种还要复杂吗,方式二就已经满足同时注入多个Bean了呀,但是细想,方式二导入配置类,整个配置类里面可能配置了几十上百个Bean,一下子全部注入到IOC了,有一些我们用不到的也一并注入了,肯定是不合理的,方式三却可以将要注入的Bean的全路径限定名配置在配置文件中,根据实际业务动态的实现Bean的注入,更加可控灵活。

4、导入ImportBeanDefinitionRegistrar实现类

首先来看一下ImportBeanDefinitionRegistrar.java接口源码:

package org.springframework.context.annotation;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.type.AnnotationMetadata;

public interface ImportBeanDefinitionRegistrar {
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        this.registerBeanDefinitions(importingClassMetadata, registry);
    }
    default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    }
}

????????源码内部有一个default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {}空实现方法,现在我们实现它,在springboot-embedded中自定义一个名为MyImportBeanDefinitionRegistrar.java的ImportBeanDefinitionRegistrar.java的实现类:

package com.embedded.config;

import com.embedded.domain.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;

/**
 * @describe:
 * @author: weny.yang
 * @date: 2021-09-08 21:42
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AbstractBeanDefinition userBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        registry.registerBeanDefinition("user", userBeanDefinition);
    }
}

修改springboot-enable的启动类如下:

package com.itlean;

import com.embedded.config.MyImportBeanDefinitionRegistrar;
import com.embedded.config.MyImportSelector;
import com.embedded.config.UserConfig;
import com.embedded.domain.Role;
import com.embedded.domain.User;
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(MyImportBeanDefinitionRegistrar.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //此处不能用别名获取了,因为SpringBoot注入IOC容器的时候不一定就叫user,要根据类型获取
        User user1 = (User)context.getBean(User.class);
        User user2 = (User)context.getBean("user");
        System.out.println(user1);
        System.out.println(user2);
        //获取IOC中所有User类型的对象
        Map<String, User> users = context.getBeansOfType(User.class);
        System.out.println(users);
    }
}

启动后,输出如下,因为实现类中有指定Bean的别名,所以获取的时候可以根据名字也可以根据类型。

============================================优雅的分割线=============================================

以上就是@Import的四种用法,现在我们像上篇一样,再次回看SpringBoot启动类上面的@SpringBootApplication注解,内部组合使用到的@Import注解是这样的:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class}) //说明是本文介绍的第三种方式
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

????????说明SpringBoot底层的@Import注解使用第三种方式,实现了ImportSelector接口,以这种方式完成了SpringBoot启动的时候动态的加载类,也是SpringBoot自动装配的核心注解之一,至于@SpringBootApplication中的ImportSelector在启动的时候到底干了哪些的不为人知的事情,我们下一篇文章再行详解。

如果学到了,不妨点赞收藏哦,一起加油!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-10 23:55:15  更:2021-09-10 23:56:05 
 
开发: 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 17:13:34-

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