Spring中@Import注解的作用

本文主要介绍Spring的@Import注解,它可导入Bean、@Configuration类等,能解决@ComponentScan无法扫描第三方jar包中@Bean的问题,还可结合@Conditional注解条件导入。同时通过声明普通Java类、创建相关实现类等步骤进行了@Import注解的实战测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、关于@Import

翻看spring的源码,@Import注解几乎随处可见,因此有必要了解一下@Import注解是用来干什么的,不然你都看不懂spring的源码。

首先看一下@Import注解的源码

package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Indicates one or more <em>component classes</em> to import &mdash; typically
 * {@link Configuration @Configuration} classes.
 *
 * <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
 * Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
 * {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
 * classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
 *
 * <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
 * accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
 * injection. Either the bean itself can be autowired, or the configuration class instance
 * declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
 * navigation between {@code @Configuration} class methods.
 *
 * <p>May be declared at the class level or as a meta-annotation.
 *
 * <p>If XML or other non-{@code @Configuration} bean definition resources need to be
 * imported, use the {@link ImportResource @ImportResource} annotation instead.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.0
 * @see Configuration
 * @see ImportSelector
 * @see ImportBeanDefinitionRegistrar
 * @see ImportResource
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
  /**
   * {@link Configuration @Configuration}, {@link ImportSelector},
   * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
   */
  Class<?>[] value();
}

类注释比较清楚地说明了@Import注解的作用,这里我翻译一下。

  • 声明一个或多个Component

  • 提供等同于spring的xml配置中<import/>元素的功能,允许导入@Configuration类、ImportSelector的实现和ImportBeanDefinitionRegistrar的实现,当然也可以导入一个常规的类作为Component(类似于4.2版本后,利用AnnotationConfigApplicationContext类的register方法导入一个普通的类作为Component)

  • 在@Configuration中声明的Bean应该被@Autowired注解注入,要么Bean自己被自动装配,要么声明bean的配置类被自动装配,后者允许在@Configuration类的方法之间进行显式的、IDE友好的导航

  • 可以声明在类级别上,或者作为一个元注解

  • 可以用@ImportResource注解代替@Import注解,去导入xml配置

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

  • 导入一个或多个Bean

  • 导入@Configuration类

  • 导入ImportSelector的实现类

  • 导入ImportBeanDefinitionRegistrar的实现类

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

  • @ComponentScan一般只会扫到自己项目中的Bean,第三方jar包中的@Bean扫不到

  • @Import注解可以结合@Conditional注解使用,即条件导入,@Conditional在spring源码中也是大量用到,这个我后面会专题介绍

2、@Import实战

@Import注解位于spring-context包下面,所以我们只需要普通的spring环境即可,当然springboot环境更可以,环境搭建这里我不介绍了,直接上例子。

2.1、声明普通Java类

由于前面介绍有四种方案可以通过@Import导入Bean,所以我先声明四个普通类(不打@Component)

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";
    }
}

2.2、创建ImportBeanByConfig

注意:ImportBeanByConfig类不能被@ComponentScan扫描到,否则用@Import注解导入它就没有意义了

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

2.3、创建ImportSelector实现

public class ImportBeanByImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.bobo.group.extra.TestBean3"};
    }
}

2.4、创建ImportBeanDefinitionRegistrar实现

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

2.5、创建用@Import注解声明的类

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

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

2.6、写一个Controller方法测试

import com.bobo.group.extra.TestBean1;
import com.bobo.group.extra.TestBean2;
import com.bobo.group.extra.TestBean3;
import com.bobo.group.extra.TestBean4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@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);
    }
}

访问HTTP接口,控制台打印日志如下:

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

可以看到两者的效果是不一样的,至于为什么大家都懂。spring源码博大精深,必须一步一个脚印才能更好地掌握与运用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

波波老师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值