spring註解驅動開發-(5) 向Spring容器中註冊組件的方法

1. 包掃描+組件標註註解

@ComponentScan+ @Controller + @Service + @Repositoryjava

2. @Bean註解導入

導入第三方包裏的組件spring

3. @Import快速導入

幾個實體類的聲明:shell

package com.niewj.bean;

public class PojoBean {
    public PojoBean() {
        System.out.println("PojoBean[無註解java類] 初始化~~~");
    }
}
package com.niewj.bean;

public class PojoBean2 {
    public PojoBean2(){
        System.out.println("PojoBean2[無註解java類] 初始化~~~");
    }
}
package com.niewj.bean;

public class PojoBean3 {
    public PojoBean3(){
        System.out.println("PojoBean3[無註解java類] 初始化~~~");
    }
}
package com.niewj.bean;

public class Pojo4 {
    public Pojo4(){
        System.out.println("Pojo4[無註解java類] 初始化~~~");
    }
}
package com.niewj.bean;

public class Pojo5 {
    public Pojo5(){
        System.out.println("Pojo5[無註解java類] 初始化~~~");
    }
}

(1) @Import導入單個

package com.niewj.config;

import com.niewj.bean.PojoBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(PojoBean.class) // 這裏
public class ImportTestConfig {
}
private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
    AnnotationConfigApplicationContext ctx =  new AnnotationConfigApplicationContext(clazz);
    Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
    return ctx;
}

@Test
public void testImport(){
    // PojoBean*.java並沒有註解類, 可是會初始化納入spring容器管理! -> @Import的做用!
    ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}

output:數組

PojoBean[無註解java類] 初始化~~~
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
importTestConfig
com.niewj.bean.PojoBean

能夠看到 PojoBean 的初始化和bean id的展現!springboot

(2) @Import導入多個(數組)

普通Javabean並無任何註解的:ide

package com.niewj.config;

import com.niewj.bean.PojoBean;
import com.niewj.bean.PojoBean2;
import com.niewj.bean.PojoBean3;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
//@Import(PojoBean.class)
@Import({PojoBean.class, PojoBean2.class, PojoBean3.class}) // 這裏
public class ImportTestConfig {
}

測試:測試

private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
    AnnotationConfigApplicationContext ctx =  new AnnotationConfigApplicationContext(clazz);
    Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
    return ctx;
}

@Test
public void testImport(){
    // PojoBean*.java並沒有註解類, 可是會初始化納入spring容器管理! -> @Import的做用!
    ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}

output: 能夠看到這三個無註解的普通bean也被容器管理和初始化了!code

PojoBean[無註解java類] 初始化~~~
PojoBean2[無註解java類] 初始化~~~
PojoBean3[無註解java類] 初始化~~~
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
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3

(3) @ImportSelector接口

@ImportSelector接口的實現類, 能夠放入@Import中使用:對象

@Import是列出全部; @ImportSelector是返回一個 class name的字符串的數組, 能夠理解爲@Import的簡化版(方便使用)接口

package com.niewj.config;

import com.niewj.bean.PojoBean;
import com.niewj.bean.PojoBean2;
import com.niewj.bean.PojoBean3;
import com.niewj.condition.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
//@Import(PojoBean.class)
//@Import({PojoBean.class, PojoBean2.class, PojoBean3.class})
@Import({PojoBean.class, PojoBean2.class, PojoBean3.class, MyImportSelector.class}) // 這裏
public class ImportTestConfig {
}

MyImportSelector:

package com.niewj.condition;

import com.niewj.bean.Pojo4;
import com.niewj.bean.Pojo5;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

import java.util.ArrayList;
import java.util.List;

public class MyImportSelector implements ImportSelector {

