使用场景
主要是 将很多Bean组合起来,就像形成了一个模块,原先使用@Bean
或@Component
或<bean>
的方式向Spring容器注入bean,所有的bean之间没有明显的关联。如果说遇到某一个场景:我需要依赖大量的bean,有没有一种方式使用一个注解就将所需要的所有bean都导入呢?这就是:模块装配。
模块装配的优点在于: 可以将执行特定功能的bean打包成一个整体,哪里需要时,使用一个注解即可将这个整体注入。
例子:我们定义四个动物类,并且尝试使用“模块装配”的方式实现:使用一个注解装四个bean
实现自定模块装配的步骤
定义一个注解
定义注解的意思就是说,我们是通过这个注解来做模块装配的。
定义一个EnableAnimal
注解,以Enable起名是有讲究的,因为看到很多以Enable开头的注解就是使用了模块装配这个技术。
@Documented
:注解(@EnableAnimal
)被@Documented
标注了,那么被@EnableAnimal
修饰的类,生成doc文档时,会在文档个中显示@EnableAnimal
。@Retention
:所注解的注解保留多久,这里的RetentionPolicy.RUNTIME
是保留至运行时。@Target
:表示该注解只能修饰在哪里,这里表示只能用在类上。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EnableAnimal {
}
关键
除了自定义注解外 ,另外一个最重要的关键就是:@Import
注解。这个注解的作用就是:要将哪些bean整合起来(打包)。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import()
public @interface EnableAnimal {
}
现在我们把目光聚焦在@Import()
的括号里,也就是它有哪些方式来打包bean
方式一:直接导入类
最简单粗暴的方式,直接在括号里加入需要装配的类名.class
,比如说装配Dog.class
@Import(Dog.class)
public @interface EnableAnimal {
}
方式二:导入一个配置类
这个方式其实和方式一的感觉是一样的,只是我们需要先定义一个配置类,然后将这个配置类放在括号中(和方式一一样)。
- 定义一个配置类,在配置类中注册Pig
@Configuration
public class AssemblyConfig {
@Bean
public Pig pig(){
return new Pig();
}
}
- 将配置类写在
@Import()
中
@Import({Dog.class, AssemblyConfig.class})
方式三:实现ImportSelector
接口
重写selectImports
方法,返回需要导入类的全限定类名。这里我们再注入Cat
public class ImportSelectorImpl implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{Cat.class.getName()};
}
}
放到注解中的@Import
@Import({Dog.class, AssemblyConfig.class, ImportSelectorImpl.class})
方法四:实现ImportBeanDefinitionRegistrar
接口
重写registerBeanDefinitions
方法;它导入的是BeanDefinition
(这个内容高级篇见)
public class ImportBeanDefinitionRegistrarImpl implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("tuzi",new RootBeanDefinition(Rabbit.class));
}
}
放到注解中的@Import
@Import({Dog.class, AssemblyConfig.class, ImportSelectorImpl.class,ImportBeanDefinitionRegistrarImpl.class})
测试
OK,我们已经操作四种方式实现模块装配了,现在测试一下IOC容器中都有什么
配置类中导入注解
导入@EnableAnimal
自定义注解即可,然后看IOC容器中是否有这四个动物了。
@Configuration
@EnableAnimal
public class AssemblyApplicationConfig {
}
主程序
打印所有在IOC容器中bean的id
public class AssemblyApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AssemblyApplicationConfig.class);
for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}