Spring @Import实现对象的引入

Springboot在实现自动配置时,在注解@EnableAutoConfiguration中使用了@Import注解来注入AutoConfigurationImportSelector对象,这个类实现很多的自动装配逻辑,这在Springboot的自动装配实现中,是非常关键的一步。

查阅@Import官方注解说明可知,@Import 用于类上,专门用于引入被@Configuration标记的类,它的功能类似spring xml配置文件中的<import>标签,还可以用于引入ImportBeanDefinitionRegistrar、ImportSelector接口的实现(AutoConfigurationImportSelector使用的就是这种方式),功能等同于AnnotationConfigApplicationContext的register方法。@Import引入@Configuration标记的类时,类中被@Bean标记的方法的返回对象将会和类一起被引入。如果是xml配置文件或非Java编码形式定义的Bean需要引入,可以使用@ImportResource注解。具体可参考@ImportResource的使用。

/**
 * 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.
 *
 */

@Import注入的3种方式

(1)@Configuration标记的类

(2)接口ImportBeanDefinitionRegistrar的实现

(3)接口ImportSelector的实现

注入@Configuration标记的类

/**
 * 定义注解,使用@Import注入@Configuration标记的类
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Import({ImportConfiguration.class})
public @interface EnableBar {

}
@Configuration
public class ImportConfiguration {

    @Bean(name="bean-of-bar")
    public Bar bar(){

        return new Bar("Bar");
    }
}
@Getter
@Setter
@ToString
public class Bar {

    public Bar(String name){
        this.name = name;
    }

    private String name;

}

从Spring Context中获取Bar对象

@Slf4j
@EnableBar
public class Bootstrap {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = new SpringApplicationBuilder(Bootstrap.class)
                .web(WebApplicationType.NONE).run(args);
        Bar bean = context.getBean(Bar.class);
        ImportConfiguration config = context.getBean(ImportConfiguration.class);
        log.info("Bar:{}",bean.toString());
        log.info("BarConfig:{}",config.toString());
    }
}

从Spring的上下文中获取对象,此时两个对象都已经注入到Context中

注入接口ImportBeanDefinitionRegistrar的实现

/**
 * 定义注解,注入ImportBeanDefinitionRegistrar的实现
 */
@Documented
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(ImportBeanDefinitionRegistrarImpl.class)
public @interface EnableDefinitionRegistrar {
}
public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
          //使用RootBeanDefinition也可实现bean的注册
//        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Bar.class);
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(Bar.class.getName());
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        propertyValues.add("name","registartName");
        registry.registerBeanDefinition("bar",beanDefinition);

    }
}

从上下文中获取对象

@Slf4j
@EnableDefinitionRegistrar
public class Bootstrap {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = new SpringApplicationBuilder(Bootstrap.class)
                .web(WebApplicationType.NONE).run(args);
        Bar bar = (Bar)context.getBean("bar");
        log.info("Bar:{}",bar.toString());
    }
}

结果可以获取到对象:

注入接口ImportSelector的实现

/**
 * 定义注解,引入ImportSelector的实现类
 */
@Documented
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(ImportSelectorImpl.class)
public @interface EnableBarSelector {

}
public class ImportSelectorImpl implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //返回需要注入的bean的类名
        return new String[]{Bar.class.getName()};
    }
}

从上下文中获取对象

@Slf4j
@EnableBarSelector
public class Bootstrap {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = new SpringApplicationBuilder(Bootstrap.class)
                .web(WebApplicationType.NONE).run(args);
        Bar bean = context.getBean(Bar.class);
        log.info("Bar:{}",bean.toString());
    }
}

结果

 

自定义注解结合@Import注解,可实现对象的动态注入,方便我们实现bean的自定义。当然Spring框架的核心注解还很多,这些都值得我们深入学习,这可以帮助我们解决实际开发中的很多问题,其实我们遇到的问题,编写框架的大神们都已经给我们提供了很好的解决方案,只待我们去发现而已。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值