@Import注解详解

@Import这个注解非常重要,而且在springboot项目当中随处可见,就拿springboot启动类来说,我们经常会遇到一些@Enable相关的注解,例如开启异步@EnableAsync、开启缓存支持@EnableCaching、开启定时任务@EnableScheduling等等…

一、@Import源码

点开源码会发现他没有使用其他特别的注解,就是用了三个元注解:

  • @Target({ElementType.TYPE}): 使用范围接口、类、枚举、注解
  • @Retention(RetentionPolicy.RUNTIME): @Retention是用来修饰注解的生命周期的,RetentionPolicy.RUNTIME代表的是不仅被保存到class文件中,jvm加载class文件之后,仍然存在;一直有效!
  • @Documented: @Documented和@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成Javadoc文档时,会显示@B。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

二、@Import官网介绍

这些@Enable注解你点进去就发现都是使用的@Import注解,就是利用@Import注解来将指定的配置类加载到容器当中!

在这里插入图片描述

@Import属于spring当中的注解,在spring-context包下。@Import源码,以及官网解释该注解:https://github.com/spring-projects/spring-framework/blob/main/spring-context/src/main/java/org/springframework/context/annotation/Import.java

(1)源码注释比较清楚地说明了@Import注解的作用,这里我翻译一下:

  • 声明一个或多个Component(Component代表的是组件,或者可以理解为对象)
  • 提供等同于spring的xml配置中<import/>元素的功能,允许导入@Configuration类、ImportSelector的实现和ImportBeanDefinitionRegistrar的实现,当然也可以导入一个常规的类作为Component(类似于4.2版本后,利用AnnotationConfigApplicationContext类的register方法导入一个普通的类作为Component)
  • 在@Configuration中声明的Bean应该被@Autowired注解注入,可以自动连接bean本身,也可以自动连接声明bean的配置类实例,后者允许在@Configuration类的方法之间进行显式的、IDE友好的导航
  • 可以声明在类级别上,或者作为一个元注解
  • 可以用@ImportResource注解代替@Import注解,去导入xml配置

(2)根据上面的翻译,我总结一下@Import注解的用法

  • 作用:
    • 导入一个或多个Bean
    • 导入@Configuration类
    • 导入ImportSelector的实现类
    • 导入ImportBeanDefinitionRegistrar的实现类
  • 使用前提: @Import必须要在@controller、@Service、@Component、@Configuration、@Repository修饰的类下,并且要在springboot扫描范围内,这些注解修饰的类默认是必须和springboot启动类同包才会被扫描到,当然也可以手动指定扫描包。在启动类上使用@Import也是可以的!使用@Bean注解间接创建的对象当中使用@Import是不可以的。如下示例就是不可以的哦!
@Configuration
public class Myconfig {
	@Bean
    public MyconfigTest myconfigTest(){
        return new MyconfigTest();
    }
}

@Import({TestBean1.class})
public class MyconfigTest {
}

(3)这些用法或许只有一个目的,就是导入Bean。那为什么要这么麻烦,手动导入Bean呢,@ComponentScan不是可以自动扫描包注册Bean嘛?其实这里的原因有两点:

  • @ComponentScan一般只会扫到自己项目中的Bean,第三方jar包中的@Bean扫不到
  • @Import注解可以结合@Conditional注解使用,即条件导入,@Conditional在spring源码中也是大量用到,这个我后面会专题介绍

(4)@Import等同于之前的<import/>标签

官方解释:<import/>元素在Spring XML文件中用于帮助模块化配置一样,@Import注释允许从另一个配置类加载@Bean定义,如果您想要避免组件扫描,通过使用一些配置类作为入口点显式定义所有组件,Import尤其有用。

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

三、@Import的四种用法

通过@Import注入对象的四种方式

理论我们都明白了,剩下来实操,首先定义四个类,我们分别用不同的方式将这四个类存到容器当中。

public class TestBean1 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean1";
    }
}

public class TestBean2 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean2";
    }
}

public class TestBean3 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean3";
    }
}

public class TestBean4 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean4";
    }
}

方式一:间接的@Configuration和@Bean注入

注意:ImportBeanByConfig类不能被@ComponentScan扫描到,如果扫描到通过@Configuration注解都可以将testBean2放入到容器当中了,用@Import注解导入它就没有意义了

@Configuration
public class ImportBeanByConfig {
    @Bean
    public TestBean2 testBean2(){
        return new TestBean2();
    }
}

方式二:创建ImportSelector实现

ImportSelector接口只定义了一个String[] selectImports(AnnotationMetadata importingClassMetadata);,用于指定需要注册为bean的Class名称。使用@Import引入了一个ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean

