spring注解开发——向IOC容器注册组件的几种方式

向IOC容器注册组件的几种方式

  • 第一种大家都常见,配置包扫描+类上注解(@Component, @Controller, @Service, @Repository, @Resource)

    也就是这样:

    // 配置类
    @Configuration
    @ComponentScan("com.example.demo.bean")
    public class AnnotationConfigTestImport {
    }
    
    // bean
    package com.example.demo.bean;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Dog {
        public Dog() {
            System.out.println("===> dog bean created...");
        }
    }
    

    这样凡是扫描的包下带有以上注解的都会被注册到IOC容器。但是缺点也显而易见:不能注册第三方包中的类

  • 第二种,使用@Bean,像这样:

    @Configuration
    // @ComponentScan("com.example.demo.bean")
    public class AnnotationConfigTestImport {
    
        @Bean
        public Cat cat() {
            return new Cat();
        }
    
        @Bean
        public Dog dog() {
            return new Dog();
        }
    }
    

    这种方式可以随意注册任何组件到容器,但是麻烦…每增加一个组件,我们都要在配置类里增加一个@Bean

  • 第三种,在配置类上使用@Import注解,我们先看看@Import源码:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Import {
    
    	/**
    	 * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
    	 * or regular component classes to import.
    	 */
    	Class<?>[] value();
    }
    

    可以看到@Import需要我们传一个Class数组,也就是我们要注册到容器的类。那我们就这样用:

    @Configuration
    // @ComponentScan("com.example.demo.bean")
    @Import({Cat.class, Dog.class})
    public class AnnotationConfigTestImport {
    
    }
    

    这种比上一种方式更加简洁一些,能少写一些代码

  • 第四种,使用ImportSelector接口,我们先看看什么是ImportSelector

    public interface ImportSelector {
    
    	/**
    	 * Select and return the names of which class(es) should be imported based on
    	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
    	 */
    	String[] selectImports(AnnotationMetadata importingClassMetadata);
    }
    

    接口里面就一个方法,从方法的注释上我们可以看到,返回一个包含类名的数组,这些类将被注册到容器。那我们写一个ImportSelector的实现类,返回我们要注册到容器的bean:

    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{"com.example.demo.bean.Windows"};
        }
    }
    

    然后在配置类中import我们写的selector即可,像这样:

    @Configuration
    @Import({Cat.class, Dog.class, MyImportSelector.class})
    public class AnnotationConfigTestImport {
    
    }
    
  • 第五种,使用ImportBeanDefinitionRegistrar接口,我们看看这个接口是啥:

    public interface ImportBeanDefinitionRegistrar {
    
    	/**
    	 * Register bean definitions as necessary based on the given annotation metadata of
    	 * the importing {@code @Configuration} class.
    	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
    	 * registered here, due to lifecycle constraints related to {@code @Configuration}
    	 * class processing.
    	 * @param importingClassMetadata annotation metadata of the importing class
    	 * @param registry current bean definition registry
    	 */
    	void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
    }
    

    我们看到这个接口有个registerBeanDefinitions()方法,方法的参数里有个BeanDefinitionRegistry,这个就是我们注册bean的类,我们可以使用这个类来注册我们的组件。现在我们来实现这个类:

    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Linux.class);
    
            registry.registerBeanDefinition("linux", rootBeanDefinition);
        }
    }
    

    然后在配置类import这个类即可向容器中注册名字为linux的bean。

    @Configuration
    // @ComponentScan("com.example.demo.bean")
    @Import({Cat.class, Dog.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class AnnotationConfigTestImport {
    }
    

以上就是我学习到的注册组件的几种方式,每种都简单的介绍了一下,实际上我们还可以做更多的操作,比如第四,第五种方式,在注册bean的时候我们还可以添加更多的逻辑,这个大家下去自行探索吧~

猜你喜欢

转载自blog.csdn.net/chenshufeng115/article/details/100061824