@Import注解使用详解

SPRING容器注解@Import

最近在研究springboot源码和spring secruity过滤链,发现一个注解很常用@Import,研究了一下发现功能起始和@Bean一样在IOC容器注入对象,但是好像牛皮多了一点,就整理了一下学习资料.

Import的作用

基本上作用就是通过不同方式将bean对象放到你的IOC容器中.这里的IOC容器可以使用Spring的AnnotationConfigApplicationContext直接加载一个入口测试类,也可以通过springboot的启动类做测试,这里我们选择后者.

第一种方式,直接导入class

先来一个类TestBean1

package cn.tedu.normal;
public class TestBean1 {
    public TestBean1(){
        System.out.println("哎,我TestBean1被谁创建了怎么回事");
    }
}

在springboot启动类中(本身这就是一个spring容器入口类),添加类注解@Import将TestBean1创建导入到容器中.

package cn.tedu;

import cn.tedu.normal.TestBean1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import({TestBean1.class})
public class SpringImportAnnotaionDemo01Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringImportAnnotaionDemo01Application.class, args);
    }
}

然后启动,可以看到有什么效果,在控制台可以打印bean被加载了这一句话,当然也可以到各种其他代码中注入这个bean使用了.所以你可能知道一万中把bean对象加载到IOC中,import是其中一种.

看见了吗,对象通过import确实被加载了,可以通过@Autowired测试是否在IOC容器.

第二种方式,导入选择器

在这里说这种方式能干什么你还理解不了,所以先做.导入选择器,必须让我们的选择器类实现一个接口ImportSelector.
咱们先准备一个测试类TestBean2.

package cn.tedu.normal;

public class TestBean2 {
    public TestBean2(){
        System.out.println("哎,我TestBean2也被加载了");
    }
}

一个普通的class,即将被我们使用导入选择器的方式导入到当前容器IOC中.
实现一个ImportSelector接口的类.

package cn.tedu.selector;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        String[] classes={"cn.tedu.normal.TestBean2"};
        return classes;
    }
}

需要实现一个接口方法selectImports,还有个参数annotationMetadata,这个参数中保存了使用该importSelector对象所在的配置类的注解信息.如果我们是在一个spring boot启动类中使用了@SpringBootApplication和@Import导入的话,这个参数中就会保存这2个注解可以给我们使用.作用是什么目前还没整明白,不过这个参数在这里不重要.
看到代码里我们在实现方法中返回了一个数组,数组元素值就是我们想要让容器通过这个ImportSelector导入时创建的类的全路径名称.看到这里你就可以去翻一翻springboot的源码了.@EnableAutoConfiguration就是通过导入一个选择器实现各种底层自定义配置类的加载的.

package cn.tedu;

import cn.tedu.normal.TestBean1;
import cn.tedu.selector.MyImportSelector;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Import({TestBean1.class, MyImportSelector.class})
public class SpringImportAnnotaionDemo01Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringImportAnnotaionDemo01Application.class, args);
    }
}

启动容器,发现两个bean都被加载了.

第三种方式,导入BeanDefinitionRegistrar

上述两种方式导入的bean对象总结一下,Import导入class,你得一个类一个类的挑出来放到注解属性值中,而ImportSelector导入就方便了,只要准备好一个文件里面记录所有导入的类全路径名称就搞定.两种方式都是默认使用类路径名称来做对象的id.还有第三种导入的内容,我们可以导入一个自定义id等参数的bean对象

准备一个测试类TestBean3

package cn.tedu.normal;
public class TestBean3 {
    public TestBean3(){
        System.out.println("哎,TestBean3被加载了");
    }
}

准备一个ImportBeanDefinitionRegistrar实现类

package cn.tedu.registrar;

import cn.tedu.normal.TestBean3;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        BeanDefinition beanDefinition=new RootBeanDefinition(TestBean3.class);
        System.out.println("定义bean的各种属性"+beanDefinition.getBeanClassName()+"/"+beanDefinition.getDescription()+"/"
                +beanDefinition.getParentName()+"/"+beanDefinition.getScope());
        beanDefinitionRegistry.registerBeanDefinition("haha",beanDefinition);
    }
}

这里又在干什么呢.beanDefinition定义的是通过这种方式创建容器bean时,对于bean的一些参数属性,在测试代码中我将RootBeanDefinition中的一些默认值打印了出来,然后自定义haha作为bean的名称来使用.

在springboot启动类中添加自定义registrar类

package cn.tedu;

import cn.tedu.normal.TestBean1;
import cn.tedu.registrar.MyImportRegistrar;
import cn.tedu.selector.MyImportSelector;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Import({TestBean1.class, MyImportSelector.class, MyImportRegistrar.class})
public class SpringImportAnnotaionDemo01Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringImportAnnotaionDemo01Application.class, args);
    }

}

最后启动可以看到输出结果
hong在这里插入图片描述
红框上的就是beanDefinitin中的默认各种值.这里没有继续修改,还可以获取其他值.

发布了6 篇原创文章 · 获赞 3 · 访问量 546
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览