Spring 是一款广泛应用于企业级应用程序开发的 Java 框架,其 IOC 和 DI 特性可以有效地管理应用程序中的对象,提高了应用程序的可维护性和可扩展性。那你知道spring有哪些方式将bean放入容器嘛?今天就给大家总结一下。
spring.factories
使用 spring.factories是springboot加载bean的一种方式,通常用于自动装配环境配置相关的类,和Configuration注解有异曲同工之妙。
其机制和java的SPI机制类似,不同的是其配置规则 : spring.factories以key,value的键值对列表存在。value是类的完全限定类名。类之间用逗号(,)分隔,后面跟着反斜杠(\)和换行符,以提高可读性。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.AutoConfigurationClass1,\
com.example.AutoConfigurationClass2
复制代码
@Configuration + @ComponentScan
@Configuration顾名思义就是我们的环境配置,标记SpringBoot中的配置类。其一般与其他Spring的相关配置一起使用。内部的话就是我们需要注入到spring容器的bean。
- 与@Conditiona簇的注解一起使用,用于在标识该类在满足某种规则后下生效。
- 在配置类中我们也可以添加@import注解导入某些类。
- 一般我们的配置类如果在启动类包路径下的话,SpringBoot可以自行装配,无需其他配置去扫描发现。但是如果不是的话,则需要配置 @ComponentScan或者 spring.factories文件了。一般我们开发一个框架的话,推荐使用spring.factories的方式,这样使用者导入相应的jar包(一般是spring-starter包)即可自动装配相应的bean。
如下的nacos中的服务发现配置:
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public NacosDiscoveryProperties nacosProperties() {
return new NacosDiscoveryProperties();
}
@Bean
@ConditionalOnMissingBean
public NacosServiceDiscovery nacosServiceDiscovery(
NacosDiscoveryProperties discoveryProperties,
NacosServiceManager nacosServiceManager) {
return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
}
}
复制代码
@Import直接导入类
在Spring框架中,@Import注解用于导入一个或多个配置类或普通的Java类,以便在当前的配置类中使用。它可以在@Configuration注解的类中使用,用于引入其他类的定义,以便在当前类中使用这些定义。
@Import注解一般有以下两种使用方式:
- 导入一个或多个配置类:可以使用@Import注解导入其他使用了@Configuration注解的配置类。例如,@Import(MyConfig.class)将会导入名为MyConfig的配置类。
- 导入普通的Java类:可以使用@Import注解导入非配置类的Java类,以便在当前配置类中使用该类的实例。例如,@Import(MyService.class)将会导入名为MyService的普通Java类。
- Import只能在类上使用。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import({ RabbitAnnotationDrivenConfiguration.class, RabbitStreamConfiguration.class })
public class RabbitAutoConfiguration {
...
}
复制代码
上述配置示例就又导入了两个配置类:RabbitAnnotationDrivenConfiguration,RabbitStreamConfiguration。
@Bean
注解@Bean一般用于向spring中注入一个比较复杂的bean,这个bean一般配置复杂,功能多。它也是我们使用的最多的一种方式。它有以下几个特点:
- 可以指定bean的名称:可以使用name属性指定bean的名称。如果未指定名称,则将使用方法名作为bean的名称。
- 可以指定bean的作用域:可以使用@Scope注解指定bean的作用域。默认情况下,bean的作用域为单例(即在整个应用程序上下文中只有一个实例)。
- 可以指定bean的初始化和销毁方法:可以使用@PostConstruct和@PreDestroy注解指定bean的初始化和销毁方法。
@Configuration
public class MyConfiguration {
@Bean
public User user() {
User user = new User();
User.setName("凹凸曼");
return user;
}
}
复制代码
@Componet + @ComponentScan
@Componet注解也是我们使用的比较多的注解,可能我这样说你比较疑惑。但是@Controller,@Service,@Repository这些注解你熟悉吧,他们都是基于@Componet实现的。其和@ComponentScan注解搭配使用,通过扫描某个包路径来实现导入。
FactoryBean接口
FactoryBean千万不要和BeanFactory搞混了喔。BeanFactory是spring的bean管理工厂用于管理Spring中的bean的,它是IOC容器的顶级接口,。FactoryBean是用来创建复杂的或自定义bean的。
FactoryBean接口有两个主要方法:
- T getObject():该方法返回由工厂创建的对象实例。
- Class<?> getObjectType():该方法返回由工厂创建的对象的类型。
我们来看一个列子:
@Configuration
public class TestConfiguration {
@Bean
public UserFactoryBean userFactoryBean() {
return new UserFactoryBean();
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfiguration.class);
Person bean = applicationContext.getBean(User.class);
System.out.println(bean);
}
}
class UserFactoryBean implements FactoryBean<User> {
/**
* 直接new出来User进行返回.
*/
@Override
public User getObject() throws Exception {
return new User();
}
/**
* 指定返回bean的类型.
*/
@Override
public Class<?> getObjectType() {
return User.class;
}
}
复制代码
BeanDefinitionRegistryPostProcessor
这个提供的一个扩展点,BeanDefinitionRegistryPostProcessor接口是spring提供的一个扩展点,用于允许开发者在应用程序上下文启动时动态修改或注册bean定义。它允许开发者在应用程序上下文创建bean之前对bean定义进行更改或添加新的bean定义。
class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
registry.registerBeanDefinition("user", beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
复制代码
上面的列子中我们可以看到,我们通过拿到BeanDefinitionRegistry,然后像里面注册了一个user的beanDefinition。后续spring就可以通过registry中的数据来实例话user这个bean了。
总结
上诉我们一共介绍了7中创建bean的方式,希望对大家有所帮助,以上内容就到这里,感谢各位看官老爷们的观看,如果觉得写得好,给个赞支持一下哈!!!
附录
Conditional
- ConditionalOnClass 当某些类存在时满足条件
- ConditionalOnBean 当某些bean存在时满足条件
- ConditionalOnProperty 当某个属性满足值满足时
- ConditionalOnCloudPlatform 当某个云平台存在时满足条件
- ConditionalOnExpression 当某个springEL表达式满足时
- ConditionalOnJava 当某个java版本匹配时满足条件 @ConditionalOnJava(JavaVersion.NINE)
- ConditionalOnJndi 当某个JNDI条件满足时 @ConditionalOnJndi({ "java:/JmsXA", "java:/XAConnectionFactory" })
- ConditionalOnMissingBean 当某些bean缺失时满足条件
- ConditionalOnMissingClass 当某些类不存在时满足条件
- ConditionalOnResource 当某些资源存在时
- ConditionalOnSingleCandidate bean实例为单列或者是满足单个实例的条件
- ConditionalOnWarDeployment 当应用以war包条件部署时
- ConditionalOnNotWebApplication 当不是一个应用程序时满足条件
- ConditionalOnWebApplication 当是一个应用程序时满足条件
作者:阿Qoder
链接:https://juejin.cn/post/722669672335437008