spring中竟然有12種定義bean的方法

前言

1. xml文件配置bean
xml配置bean開始,它是spring最早支持的方式。后來,隨著springboot越來越受歡迎,該方法目前已經(jīng)用得很少了,但我建議我們還是有必要了解一下。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所需參數(shù)。<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 靜態(tài)工廠
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參數(shù)指定靜態(tài)工廠方法,同時通過<constructor-arg>設置相關參數(shù)。<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參數(shù)指定該工廠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方法中可以實現(xiàn)我們自己的邏輯創(chuàng)建對象,并且在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系列注解的出現(xiàn),給我們帶來了極大的便利。我們不需要像以前那樣在bean.xml文件中配置bean了,現(xiàn)在只用在類上加Component、Repository、Service、Controller,這四種注解中的任意一種,就能輕松完成bean的定義。@Service
public class PersonService {
public String get() {
return "data";
}
}
Controller 一般用在控制層 Service 一般用在業(yè)務層 Repository 一般用在數(shù)據(jù)層 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參數(shù),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注解的功能,即將接口響應數(shù)據(jù)的格式自動轉換成json。
@Component系列注解已經(jīng)讓我們愛不釋手了,它目前是我們日常工作中最多的定義bean的方式。3. JavaConfig
@Component系列注解雖說使用起來非常方便,但是bean的創(chuàng)建過程完全交給spring容器來完成,我們沒辦法自己控制。@Configuration
public class MyConfiguration {
@Bean
public Person person() {
return new Person();
}
}
@Configuration注解,相當于配置了<beans>標簽。而在方法上加@Bean注解,相當于配置了<bean>標簽。@Conditional注解,用來控制bean的創(chuàng)建。@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方法,該方法會根據(jù)某些注解去找所有需要創(chuàng)建bean的類名,然后返回這些類名。其中在查找這些類名之前,先調用isEnabled方法,判斷是否需要繼續(xù)查找。

spring.boot.enableautoconfiguration。把某個功能的相關類,可以放到一起,方面管理和維護。 重寫selectImports方法時,能夠根據(jù)條件判斷某些類是否需要被實例化,或者某個條件實例化這些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之前,我們先要創(chuàng)建BeanDefinition對象,它里面可以自定義bean的名稱、作用域等很多參數(shù)。@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方法,沒有做任何實現(xiàn)。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 更側重于對已經(jīng)注冊的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創(chuàng)建成功,并且完成依賴注入之后,在真正初始化之前才被調用的。在這個時候去注冊bean意義不大,因為這個接口是給我們獲取bean的,并不建議去注冊bean,會引發(fā)很多問題。此外,ApplicationContextRegistry和ApplicationListener接口也有類似的問題,我們可以用他們獲取bean,但不建議用它們注冊bean。

好文推薦

網(wǎng)傳京東某程序員因壓力太大,在商品頁面置入罵人代碼!京東辟謠:不關我們的事,外部商家干的!

某大廠程序員炫耀:來新加坡后,每天最多工作五六個小時,家庭年收入150萬人民幣,已躺平!

19年寒窗苦讀,清華畢業(yè),來了騰訊就做炸翔的功能?
一鍵三連「分享」、「點贊」和「在看」
技術干貨與你天天見~
評論
圖片
表情