public class ImportBeanByImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
    	// 这里全类名
        return new String[]{"com.gzl.cn.springbootcache.config.TestBean3"};
    }
}

方式三:创建ImportBeanDefinitionRegistrar实现

public class ImportBeanByImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestBean4.class);
        registry.registerBeanDefinition("TestBean4", rootBeanDefinition);
    }
}

方式四:直接被注入(直接写要注入的类class)

ImportTest类是需要被@ComonentScan扫到的,否则@Import直接不会生效

@Import({TestBean1.class,
        ImportBeanByConfig.class,
        ImportBeanByImportSelector.class,
        ImportBeanByImportBeanDefinitionRegistrar.class})
@Configuration
public class ImportTest {
}

写一个Controller方法测试

正常使用@Autowired注解的话,假如容器当中没有这个对象是会报错的,所以我们这里设置为required = false,这样就算没有这个对象,启动不会报错。

@RestController
public class CommonController {
    @Autowired(required = false)
    private TestBean1 testBean1;
    @Autowired(required = false)
    private TestBean2 testBean2;
    @Autowired(required = false)
    private TestBean3 testBean3;
    @Autowired(required = false)
    private TestBean4 testBean4;

    @RequestMapping("/import")
    public void printImportBeanInfo() {
        System.out.println(testBean1);
        System.out.println(testBean2);
        System.out.println(testBean3);
        System.out.println(testBean4);
    }
}

测试结果:

在这里插入图片描述

将ImportTest类的@Import注释掉,再次访问HTTP接口,控制台打印日志如下:

在这里插入图片描述

四、@Import扩展注解

@ImportAutoConfiguration@EnableAutoConfiguration就是通过@Import注解所扩展出来的注解,@ImportAutoConfiguration应该用到的比较少,但是@EnableAutoConfiguration注解大家应该不陌生吧,他是springboot当中@SpringBootApplication启动注解当中的组合注解之一,读springboot源码基本上都需要了解这个的。

在这里插入图片描述

五、@ImportResource注解

早在以前我们注入bean都是 通过xml来实现的,springboot项目当中已经很少见了,都是通过注解来存放到容器当中的,@ImportResource就是将xml配置文件生效。接下来通过代码来演示他的作用。

(1)创建一个类

@Data
public class Student {
    private String name;
    private Integer age;
}

(2)添加applicationContext.xml

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dog1" class="com.gzl.cn.springbootcache.config.Student">
        <property name="name" value="zhangsan"/>
        <property name="age" value="27"/>
    </bean>
</beans>

(3)添加配置

@Configuration
@ImportResource(locations = "classpath:applicationContext.xml")
public class Myconfig {
}

(4)添加测试

@RestController
public class CommonController {
    @Autowired(required = false)
    private Student student;

    @RequestMapping("/import")
    public void printImportBeanInfo() {
        System.out.println(student);
    }
}

(5)启动访问接口:打印如下,成功从容器当中取出。

在这里插入图片描述

假如把@ImportResource(locations = "classpath:applicationContext.xml")去掉打印如下:

在这里插入图片描述

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
@Import注解Java中用于导入其他配置类或组件的注解,它可以用在类级别上,用于导入其他类或组件,从而让它们成为当前类的依赖项。@Import注解支持三种不同的导入方式: 1. 导入配置类: 可以使用@Import注解来导入一个或多个配置类,这些配置类会被Spring容器加载并且进行解析,从而可以在应用程序中使用。例如: ``` @Configuration @Import({Config1.class, Config2.class}) public class AppConfig { // Configuration code... } ``` 在上面的例子中,AppConfig类使用@Import注解来导入了Config1和Config2两个配置类。 2. 导入普通的组件: 除了导入配置类外,@Import注解还可以用来导入普通的组件,例如一个普通的Java类、接口或枚举。例如: ``` @Configuration @Import(MyComponent.class) public class AppConfig { // Configuration code... } ``` 在上面的例子中,AppConfig类使用@Import注解来导入了一个名为MyComponent的普通Java组件。 3. 导入ImportSelector: @Import注解还可以使用ImportSelector类型的实现类来动态地导入一组组件,这些组件可以根据不同的条件进行选择。例如: ``` @Configuration @Import(MyImportSelector.class) public class AppConfig { // Configuration code... } ``` 在上面的例子中,AppConfig类使用@Import注解来导入了一个名为MyImportSelector的ImportSelector实现类,它会根据不同的条件来选择一组组件,然后将它们动态导入到应用程序中。 总之,@Import注解是一个非常有用的注解,它可以帮助我们方便地导入其他配置类或组件,从而让我们的应用程序更加灵活和可扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怪 咖@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值