Spring中,我们总是通过IOC肆无忌惮的去获取Bean对象,本着饮水思源的道理,我们来针对Bean注入的各种姿势进行详细分析。其实重点还有一个,面试的时候我很喜欢提这个问题,Spring的Bean注入方式你了解哪些?而非Spring的Bean获取方式。
XML注入是一种最原生的注入方式,一个XML配置文件,一个Bean配置对象,即可在Spring容器中注入一个Bean。
以上代码则代表在spring容器中注入一个id名为user的对象。获取时通过 applicationContext.getBean("user", User.class); 获取即可。
@configuration + @Bean 注解,相当于XML注入方法的简化注解形式,一个配置类加上@configuration 注解,在类中使用@Bean注解注入对象接口。ID为方法名称
@Configuration
public class SpringTestConfig {
@Bean
public User user() {
return new User(2, "yiang");
}
}
以上代码则表示在Spring容器中注入一个ID为2,名称为yiang的用户实体。关于Bean注解的其它说明可以参考该文章:偷窥Spring中的Bean加载。
@Bean的条件注入注解,与@Bean一起在对象注入时使用,可以通过@Conditional(WindowsCondition.class)指定条件处理类,处理类通过实现Condition接口,来进行相关的逻辑判断,以下代码则表示,如果操作系统为Windows10的情况下,才会放行将该Bean注入到Spring容器中。
public class WindowsCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
return "Windows 10".equals(property);
}
}
@Import导入注解,使用在类头,包含一个Class>[]的数组参数,可以传入多个类,一般更多用于外部jar对象导入,导入的对象ID为其全路径名,与@Bean注解的区别是@Bean的导入默认为方法名或者是首字母小写的驼峰。使用方法如下
@Import({PayEntity.class})
public class SpringTestConfig {
表示注入配置的PayEntity类对象,注入后的ID如下:
com.yiang.code.entity.PayEntity
@EnableXXX是大部分框架的导包实现,很凸显的栗子就是@EnableEureka(注册中心)、@EnableFeignClients(Feign客户端)、@EnableAsync(异步注解)。
我们翻看到@EnableAsync 异步注解源码中,实际上在里面的处理还是通过调用的@Import注解,那么也就是说,@EnableXXX、注解实际上就是对@Import注解的一个封装。使用时在配置导入的时候,仅仅只需要使用一个@Enablexxx即可,无需指定导入某个类。更加简单、整洁。
通过手写类实现ImportSelector接口,并且注入到Spring容器,可实现自定义去注入对象,实则在前面@EnableAsync时,指向的AsyncConfigurationSelector类就是采用了这种方式进行导包,通过实现ImportSelector(基类),然后实现selectImports方法,去返回对应的类名注入到Spring容器。
通过手写类实现ImportBeanDefinitionRegistrar接口,并且注入到Spring容器,注入形式和@ImportSelector接口无差距,通过实现接口方法即可。以下代码则代表注入RegisterEntity
类到容器中,ID为registerEntity。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RegisterEntity.class);
registry.registerBeanDefinition("registerEntity", rootBeanDefinition);
}
}
这里需要注意的是FactoryBean接口 与BeanFactory的区别,本接口是注册Bean对象的,而BeanFactory接口则是获取Bean对象。
实现方式也比较简单,isSingleton方法决定是否单例,默认不会强制实现,是false,实现改为true则是单例模式,其它就是返回对应的对象与类实例。
public class MyFactoryBean implements FactoryBean {
public MyFactoryBeanEntity getObject() {
return new MyFactoryBeanEntity();
}
public Class> getObjectType() {
return MyFactoryBeanEntity.class;
}
public boolean isSingleton() {
return true;
}
}
注入时可以使用@Bean注册该类,亦可以使用@Import导入
@Bean
public MyFactoryBean myFactoryBean() {
return new MyFactoryBean();
}
正常项目开发架构中,用的最多的也就是这几个注解了。@Repository代表Mapper文件Dao层,@Service代表业务逻辑层,@Controller代表控制层,这个需要注意的是@RestController并非Spring包自带的注解。所以不在此说明。实际上进行代码分组的三个注解核心都是依赖的@Component注解。只做区分,其实内部并无差距。
以上即为9种Spring中Bean的注入方式, 很多方式其实属于大同小异,可以根据需求灵活运用。我们亦可以在实际项目中选择自己喜欢的方式,保证其适用性与合理性即可。