學過Spring應該都知道Spring最核心的功能之一就是可以幫我們管理Bean。當然,Bean不是無中生有的,需要我們按照Spring的規則做配置,Spring容器中才會有。那么到底有多少種配置方式可以往容器注入Bean呢,今天做個簡單總結。
一 <bean id="" class=""/>
這個應該是最最基礎的了,基本上學Spring都是從這種方式開始的。在Spring配置文件中的每一個bean標簽都對應一個bean。代碼如下:
public class Student {
private Integer id;
private String name;
public Student() {
}
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void study(){
System.out.println("今天不學習,明天變垃圾");
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
<bean id="xiaoming" class="com.study.spring.bean.Student">
<property name="id" value="007"></property>
<property name="name" value="xiaoming"></property>
</bean>
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext=
new ClassPathXmlApplicationContext("applicationContext.xml");
Student xiaoming = applicationContext.getBean("xiaoming", Student.class);
System.out.println(xiaoming);
}
}
二 <bean id="" factory-bean="" factory-method=""/>
通過實例工廠方法創建
public class StudentFactoryBean {
public Student instance(){
return new Student();
}
}
<bean id="studentFactoryBean" class="com.study.spring.config.StudentFactoryBean"/>
<bean id="student" factory-bean="studentFactoryBean" factory-method="instance"/>
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext=
new ClassPathXmlApplicationContext("applicationContext.xml");
Student student=classPathXmlApplicationContext.getBean(Student.class);
System.out.println(student);
}
}
三 <bean id="" class="" factory-method=""/>
通過靜態工廠方法創建
public class StaticStudentFactoryBean {
public static Student getInstance(){
return new Student();
}
}
<bean id="student" class="com.study.spring.config.StaticStudentFactoryBean" factory-method="getInstance"/>
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext=
new ClassPathXmlApplicationContext("applicationContext.xml");
Student student=classPathXmlApplicationContext.getBean(Student.class);
System.out.println(student);
}
}
四 <context:component-scan/> + @Component
在context:component-scan標簽掃描范圍內且並未排除的,標了Component(Controller,Service,Repository)注解都可以成為Bean。代碼如下。
<context:component-scan base-package="com.study.spring"/>
@Component
public class Student {
。。。
}
五 @Configuration + @Bean
隨着純注解編程越來越普及,這種方式用得相當多,很多優秀的開源框架都在用
@Configuration
public class MyConfig {
@Bean
public Student student(){
return new Student(007,"xiaoming");
}
}
六 @Component + @ComponentScan
@Component
public class Student {
。。。
}
@ComponentScan(basePackages = "com.study.spring.*")
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(Test.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
七 @Import直接注入一個bean
我們自己用得不多,但是在基於springboot的框架中被大量使用,如springcloud系列
@Configuration
@Import(Student.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
八 ImportSelector + @Import
ImportSelector 的selectImports方法返回的是字符竄數組,所以可以一次導入多個bean
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.study.spring.bean.Student"};
}
}
@Configuration
@Import(MyImportSelector.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
九 DeferredImportSelector + @Import
public class MyDeferredSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{Student.class.getName()};
}
}
@Configuration
@Import(MyDeferredSelector.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
提示:
1. DeferredImportSelector是ImportSelector的擴展;
2. ImportSelector實例的selectImports方法的執行時機,是在@Configguration注解中的其他邏輯被處理之前,所謂的其他邏輯,包括對@ImportResource、@Bean這些注解的處理;
3. DeferredImportSelector實例的selectImports方法的執行時機,是在@Configguration注解中的其他邏輯被處理完畢之后,所謂的其他邏輯,包括對@ImportResource、@Bean這些注解的處理;
4. DeferredImportSelector的實現類可以用Order注解,或者實現Ordered接口來對selectImports的執行順序排序;
十 ImportBeanDefinitionRegistrar + @Import
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AbstractBeanDefinition abstractBeanDefinition=
BeanDefinitionBuilder.rootBeanDefinition(Student.class).getBeanDefinition();
registry.registerBeanDefinition("student",abstractBeanDefinition);
}
}
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
十一 FactoryBean 接口
public class StudentFactoryBean implements FactoryBean<Student> {
@Override
public Student getObject() throws Exception {
return new Student();
}
@Override
public Class<?> getObjectType() {
return Student.class;
}
@Override
public boolean isSingleton() {
return true;//返回true,表示返回的Student是單例的,每次獲取的是同一個對象,返回false,每次獲取的不是同一個對象。
}
}
@Configuration
public class MyConfig {
@Bean
public StudentFactoryBean studentFactoryBean(){
return new StudentFactoryBean();
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
十二 BeanDefinitionRegistryPostProcessor 接口
這是利用了bean定義注冊器后置處理器,后置處理器這個概念在spring中無處不在
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry)
throws BeansException {
AbstractBeanDefinition abstractBeanDefinition=
BeanDefinitionBuilder.rootBeanDefinition(Student.class).getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition("student",abstractBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
throws BeansException {
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext();
MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor=
new MyBeanDefinitionRegistryPostProcessor();
applicationContext.addBeanFactoryPostProcessor(myBeanDefinitionRegistryPostProcessor);
applicationContext.refresh();
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
學無止境,讓學習成為一種習慣。
本人水平有限,有不對的地方請指教,謝謝。