    /**
     * 返回的數組中的類名, 也會做爲加入容器管理的bean
     * @param importingClassMetadata 能夠獲取到當前類的全部註解信息!
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        List<String> classNameList = new ArrayList<>();

        // 能夠假設Pojo4/Pojo5的類名都讀取字配置文件, 好比 spring.factories-->相似springboot源碼
        classNameList.add(Pojo4.class.getName());
        classNameList.add(Pojo5.class.getName());

        return classNameList.toArray(new String[0]);
    }
}

testcase:

private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
    AnnotationConfigApplicationContext ctx =  new AnnotationConfigApplicationContext(clazz);
    Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
    return ctx;
}

@Test
public void testImport(){
    // PojoBean*.java並沒有註解類, 可是會初始化納入spring容器管理! -> @Import的做用!
    ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}

output: 可見: PojoBean/PojoBean2/PojoBean3都初始化了; 並且 ImportSelector中加入數組的 Pojo4/Pojo5也初始化了!

PojoBean[無註解java類] 初始化~~~
PojoBean2[無註解java類] 初始化~~~
PojoBean3[無註解java類] 初始化~~~
Pojo4[無註解java類] 初始化~~~
Pojo5[無註解java類] 初始化~~~
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
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3
com.niewj.bean.Pojo4
com.niewj.bean.Pojo5

(4). ImportBeanDefinitionRegistrar

能夠結合已有beanDefinition信息!

package com.niewj.config;

import com.niewj.bean.PojoBean;
import com.niewj.bean.PojoBean2;
import com.niewj.bean.PojoBean3;
import com.niewj.condition.MyImportBeanDefRegistrar;
import com.niewj.condition.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
//@Import(PojoBean.class)
//@Import({PojoBean.class, PojoBean2.class, PojoBean3.class})
@Import({PojoBean.class, PojoBean2.class, PojoBean3.class, MyImportSelector.class, MyImportBeanDefRegistrar.class})
public class ImportTestConfig {
}

MyImportBeanDefRegistrar:

package com.niewj.condition;

import com.niewj.bean.Pojo4;
import com.niewj.bean.Pojo5;
import com.niewj.bean.PojoWhenHasPojo4AndPojo5;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefRegistrar implements ImportBeanDefinitionRegistrar {

    /** 能夠獲取容器中已有 BeanDefinition 信息來作一些判斷; 
     * 好比, 若是有這兩個類, 也加入類 PojoWhenHasPojo4AndPojo5
     * @param importingClassMetadata 能夠獲取到當前類(掃描到的類)的全部註解信息
     * @param registry beanDefinition的註冊接口
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean hasPojo5 = registry.containsBeanDefinition(Pojo5.class.getName());
        boolean hasPojo4 = registry.containsBeanDefinition(Pojo4.class.getName());
        
        if(hasPojo4 && hasPojo5){
            RootBeanDefinition beanDefinition = new RootBeanDefinition(PojoWhenHasPojo4AndPojo5.class);
            registry.registerBeanDefinition("pojoWhenHasPojo4AndPojo5", beanDefinition);
        }
    }
}

測試:

private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
    AnnotationConfigApplicationContext ctx =  new AnnotationConfigApplicationContext(clazz);
    Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
    return ctx;
}

@Test
public void testImport(){
    // PojoBean*.java並沒有註解類, 可是會初始化納入spring容器管理! -> @Import的做用!
    ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
}

output: 能夠看到 PojoWhenHasPojo4AndPojo5 的初始化!

PojoBean[無註解java類] 初始化~~~
PojoBean2[無註解java類] 初始化~~~
PojoBean3[無註解java類] 初始化~~~
Pojo4[無註解java類] 初始化~~~
Pojo5[無註解java類] 初始化~~~
PojoWhenHasPojo4AndPojo5[無註解java類] 初始化~~~
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
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3
com.niewj.bean.Pojo4
com.niewj.bean.Pojo5
pojoWhenHasPojo4AndPojo5

4. Spring的FactoryBean<T>接口(工廠Bean)

  • getObject() 獲取要生產的對象
  • getObjectType() 獲取要生產的對象的類型
  • isSingleton() 定義是單例仍是多例

    注意: 經過 ctx.getBean("beanId") 調用, 獲得的是 getObject()方法返回的對象的實際內容;

    經過ctx.getBean("&beanId")調用, 獲得的纔是實際的FactoryBean對象

package com.niewj.bean;

public class Pojo7 {
    public Pojo7(){
        System.out.println("Pojo7[無註解java類] 初始化~~~");
    }
}
package com.niewj.bean;

import org.springframework.beans.factory.FactoryBean;

public class Pojo7FactoryBean implements FactoryBean<Pojo7> {
    @Override
    public Pojo7 getObject() throws Exception {
        System.out.println("Pojo7FactoryBean---FactoryBean---初始化");
        return new Pojo7();
    }

    @Override
    public Class<?> getObjectType() {
        return Pojo7.class;
    }
    
    @Override
    public boolean isSingleton() {
        return false;
    }
}
private AnnotationConfigApplicationContext printAnnoBeans(Class clazz) {
        AnnotationConfigApplicationContext ctx =  new AnnotationConfigApplicationContext(clazz);
        Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
        return ctx;
    }

    @Test
    public void testImport(){
        // PojoBean*.java並沒有註解類, 可是會初始化納入spring容器管理! -> @Import的做用!
        ApplicationContext ctx = printAnnoBeans(ImportTestConfig.class);
        Pojo7 bean1 = ctx.getBean("pojo7", Pojo7.class);
        System.out.println(bean1);
        Pojo7FactoryBean bean2 = ctx.getBean("&pojo7", Pojo7FactoryBean.class);
        System.out.println(bean2);
    }

output: 看最後兩行: 說明了 FactoryBean的特徵: &beanId獲得是 FactoryBean; beanId獲得是 getObject()返回的實際Bean!

PojoBean[無註解java類] 初始化~~~
PojoBean2[無註解java類] 初始化~~~
PojoBean3[無註解java類] 初始化~~~
Pojo4[無註解java類] 初始化~~~
Pojo5[無註解java類] 初始化~~~
PojoWhenHasPojo4AndPojo5[無註解java類] 初始化~~~
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
importTestConfig
com.niewj.bean.PojoBean
com.niewj.bean.PojoBean2
com.niewj.bean.PojoBean3
com.niewj.bean.Pojo4
com.niewj.bean.Pojo5
pojo7
pojoWhenHasPojo4AndPojo5
Pojo7FactoryBean---FactoryBean---初始化
Pojo7[無註解java類] 初始化~~~
com.niewj.bean.Pojo7@2bbf180e
com.niewj.bean.Pojo7FactoryBean@163e4e87

小結

向spring容器中註冊組件有四種方式:

  1. @ComponentScan+註解 @Controller/@Service/@Response;
  2. @Bean註解導入;
  3. @Import註解導入普通bean;
  4. 實現spring的FactoryBean<T>接口, 經過@Bean加入容器;

@Import導入普通bean也有四種方式:

  1. @Import(單個bean)
  2. @Import({多個bean-1, 多個bean-2, ...}
  3. @Import({bean1.class, bean2.class, ImportSelector.class})
  4. @Import({bean1.class, bean2.class, ImportSelector.class, ImportBeanDefinitionRegistrar.class})
相關文章
相關標籤/搜索