【Spring】@Import注解

概述

@Import是Spring框架提供的一个注解,用于将实例加入到Spring的IOC容器中,提供类似@Bean注解的功能,也同效于Spring XML中的</import>,@Import有三种用法:

  1.  普通方式
  2.  ImportSelector方式
  3.  ImportBeanDefinitionRegister方式


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

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

@Target表示作用范围,可在类、接口、枚举上使用

value是仅有的属性,是一个类对象数组,数组值为交由IOC管理的对象

@Import的三种用法

1.普通方式

直接填写class,可以写入多个class

先创建一个普通类

package com.ck.springautomatic.test;

public class TestOne {
    public void testPrintln(){
        System.out.println("普通方式,直接写入class!");
    }
}

然后利用Spring的ApplicationRunner来做测试

/**
 * 服务启动后立即执行
 * @author CK
 */
@Component
@Import(com.ck.springautomatic.test.TestOne.class)
public class StartRun implements ApplicationRunner {

	@Autowired
	private TestOne testOne;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		/** 获取IOC容器管理的实例 */
		ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
		String [] strings = applicationContext.getBeanDefinitionNames();
		for(String str : strings){
			/** 实例列表中是否包含@Import中加入的类 ,如包含打印True */
			if(str.equals("com.ck.springautomatic.test.TestOne")){
				System.out.println(Boolean.TRUE);
			}
		}

		testOne.testPrintln();
	}
}

运行后打印如下结果:

结论:TestOne实例成功的加入到IOC容器中,并且可以通过@Autowired注解来注入实例。

 2.ImportSelector方式

加入的类需要实现实现ImportSelector接口

还是选用TestOne来做加入IOC的实例

先来看看ImportSelector接口的定义

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata importingClassMetadata);

    @Nullable
    default Predicate<String> getExclusionFilter() {
        return null;
    }
}
  • selectImport方法

        返回一个包含类全名(包括包路径)的数组,这些类会注入到IOC容器中,必须实现

  • getExclusionFilter方法

        返回一个谓词,用于从导入候选对象中排除类,该谓词可作用于当前选择器中的所有类

创建一个MySelector类,实现ImportSelector接口及其selectImport方法

public class MySelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.ck.springautomatic.test.TestOne"};
    }
}

还是使用Spring的ApplicationRunner来做测试,对@import做了改动

@Component
@Import(MySelector.class)
public class StartRun implements ApplicationRunner {

	@Autowired
	private TestOne testOne;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		/** 获取IOC容器管理的实例 */
		ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
		String [] strings = applicationContext.getBeanDefinitionNames();
		for(String str : strings){
			/** 实例列表中是否包含@Import中加入的类 ,如包含打印True */
			if(str.equals("com.ck.springautomatic.test.TestOne")){
				System.out.println(Boolean.TRUE);
			}
		}

		testOne.testPrintln();
	}
}

运行后打印如下结果: 

结论:TestOne实例通过SelectorImport成功的加入到IOC容器中,并且可以通过@Autowired注解来注入实例。

思路扩展

自己实现@Enable***注解来加载所需的类

1.创建两个注解EnableOneA和EnableOneB,使用@Import注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MySelector.class)
public @interface EnableOneA {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MySelector.class)
public @interface EnableOneB {
}

2.创建一个One接口,定义一个println(),OneA和OneB实现One接口并对println()进行不同的实现

public interface One {
    void println();
}
public class OneA implements One {
    @Override
    public void println() {
        System.out.println("装配的A!");
    }
}
public class OneB implements One {
    @Override
    public void println() {
        System.out.println("装配的B!");
    }
}

3.Myselector中增根据注解加载对应的实现类到IOC容器

public class MySelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        List<String> list = new ArrayList<>();
        Set<String> types = importingClassMetadata.getAnnotationTypes();
        if(types.contains(EnableOneA.class.getName())){
            list.add(OneA.class.getName());
        }
        if(types.contains(EnableOneB.class.getName())){
            list.add(OneB.class.getName());
        }
        return list.toArray(new String[list.size()]);
    }
}

4.在启动类上使用自定义注解@EnableOneA

@SpringBootApplication
@EnableOneA
public class SpringAutomaticApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringAutomaticApplication.class, args);
    }
}

5.还是用Spring的ApplicationRunner来做测试,期望执行的是OneA中的实现

@Component
public class StartRun implements ApplicationRunner {

	@Autowired
	private One one;

	@Override
	public void run(ApplicationArguments args) throws Exception {
		/** 获取IOC容器管理的实例 */
		ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
		String [] strings = applicationContext.getBeanDefinitionNames();
		for(String str : strings){
			/** 实例列表中是否包含@Import中加入的类 ,如包含打印True */
			if(str.equals("com.ck.springautomatic.test.TestOne")){
				System.out.println(Boolean.TRUE);
			}
		}

		one.println();
	}
}

6.启动,看输出结果

结论:通过自定义注解结合ImportSelector,成功的获取到了期望的OneA实例,很多@Enable**注解都是通过@Import和ImportSelector来实现(@EnableAsync、@EnableScheduling

  3.registerBeanDefinitions方式

通过BeanDefinitionRegistry来完成动态注册,这里不做过多解释,可以参考Mybatis的Mapper代理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值