spring中竟然有12种定义bean的方法
Python涨薪研究所
共 18976字,需浏览 38分钟
·
2021-07-20 08:43
前言
1. xml文件配置bean
xml配置bean
开始,它是spring最早支持的方式。后来,随着springboot
越来越受欢迎,该方法目前已经用得很少了,但我建议我们还是有必要了解一下。1.1 构造器
<bean id="personService" class="com.sue.cache.service.test7.PersonService">
</bean>
<constructor-arg>
标签来完成配置。<bean id="personService" class="com.sue.cache.service.test7.PersonService">
<constructor-arg index="0" value="susan"></constructor-arg>
<constructor-arg index="1" ref="baseInfo"></constructor-arg>
</bean>
index
表示下标,从0开始。value
表示常量值ref
表示引用另一个bean
1.2 setter方法
@Data
public class Person {
private String name;
private int age;
}
<property>
标签设置bean所需参数。<bean id="person" class="com.sue.cache.service.test7.Person">
<property name="name" value="susan"></constructor-arg>
<property name="age" value="18"></constructor-arg>
</bean>
1.3 静态工厂
public class SusanBeanFactory {
public static Person createPerson(String name, int age) {
return new Person(name, age);
}
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Person {
private String name;
private int age;
}
factory-method
参数指定静态工厂方法,同时通过<constructor-arg>
设置相关参数。<bean class="com.sue.cache.service.test7.SusanBeanFactory" factory-method="createPerson">
<constructor-arg index="0" value="susan"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>
</bean>
1.4 实例工厂方法
public class SusanBeanFactory {
public Person createPerson(String name, int age) {
return new Person(name, age);
}
}
factory-bean
参数指定该工厂bean的引用。<bean id="susanBeanFactory" class="com.sue.cache.service.test7.SusanBeanFactory">
</bean>
<bean factory-bean="susanBeanFactory" factory-method="createPerson">
<constructor-arg index="0" value="susan"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>
</bean>
1.5 FactoryBean
FactoryBean
接口。public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
getObject
方法中可以实现我们自己的逻辑创建对象,并且在getObjectType
方法中我们可以定义对象的类型。<bean id="userFactoryBean" class="com.sue.async.service.UserFactoryBean">
</bean>
注意:getBean("userFactoryBean");获取的是getObject方法中返回的对象。而getBean("&userFactoryBean");获取的才是真正的UserFactoryBean对象。
2. Component注解
@Component
、@Repository
、@Service
、@Controller
等注解定义bean。@Component
。@Component
系列注解的出现,给我们带来了极大的便利。我们不需要像以前那样在bean.xml文件中配置bean了,现在只用在类上加Component、Repository、Service、Controller,这四种注解中的任意一种,就能轻松完成bean的定义。@Service
public class PersonService {
public String get() {
return "data";
}
}
Controller 一般用在控制层 Service 一般用在业务层 Repository 一般用在数据层 Component 一般用在公共组件上
@Component
扫描注解的方式定义bean的前提是:需要先配置扫描路径。在applicationContext.xml文件中使用 <context:component-scan>
标签。例如:
<context:component-scan base-package="com.sue.cache" />
在springboot的启动类上加上 @ComponentScan
注解,例如:
@ComponentScan(basePackages = "com.sue.cache")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
直接在 SpringBootApplication
注解上加,它支持ComponentScan功能:
@SpringBootApplication(scanBasePackages = "com.sue.cache")
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
scanBasePackages
参数,spring默认会从入口类的同一级或者子级的包去找。@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
@Component
注解之外,springboot还增加了@RestController
注解,它是一种特殊的@Controller
注解,所以也是@Component
注解。@RestController
还支持@ResponseBody
注解的功能,即将接口响应数据的格式自动转换成json。@Component
系列注解已经让我们爱不释手了,它目前是我们日常工作中最多的定义bean的方式。3. JavaConfig
@Component
系列注解虽说使用起来非常方便,但是bean的创建过程完全交给spring容器来完成,我们没办法自己控制。@Configuration
public class MyConfiguration {
@Bean
public Person person() {
return new Person();
}
}
@Configuration
注解,相当于配置了<beans>
标签。而在方法上加@Bean
注解,相当于配置了<bean>
标签。@Conditional
注解,用来控制bean的创建。@Configuration
public class MyConfiguration {
@ConditionalOnClass(Country.class)
@Bean
public Person person() {
return new Person();
}
}
@ConditionalOnClass
注解的功能是当项目中存在Country类时,才实例化Person类。换句话说就是,如果项目中不存在Country类,就不实例化Person类。ConditionalOnBean ConditionalOnProperty ConditionalOnMissingClass ConditionalOnMissingBean ConditionalOnWebApplication
4. Import注解
@Import
注解导入。4.1 普通类
@Import
注解可以实例化普通类的bean实例。例如:@Data
public class Role {
private Long id;
private String name;
}
@Import(Role.class)
@Configuration
public class MyConfig {
}
@Autowired
注解注入所需的bean。@RequestMapping("/")
@RestController
public class TestController {
@Autowired
private Role role;
@GetMapping("/test")
public String test() {
System.out.println(role);
return "test";
}
}
@Import
注解的强大之处。@Import
注解能定义单个类的bean,但如果有多个类需要定义bean该怎么办呢?@Import
注解也支持。@Import({Role.class, User.class})
@Configuration
public class MyConfig {
}
MyConfig
类,springboot也欢迎。@Import({Role.class, User.class})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.SERVLET).run(args);
}
}
4.2 Configuration类
@Configuration
public class MyConfig2 {
@Bean
public User user() {
return new User();
}
@Bean
public Role role() {
return new Role();
}
}
@Import({MyConfig2.class})
@Configuration
public class MyConfig {
}
@EnableSwagger2
注解,就能开启swagger的功能。SpringfoxWebMvcConfiguration SwaggerCommonConfiguration
@EnableSwagger2
注解,就能轻松的导入swagger所需的一系列bean,并且拥有swagger的功能。4.3 ImportSelector
ImportSelector
接口了。ImportSelector
接口:public class DataImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.sue.async.service.User", "com.sue.async.service.Role"};
}
}
selectImports
方法,在该方法中指定需要定义bean的类名,注意要包含完整路径,而非相对路径。@Import({DataImportSelector.class})
@Configuration
public class MyConfig {
}
spring.boot.enableautoconfiguration
。ImportSelector
接口。selectImports
方法,该方法会根据某些注解去找所有需要创建bean的类名,然后返回这些类名。其中在查找这些类名之前,先调用isEnabled方法,判断是否需要继续查找。spring.boot.enableautoconfiguration
。把某个功能的相关类,可以放到一起,方面管理和维护。 重写selectImports方法时,能够根据条件判断某些类是否需要被实例化,或者某个条件实例化这些bean,其他的条件实例化那些bean等。我们能够非常灵活的定制化bean的实例化。
4.4 ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar
接口的神奇之处。public class CustomImportSelector implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
registry.registerBeanDefinition("role", roleBeanDefinition);
RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
registry.registerBeanDefinition("user", userBeanDefinition);
}
}
registerBeanDefinitions
方法,在该方法中我们可以获取BeanDefinitionRegistry
对象,通过它去注册bean。不过在注册bean之前,我们先要创建BeanDefinition对象,它里面可以自定义bean的名称、作用域等很多参数。@Import({CustomImportSelector.class})
@Configuration
public class MyConfig {
}
5. PostProcessor
BeanDefinitionRegistryPostProcessor
。BeanDefinitionRegistryPostProcessor
接口。@Component
public class MyRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
registry.registerBeanDefinition("role", roleBeanDefinition);
RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
registry.registerBeanDefinition("user", userBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
postProcessBeanDefinitionRegistry
方法,在该方法中能够获取BeanDefinitionRegistry
对象,它负责bean的注册工作。postProcessBeanFactory
方法,没有做任何实现。BeanFactoryPostProcessor
里的方法。@Component
public class MyPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory registry = (DefaultListableBeanFactory)beanFactory;
RootBeanDefinition roleBeanDefinition = new RootBeanDefinition(Role.class);
registry.registerBeanDefinition("role", roleBeanDefinition);
RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
registry.registerBeanDefinition("user", userBeanDefinition);
}
}
BeanDefinitionRegistryPostProcessor 更侧重于bean的注册 BeanFactoryPostProcessor 更侧重于对已经注册的bean的属性进行修改,虽然也可以注册bean。
BeanFactoryAware
接口:@Component
public class BeanFactoryRegistry implements BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
DefaultListableBeanFactory registry = (DefaultListableBeanFactory) beanFactory;
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class);
registry.registerBeanDefinition("user", rootBeanDefinition);
RootBeanDefinition userBeanDefinition = new RootBeanDefinition(User.class);
userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
registry.registerBeanDefinition("user", userBeanDefinition);
}
}
setBeanFactory
方法,在该方法中能够获取BeanFactory对象,它能够强制转换成DefaultListableBeanFactory对象,然后通过该对象的实例注册bean。BeanFactoryAware
接口是在bean创建成功,并且完成依赖注入之后,在真正初始化之前才被调用的。在这个时候去注册bean意义不大,因为这个接口是给我们获取bean的,并不建议去注册bean,会引发很多问题。此外,ApplicationContextRegistry和ApplicationListener接口也有类似的问题,我们可以用他们获取bean,但不建议用它们注册bean。
好文推荐
网传京东某程序员因压力太大,在商品页面置入骂人代码!京东辟谣:不关我们的事,外部商家干的!
某大厂程序员炫耀:来新加坡后,每天最多工作五六个小时,家庭年收入150万人民币,已躺平!
19年寒窗苦读,清华毕业,来了腾讯就做炸翔的功能?
一键三连「分享」、「点赞」和「在看」
技术干货与你天天见~
评论