SpringBoot向容器註冊bean的方法詳解

簡介

本文用示例介紹SpringBoot如何向容器註冊bean(即:將對象加入容器)。

法1:@Component

(@Controller/@Service/@Repository也可以,因為它裡邊包含@Component)

默認是加載和Application類所在同一個目錄下的所有類,包括所有子目錄下的類。

當啟動類和@Component分開時,如果啟動類在某個包下,需要在啟動類中增加註解@ComponentScan,配置需要掃描的包名。例如:

@SpringBootApplication(scanBasePackages="com.test.chapter4")

此註解其實是@ComponentScan的basePackages,通過查看scanBasePackages即可得知。

@SpringBootApplication隻會掃描@SpringBootApplication註解標記類包下及其子包的類,將這些類納入到spring容器,隻要類有@Component註解即可。

有的註解的定義中已加入@Component,所以這些註解也會被掃描到:@Controller,@Service,@Configuration,@Bean

@[email protected][email protected]

DemoConfig在掃描路徑之內

@Configuration
@ComponentScan(basePackages = { "com.example.demo.mybeans" })
public class DemoConfig {
}

 MyBean1在com.example.demo.mybeans下

@Component
public class MyBean1{
}

法2:@[email protected]

使用場景:將沒有Component等註解的類導入。例如:第三方包裡面的組件、將其他jar包中的類。

public class User {
    //@Value("Tom")
    public String username;
 
    public User(String s) {
        this.username = s;
    }
}
 
@Configuration
public class ImportConfig {
    @Bean
    public User user(){
        return new User("Lily");
    }
}
 
@RestController
public class ImportDemoController {
    @Autowired
    private User user;
 
    @RequestMapping("/importDemo")
    public String demo() throws Exception {
        String s = user.username;
        return "[email protected] " + s;
    }
}

法3:@Import等

簡介

@Import(要導入到容器中的組件);容器會自動註冊這個組件,id默認是全類名。(@Import是Spring的註解。)

ImportSelector:返回需要導入的組件的全類名數組;

ImportBeanDefinitionRegistrar:手動註冊bean到容器中

@Import方式

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({ImportDemoConfig.class})
public @interface EnableImportDemo {
}
 
public class ImportDemoConfig{
    @Bean
    public User user(){
        return new User("Lily");
    }
}
 
@EnableImportDemo
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
 
@RestController
public class ImportDemoController {
    @Autowired
    private User user;
 
    @RequestMapping("/importDemo")
    public String demo() {
        String s = user.getName();
        return "user.getName():" + s;
    }
}

ImportSelector方式

//自定義邏輯返回需要導入的組件
public class MyImportSelector implements ImportSelector {
 
    //返回值,就是到導入到容器中的組件全類名
    //AnnotationMetadata:當前標註@Import註解的類的所有註解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //當前類的所有註解
        Set<String> annotationTypes = importingClassMetadata.getAnnotationTypes();
        System.out.println("當前配置類的註解信息:"+annotationTypes);
        //註意不能返回null,不然會報NullPointException
        return new String[]{"com.paopaoedu.springboot.bean.user01","com.paopaoedu.springboot.bean.user02"};
    }
}
 
public class User01 {
	public String username;
 
    public User01() {
        System.out.println("user01...constructor");
    }
}
 
public class User02 {
    public String username;
 
    public User02() {
        System.out.println("user02...constructor");
    }
}
 
@Configuration
@Import({ImportDemo.class, MyImportSelector.class})
public class ImportConfig {
    @Bean
    public User user(){
        return new User("Lily");
    }
}
 
@RestController
public class ImportDemoController {
    @Autowired
    private User user;
 
    @Autowired
    private ImportDemo importDemo;
 
    @Autowired
    private User01 user01;
 
    @RequestMapping("/importDemo")
    public String demo() throws Exception {
        importDemo.doSomething();
        user01.username = "user01";
        String s = user.username;
        String s1 = user01.username;
 
        return "[email protected] " + s + " " + s1;
    }
}

ImportBeanDefinitionRegistrar方式

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * AnnotationMetadata:當前類的註解信息
     * BeanDefinitionRegistry:BeanDefinition註冊類;
     * 		把所有需要添加到容器中的bean;調用
     * 		BeanDefinitionRegistry.registerBeanDefinition手工註冊進來
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                   BeanDefinitionRegistry registry) {
 
        boolean definition = registry.containsBeanDefinition("com.paopaoedu.springboot.bean.User01");
        boolean definition2 = registry.containsBeanDefinition("com.paopaoedu.springboot.bean.User02");
        if(definition && definition2){
            //指定Bean定義信息作用域都可以在這裡定義;(Bean的類型,Bean。。。)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(User03.class);
            //註冊一個Bean,指定bean名
            registry.registerBeanDefinition("User03", beanDefinition);
        }
    }
}
public class User03 {
    public String username;
 
    public User03() {
        System.out.println("user03...constructor");
    }
}

使用上和前面的類似就不舉例瞭。

法4:FactoryBean

默認獲取到的是工廠bean調用getObject創建的對象。

要獲取工廠Bean本身,我們需要給id前面加一個&。例如:&xxxFactoryBean 註意類名是X,這裡就是小寫的x

public class UserFactoryBean implements FactoryBean<User04> {
    @Override
    public User04 getObject() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("UserFactoryBean...getObject...");
        return new User04("User04");
    }
 
    @Override
    public Class<?> getObjectType() {
        // TODO Auto-generated method stub
        return User04.class;
    }
 
    //是否單例?
    //true:這個bean是單實例,在容器中保存一份
    //false:多實例,每次獲取都會創建一個新的bean;
    @Override
    public boolean isSingleton() {
        return true;
    }
}
 
public class User04 {
    public String username;
    public User04(String s) {
        String nowtime= DateUtil.now();
        username=s+" "+nowtime;
    }
}
 
@Configuration
@Import({ImportDemo.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class ImportConfig {
 
    // 要獲取工廠Bean本身,需要給id前面加一個&,&userFactoryBean
    @Bean
    public UserFactoryBean userFactoryBean(){
        return new UserFactoryBean();
    }
 
    @Bean
    public User user(){
        return new User("Lily");
    }
}
 
@RestController
public class ImportDemoController {
    @Autowired
    private User user;
 
    @Autowired
    private ImportDemo importDemo;
 
    @Autowired
    private User01 user01;
 
    @Autowired
    private UserFactoryBean userFactoryBean;
 
    @RequestMapping("/importDemo")
    public String demo() throws Exception {
        importDemo.doSomething();
        user01.username = "user01";
        String s = user.username;
        String s1 = user01.username;
        String s4 = userFactoryBean.getObject().username;
 
        return "[email protected] " + s + " " + s1 + " " + s4;
    }
}
 
@SpringBootApplication
public class SpringBootLearningApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringBootLearningApplication.class, args);
 
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext("com.paopaoedu.springboot.config");
        ImportDemo importDemo = context.getBean(ImportDemo.class);
        importDemo.doSomething();
        printClassName(context);
 
        Object bean1 = context.getBean("userFactoryBean");
        Object bean2 = context.getBean("userFactoryBean");
        System.out.println(bean1 == bean2);
    }
 
    private static void printClassName(AnnotationConfigApplicationContext annotationConfigApplicationContext){
        String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
        for (int i = 0; i < beanDefinitionNames.length; i++) {
            System.out.println("匹配的類"+beanDefinitionNames[i]);
        }
    }
}

測試結果

以上就是SpringBoot向容器註冊bean的方法詳解的詳細內容,更多關於SpringBoot註冊bean的資料請關註WalkonNet其它相關文章!

推薦閱讀: