Spring中组件添加的方式
本文所介绍的所有组件添加的方式都是基于注解的方式。
准备工作
- 需要一个spring项目
添加组件的方式
结合@Configuration和@Bean注解
在@Configuration注解的配置类中,通过@Bean注解方法,可以将方法返回的对象添加到容器中。下面介绍详细的步骤。
- 首先我们定义了一个用户类,作为要注入到容器的目标
public class User {
private String id;
private String username;
private Integer age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", username='" + username + '\'' +
", age=" + age +
'}';
}
}
- 然后我们定义一个配置类
BeanConfig
,这个配置类使用注解@Configuration
进行了配置,表示了这个类是作为Spring的配置类。BeanConfig
里面有一个方法user
,返回结果就是我们步骤1中定义的类User,而且这个方法被注解@Bean进行了注解。
@Configuration
public class BeanConfig {
@Bean
public User user(){
return new User();
}
}
- 我们定义一个测试类,测试下容器中是否可以获取到注入的组件。
public class BeanTest {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
}
}
- 输出结果中可以看到,已经获取到了user组件
User{id='null', username='null', age=null}
结合@ComponentScan和@Controller、@Service、@Repository、@Component
- 给配置类
BeanConfig
上加上注解@ComponentScan
,并设置值为com.wangguitang.freedom.interview.spring.bean
,表示要扫描的包的位置。
@Configuration
@ComponentScan("com.wangguitang.freedom.interview.spring.bean")
public class BeanConfig {
@Bean
public User user(){
return new User();
}
}
- 在包
com.wangguitang.freedom.interview.spring.bean
下增加一个类UserService
,这个类使用了@Service
注解,结合扫描,意味着这个类要被作为组件加入到容器中。
@Service
public class UserService {
public void sayHello(String name) {
System.out.println("Hello " + name);
}
}
- 我们从容器中获取到
UserService
这个组件,并掉用sayHello
方法,输出结果证明我们成果地将UserSerice
加入到容器中,并成功获取。
public class BeanTest {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
UserService userService = applicationContext.getBean(UserService.class);
userService.sayHello("Spring");
}
}
使用@Import导入
这种方式在Spring boot中被大量使用。很多@EnableXXX
注解的功能都是通过@Import
往容器里导出组件实现的。使用@Import
导入组件,又有三种方式,下面分别介绍。
直接导入组件
- 我们定义了一个类
UserDao
,我们准备将这个类导入到容器中作为组件。我们没有在代码上加上@Component之类的注解,让自动扫描去自动将此类加入到容器中,模仿这是一个外部Jar包里面一个类。
public class UserDao {
public void getName(){
System.out.println("My name is Spring");
}
}
- 还在
BeanConfig
这个配置类中,我们加入了一行@Import(UserDao.class)
,表示往容器中导入UserDao
这个类。
@Configuration
@ComponentScan("com.wangguitang.freedom.interview.spring.bean")
@Import(UserDao.class)
public class BeanConfig {
@Bean
public User user(){
return new User();
}
}
- 我们依旧在测试类
BeanTest
中的测试代码中尝试获取UserDao
,发现是可以成功的。
public class BeanTest {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
UserService userService = applicationContext.getBean(UserService.class);
userService.sayHello("Spring");
UserDao userDao = applicationContext.getBean(UserDao.class);
userDao.getName();
}
}
实现接口ImportSelector
通过查看@Import
的注解,我们可以发现,我们也可以实现接口ImportSelector
,通过实现方法selectImports
,返回要导入类的全限定名,也可以实现导入组件,这种方式也是Spring Boot的自动配置使用的方式。下面我们试试。
- 我们编写了一个类
UserController
,将此类作为我们要导入到容器中的类。
public class UserController {
public void query(){
System.out.println("UserController#query");
}
}
- 我们编写了一个类
MyImportSelector
,这个类实现了ImportSelector
接口,并实现了方法selectImports
,返回一个包含了UserController
全限定名的String数组。
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.wangguitang.freedom.interview.spring.bean.UserController"};
}
}
- 还是在配置类
BeanConfig
上,@Import
传入的值是支持数组的,我们将MyImportSelector
也加入。
@Configuration
@ComponentScan("com.wangguitang.freedom.interview.spring.bean")
@Import({
UserDao.class,
MyImportSelector.class
})
public class BeanConfig {
@Bean
public User user(){
return new User();
}
}
- 在测试类
BeanTest
中加入获取UserController
类的代码进行测试,结果是UserController
成功加入到了容器中。
public class BeanTest {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
UserService userService = applicationContext.getBean(UserService.class);
userService.sayHello("Spring");
UserDao userDao = applicationContext.getBean(UserDao.class);
userDao.getName();
UserController userController = applicationContext.getBean(UserController.class);
userController.query();
}
}
输出:
User{id='null', username='null', age=null}
Hello Spring
My name is Spring
UserController#query
实现ImportBeanDefinitionRegistrar接口
通过查看@Import
注解,发现还可以实现ImportBeanDefinitionRegistrar
接口来注入组件。
- 我们编写一个类
BookService
,作为我们要注入到容器中的组件。
public class BookService {
public void getBookName(){
System.out.println("Book name is A");
}
}
- 我们编写一个类
MyImportBeanDefinitionRegistrar
,此类实现了接口ImportBeanDefinitionRegistrar
,注册了一个BookService
类的Bean定义。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookService.class).getBeanDefinition();
registry.registerBeanDefinition("bookService", beanDefinition);
}
}
- 还是修改我们的配置类
Bean Config
,给@Import
中加入类MyImportBeanDefinitionRegistrar
@Configuration
@ComponentScan("com.wangguitang.freedom.interview.spring.bean")
@Import({
UserDao.class,
MyImportSelector.class,
MyImportBeanDefinitionRegistrar.class
})
public class BeanConfig {
@Bean
public User user() {
return new User();
}
}
- 我们在测试类中尝试获取
BookService
,结果是可以成功获取到此组件。
public class BeanTest {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
User user = applicationContext.getBean(User.class);
System.out.println(user);
UserService userService = applicationContext.getBean(UserService.class);
userService.sayHello("Spring");
UserDao userDao = applicationContext.getBean(UserDao.class);
userDao.getName();
UserController userController = applicationContext.getBean(UserController.class);
userController.query();
BookService bookService = applicationContext.getBean(BookService.class);
bookService.getBookName();
}
}
输出结果:
User{id='null', username='null', age=null}
Hello Spring
My name is Spring
UserController#query
Book name is A
总结
我们介绍了五种往容器中添加组件的办法,每种方法各有各自的使用场景。在编写我们自己的代码时,可以最经常使用的是@ComponentScan
加上@Component
等注解的方式。在添加第三方的配置类时,可能使用比较多的是使用@Bean
注解。如果想导入一个配置类,或者使用编码的方式导入组件时,使用@Import
注解是一种不错的方式。