Spring注解-(八)@Import的用法

本文最后更新于:June 14, 2022 pm

Spring 是目前主流的 Java Web 开发框架,是 Java 世界最为成功的框架。Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力。Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。

目录

导入普通类

目标类:(只是一个普通的类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.SpringTestAnnotation.TestValue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
public class Per {

public void show(){
System.out.println("Per show");
}

}

配置类中进行导入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.SpringTestAnnotation;

import com.SpringTestAnnotation.TestValue.OrderS;
import com.SpringTestAnnotation.TestValue.OurAnno;
import com.SpringTestAnnotation.TestValue.Per;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
@ComponentScan(value = "com.SpringTestAnnotation")
@Import(Per.class) //导入目标类
public class TestConfig {

}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.SpringTestAnnotation;

import com.SpringTestAnnotation.TestValue.OrderS;
import com.SpringTestAnnotation.TestValue.Per;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
public class TestAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
Per per = applicationContext.getBean(Per.class);
per.show();
}
}

需要说明的一点,使用@Import导入的类的Bean名称不是类名的小驼峰(类首字母小写),也就是说不是使用注解时的名称。如类名为OrderS,使用注解为orderS;而使用@Import就不再是orderS了,内部会自动生成一个名称。所以这里并没有直接使用名称进行获取,而是通过class获取的。

输出结果:

1
Per show

如果在配置类中没有导入目标类,则会报错如下:

1
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.SpringTestAnnotation.TestValue.Per' available

📢注意:使用@Import导入的类并不是一个普通的Bean,而是一个配置Bean。在配置Bean中可以使用@Bean定义其他的Bean,以及可以在配置Bean中使用@ComponentScan。

ImportSelector

个人理解:可以动态批量注入Bean。

目标类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.SpringTestAnnotation.TestValue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
public class Per {

public void show(){
System.out.println("Per show");
}

}

实现接口ImportSelector:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.SpringTestAnnotation.TestValue;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;

/**
* @Author DragonOne
* @Date 2022/6/10 21:56
* @墨水记忆 www.tothefor.com
*/
//@Component //使用Component只是一个普通的Bean,而这里需要的是一个配置Bean
public class OrderS implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 自定义逻辑
// ....
return new String[]{Per.class.getName()};
}
}

实现接口的类必须成为一个配置Bean,所以使用@Import将其设置为一个配置Bean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.SpringTestAnnotation;

import com.SpringTestAnnotation.TestValue.OrderS;
import com.SpringTestAnnotation.TestValue.OurAnno;
import com.SpringTestAnnotation.TestValue.Per;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
@ComponentScan(value = "com.SpringTestAnnotation")
@Import(OrderS.class)
public class TestConfig {

}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.SpringTestAnnotation;

import com.SpringTestAnnotation.TestValue.OrderS;
import com.SpringTestAnnotation.TestValue.Per;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
public class TestAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
Per per = applicationContext.getBean(Per.class);
per.show();
}
}

获取Bean也不能使用名称进行获取,而是通过class获取。

输出结果:

1
Per show

如果不在配置类中使用@Import,而是直接使用@Component,则会报错如下:

1
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.SpringTestAnnotation.TestValue.Per' available

ImportBeanDefinitionRegistrar

和上面的接口是一样的功能。

其他代码同上,只是修改以下实现的接口。上面接口的实现改成新接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.SpringTestAnnotation.TestValue;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;

/**
* @Author DragonOne
* @Date 2022/6/10 21:56
* @墨水记忆 www.tothefor.com
*/
public class OrderS implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {

BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
beanDefinition.setBeanClass(Per.class);
registry.registerBeanDefinition("per123",beanDefinition); // 自定义Bean的名称

}
}

测试输出结果:

1
Per show

然后再通过名称进行获取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.SpringTestAnnotation;

import com.SpringTestAnnotation.TestValue.OrderS;
import com.SpringTestAnnotation.TestValue.Per;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
public class TestAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
Per per = applicationContext.getBean("per123",Per.class);
per.show();
}
}

其中的per123为实现接口时的自定义Bean名称。输出结果同上。