Spring注入Bean的几种方式
简单罗列下Spring注入Bean的几种方式。
XML注入
早期的Spring,特别是springboot框架没有出来之前,都是基于XML配置的方式进行注入的,通过该方式配置的过程比较繁琐,但是对代码的侵入性较小。现在使用xml的项目已经不多了。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.xx.Hello">
<property name="id" value="1"/>
<property name="name" value="hello"/>
</bean>
</beans>
注解注入
@Component @Controller @Service @Repository & @ComponentScan
这种方式是我们使用最频繁的方式,Spring为我们提供了对业务的不同层提供了不同的注解的来标记不同类型的Bean,他们的本质都是@Component。SpringBoot在启动的时候,会扫描@ComponentScan配置的(如果没有配置则会扫描当前主类同级及子级包下)所有带有该注解的类,并注入到容器中。
@Controller
public class HelloController {}
@Service
public class HelloService {}
@Repository
public class HelloMapper {}
@Component
public class HelloEntity {}
@Bean & @Configuration
该方式其实完全就等效于上面的xml的配置,一个@Configuration注解的类可以就理解为一个xml配置文件,一个@Bean注解的方法就可以看做配置的一个<bean>标签。这个一般我们用来加载配置使用的,比如在该类中读取到配置文件中的一些值,需要对其加工和封装成一个Bean,然后将其注入对象,他的职责更多是为了配置。
@Configuration
public class Config {
//给容器中注册一个bean, 类型为返回值的类型
//指定bean的id
@Bean("user")
public Hello hello(){
return new Hello();
}
}
@Bean & FactoryBean & @Configuration
在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。
@Configuration
public class Config {
//通过Spring的工厂bean注册
@Bean
public HelloFactoryBean helloFactoryBean(){
return new HelloFactoryBean();
}
}
public class HelloFactoryBean implements FactoryBean<Hello>{
@Override
public Pig getObject() throws Exception {
// TODO Auto-generated method stub
return new Hello();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Hello.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
BeanDefinition & @Import
BeanDefinition是Spring容器的底层实现,上面提到的那些方式其实底层都是通过先注入BeanDefinition注入的,Spring中每一个配置的Bean其实都会先对应一个BeanDefinition。这个一般都是在其他框架和Spring进行整合的时候使用比较多,我们日常使用的比较少。
一般情况下,这种方式都结合@Import方式注入的。比如Mybatis中注入Mapper扫描器的逻辑,就是通过注入BeanDefinition。
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
}
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
}