在前面的博客中我们讲解到使用方法级别注解(@Bean)和类级别注解(@Controller、@Component、@Service等)加包扫描的方式注入Beans,这些方式的最后一步都要加载配置类。这篇博客我们来讲解使用import方式手动注入Bean的三种方式。
这里为了方便,导入了Springboot模块自动扫描注解,从而避免加载配置类。
第一种方式:@Import注解注入Bean
代码示例:
import com.michael.annotation.demo.POJO.Person;
import com.michael.annotation.demo.POJO.Student;
import org.springframework.context.annotation.*;
@Configuration
@Import({Student.class})
public class MyConfig {
@Bean
public Person person(){
return new Person("Michael", 19);
}
}
这里@Import注解在被@Configuration注解的配置类上;注解的value为数组类型,说明可以使用这种方法注入多个Beans.
- 配置测试代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import static java.lang.System.out;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
for(String name : applicationContext.getBeanDefinitionNames()){
out.println(name);
}
}
}
- 输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
demoApplication
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
test
myConfig
personService
com.michael.annotation.demo.POJO.Student
person
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
propertySourcesPlaceholderConfigurer
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
org.springframework.boot.context.internalConfigurationPropertiesBinderFactory
org.springframework.boot.context.internalConfigurationPropertiesBinder
org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
taskExecutorBuilder
applicationTaskExecutor
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
taskSchedulerBuilder
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
org.springframework.aop.config.internalAutoProxyCreator
-
从输出可以发现,Student类型的Bean被注入到了容器里,并且ID为带全类名。
-
这里我们测试一下当@Import单独使用时,它是否能生效。首先注释MyConfig类的@Import,再创建MyConfig2类并注解@Import。
package com.michael.annotation.demo.configuration;
import com.michael.annotation.demo.POJO.Student;
import org.springframework.context.annotation.Import;
@Import({Student.class})
public class MyConfig2 {
}
- 输出:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
demoApplication
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
test
myConfig
personService
person
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
propertySourcesPlaceholderConfigurer
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
org.springframework.boot.context.internalConfigurationPropertiesBinderFactory
org.springframework.boot.context.internalConfigurationPropertiesBinder
org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
taskExecutorBuilder
applicationTaskExecutor
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
taskSchedulerBuilder
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
org.springframework.aop.config.internalAutoProxyCreator
- 输出没有Student类型的Bean,说明@Import注解需要和@Configuration结合使用才能生效。
实现ImportSelector接口的类并把对应Clazz实例当做value放入@Import
- 实现ImportSelector接口的类:
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//返回值为String数组类型,实际值应该是注入Bean类的全类名。
return new String[]{"com.michael.annotation.demo.POJO.Lecturer"};
}
}
我们可以看到实现的方法中还有一个对象参数annotationMetadata;可以从该对象中获取配置类的其他注解的信息,可用于做出其他业务逻辑的判断。实现方法的返回值为数组类型,实际值应该为注入Bean类的全类名。
- 把该类对应的运行时Clazz对象当做value放入@Import注解:
@Configuration
@Import({Student.class, MyImportSelector.class})
public class MyConfig {
@Bean
public Person person(){
return new Person("Michael", 19);
}
}
- 输出结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
demoApplication
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
test
myConfig
personService
com.michael.annotation.demo.POJO.Student
com.michael.annotation.demo.POJO.Lecturer
person
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
propertySourcesPlaceholderConfigurer
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
org.springframework.boot.context.internalConfigurationPropertiesBinderFactory
org.springframework.boot.context.internalConfigurationPropertiesBinder
org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
taskExecutorBuilder
applicationTaskExecutor
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
taskSchedulerBuilder
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
org.springframework.aop.config.internalAutoProxyCreator
- 输出显示,Lecture类的实例被注入到容器中,Bean的ID为类的全类名。
实现ImportBeanDefinitionRegistrar接口的类并把对应Clazz实例当做value放入@Import
- 实现ImportBeanDefinitionRegistrar接口的类:
import com.michael.annotation.demo.POJO.Class;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements org.springframework.context.annotation.ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//可以从importingClassMetadata和registry对象获取一些上下文信息进行其他业务逻辑的判断
boolean b1 = registry.containsBeanDefinition("com.michael.annotation.demo.POJO.Student");
boolean b2 = registry.containsBeanDefinition("com.michael.annotation.demo.POJO.Lecturer");
if(b1 && b2){
registry.registerBeanDefinition("Class", new RootBeanDefinition(Class.class));
}
}
}
我们可以从重写方法的importingClassMetadata和registry对象参数中获s取其他上下文信息进行其他业务逻辑的判断;这里做了一个简单的业务判断,如果容器中存在Student和Lecture实例就注入Class类型的Bean。其实这里还有其他方式注入Bean,可以通过观察对象参数回溯到源代码,举一反三。
- 把该类对应的运行时Clazz对象当做value放入@Import注解:
import com.michael.annotation.demo.POJO.Person;
import com.michael.annotation.demo.POJO.Student;
import org.springframework.context.annotation.*;
@Configuration
@Import({Student.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MyConfig {
@Bean
public Person person(){
return new Person("Michael", 19);
}
}
- 输出结果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
demoApplication
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
test
myConfig
personService
com.michael.annotation.demo.POJO.Student
com.michael.annotation.demo.POJO.Lecturer
person
Class
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
propertySourcesPlaceholderConfigurer
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
org.springframework.boot.context.internalConfigurationPropertiesBinderFactory
org.springframework.boot.context.internalConfigurationPropertiesBinder
org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
taskExecutorBuilder
applicationTaskExecutor
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
taskSchedulerBuilder
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
org.springframework.aop.config.internalAutoProxyCreator
- 观察输出,可以看到ID为"Class"实例被注入到了容器中。