注册 bean 的方式
注册 bean 的方式
- XML 方式,这个已经没人使用了
- 单注解
@Component、@Service、@Controller、@RestController、@Respository、@Configuation - 组合注解
@Configuation+@Bean、@Configuation+@Import、@Configuation+@ImportResource @ConfigurationProperties、@Condition
@Configuation + @Bean
@Configuration
public class MyConfig { // MyConfig 也会注册
@Bean
public User user(){ // User 会注册到容器中
retu new User();
}
}
@Configuation + @ImportResource
这种方式是想兼容老项目,把 xml 中配置的 bean 批量导入容器中
@Configuration
@ImportResource({"classpath:applicationContext.xml", "classpath:anotherContext.xml"}) // 把这两个 xml 文件中的 bean 注册到容器中
public class ImportResourceConfig {
}
@Configuation + @Import
通过指定类批量注册
@Configuration
@Import({User.class, Person.class}) // 把 User 和 Person 注册到容器中
public class SpringConfig {
}
通过 ImportSelector 批量注册
public class MyImportSelector implements ImportSelector { // 实现 ImportSelector 接口
@Override
public String[] selectImports(AnnotationMetadata icm) {
// 返回一个全限定名的类的数组
return new String[]{User.class.getName(), "com.cyrus.dto.Person"};
}
}
@Configuration
@PropertySource("classpath:jdbc.properties")
@ComponentScan("com.study")
@Import(MyImportSelector.class) // 把内部返回的数组全都注册到容器中
@EnableAspectJAutoProxy
@EnableTransacTionManagement
public class SpringConfig {
}
selectImports(AnnotationMetadata icm) 的参数可以获取到标注了 @Import 注解的类上的注解,标注的类是 SpringConfig,SpringConfig 上的所有注解
通过 ImportBeanDefinitionRegistrar 批量注册
public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar { // 实现 ImportBeanDefinitionRegistrar 接口
@Override
public void registerBeanDefinitions(AnnotationMetadata icm, BeanDefinitionRegistry registry) {
// 注册 User 类型的 BeanDefinition
AbstractBeanDefinition userBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
registry.registerBeanDefinition("user", beanDefinition);
// 注册 Person 类型的 BeanDefinition
RootBeanDefinition personBeanDefinition = new RootBeanDefinition();
personBeanDefinition.setBeanClassName("com.cyrus.dto.Person");
registry.registerBeanDefinition("person", personBeanDefinition);
}
}
@Configuration
@Import(User.class) // 注册 User
@Import(MyBeanDefinitionRegister.class) // 内部会把 BeanDefinition 都注册到容器中
public class SpringConfig {
}
Spring 内部会先注册 BeanDefinition,然后根据 BeanDefinition 的信息(比如 lazy、calss、name 等)构建出 Bean 放入到容器中
registerBeanDefinitions(AnnotationMetadata icm, BeanDefinitionRegistry registry) 参数:
- 第一个参数和 ImportSelector 的
selectImports(AnnotationMetadata icm)方法相同,也是获取标注了@Import的类上的所有注解 - 第二个参数是 BeanDefinition 注册器,用来注册 BeanDefinition 的(不是直接注册 bean,根据 Spring 机制间接注册 Bean)
@ConfigurationProperties
这是用来绑定配置文件的,把配置文件的属性绑定到 java 对象的字段上。这个 java 对象会被注册到容器中
有多种搭配方式:@EnableConfigurationProperties、@Configuration、@Component、@Bean
虽然也是注册bean的方式,意义上主要是读取配置文件。SpringBoot 读取配置文件
@Condition
自定义条件注册
@Configuration
public class MyBean3 {
@Conditional(EvenWeekDayCondition.class) // 这个类决定 User 是否注册(内部 matches 方法返回 true 就注册,false 不注册)
@Bean
public User user(){
return new User();
}
}
// 不用标注注解,如果当前星期是偶数就返回 true
public class EvenWeekDayCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
int dayOfWeek = LocalDate.now().getDayOfWeek().getValue(); // 返回星期,从1开始
return dayOfWeek % 2 == 0; // 是否是偶数
}
}
Spring 批处理条件注册分析
@Configuration(proxyBeanMethods = false) // 是否对当前类下的 @Bean 使用代理拦截
@ConditionalOnClass({JobLauncher.class, DataSource.class}) // 如果 JobLauncher 和 DataSource 类存在,才进行注册
@AutoConfigureAfter(HibernateJpaAutoConfiguration.class) // 等 HibernateJpaAutoConfiguration 类型的 bean 注册了,才进行注册
@ConditionalOnBean(JobLauncher.class) // 如果 JobLauncher 类型的 bean 存在,才进行注册
@EnableConfigurationProperties(BatchProperties.class) // 启用自定义配置类
@Import(BatchConfigurerConfiguration.class) // 注册 BatchConfigurerConfiguration 的 bean
public class BatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.batch.job", name = "enabled", havingValue = "true", matchIfMissing = true)
public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer,
JobRepository jobRepository, BatchProperties properties) {
...
}
...
}
-
@Configuration的proxyBeanMethods属性规定 当前类 下的 @Bean 如果有依赖关系,是否使用代理拦截创建@Configuration(proxyBeanMethods = false) public class ConfigA { @Bean public ServiceA serviceA() { return new ServiceA(); } @Bean public ServiceB serviceB() { // 如果 proxyBeanMethods 是 true,serviceA 会到容器中获取 // 这里是 false,会直接调用方法,会产生新的实例(如果要保证单例需要自行控制) return new ServiceB(serviceA()); } } -
@ConditionalOnClass当指定的类如果不存在,就不进行注册(当前类下的各个@Bean配置的 bean 也不会注册了) -
@ConditionalOnBean同上,当指定的 bean 如果不存在,就不进行注册 -
@AutoConfigureAfter等指定的 bean 先配置完成,再注册当前类。指定 bean 的创建顺序,和@DependsOn有类似效果,但两者也有区别- AutoConfigureAfter 依赖的 bean 不一定存在;DependsOn 依赖的 bean 必须存在
- AutoConfigureAfter 语义上属于自动配置的基础支持层面;DependsOn 属于应用层面,程序员自定义 bean 时
@Configuration public class AppConfig { @Bean @DependsOn("redis") // 确保 redis 先创建(如果没有会报错) public DataSource dataSource() { } } -
@ConditionalOnMissingBean当指定的 bean 如果已经存在,不会进行注册 -
@ConditionalOnProperty根据配置文件的配置项决定当前 bean 是否注册,如果为真进行注册,为假不注册prefix = "spring.batch.job", name = "enabled"确定配置项,这里的配置项是spring.bath.job.enabledhavingValue = "true"如果spring.bath.job.enabled是true条件为真matchIfMissing = true如果没有spring.bath.job.enabled配置项,也判定条件为真(如果spring.batch.job.enabled是false条件为假)
要么不要配置,默认是真;如果你配置了为 false 那就是假

浙公网安备 33010602011771号