Spring?Bean的8種加載方式總結
前言
以前學習Spring框架的時候,總結了幾種Bean的加載方式,不過老師說還有其它的加載方式,以下八種并不是全部,但也足以用來做很多事情了。
注意以下是Spring中Bean的加載方式,不是SpringBoot,但其中的很多東西是相通的,尤其是Bean的注入方式、適用場景等,在本文中也有介紹的。
分享給大家一起學習,如有錯誤的地方,麻煩各位在評論區(qū)幫我指出。
1.xml+<bean>
被配置的bean需要有無參數(shù)的構造函數(shù)
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- xml方式聲明自己開發(fā)的bean -->
<bean id="user" class="cn.sticki.blog.pojo.domain.User" />
<!-- xml方式聲明第三方bean -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/>
</beans>2.xml:context+注解(@Component+4個@Bean)
使用組件掃描,指定加載bean的位置,spring會自動掃描這個包下的文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 組件掃描,指定加載bean的位置 -->
<context:component-scan base-package="cn.sticki.bean,cn.sticki.config"/>
</beans>然后在需要被加載的類名上添加@Component注解。也可以使用@Controller、@Service、@Repository定義bean。
@Service
publice class UserServiceImpl implements UserService {
}使用@Bean定義第三方bean,并將所在類定位為配置類或Bean
@Configuration // 或使用@Component
public class DBConfig {
@Bean
public DruidDataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}
}3.配置類+掃描+注解(@Component+4個@Bean)
使用 AnnotationConfigApplicationContext(SpringConfig.class); 來獲取 ApplicationContext
public class AppObject {
public static void main() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
SpringConfig config = ctx.getBean("Config", SpringConfig.class);
// 兩次獲取的是同一個對象
config.user();
config.user();
}
}和上面的第二種有點類似,就是包的掃描方式有所改變。
@ComponentScan({"cn.sticki.bean","cn.sticki.config"})
public class SpringConfig {
@Bean
public DogFactoryBean dog(){
return new DogFactoryBean();
}
}3.1FactoryBean接口
初始化實現(xiàn)FactoryBean接口的類,實現(xiàn)對bean加載到容器之前的批處理操作。
public class DogFactoryBean implements FactoryBean<Dog> {
@Override
public Dog getObject() throws Exception {
return new Dog();
}
@Override
public Class<?> getObjectType() {
return Dog.class;
}
}在下面的bean中,顯示的表示為配置DogFactoryBean ,但實際上配置的是 Dog 。
@Component
public class SpringConfig {
@Bean
public DogFactoryBean dog(){
return new DogFactoryBean();
}
}3.2@ImportResource注解
用于加載配置類并加載配置文件(系統(tǒng)遷移)
@Configuration
@ComponentScan("cn.sticki.bean")
@ImportResource("applicationContext.xml")
public class SpringConfig {
}3.3proxyBeanMethods屬性
使用 proxyBeanMethods = true 可以保障調用此類中的方法得到的對象是從容器中獲取的,而不是重新創(chuàng)建的,但要求必須是通過此類調用方法獲得的bean。
@Configuration(proxyBeanMethods = true)
public class SpringConfig {
@Bean
public User user() {
System.out.println("user init...");
return new User();
}
}4.@Import導入bean的類
使用@Import注解導入要注入的bean對應的字節(jié)碼
@Import(User.class)
public class SpringConfig {
}而被導入的bean無需使用注解聲明為bean
public class User{
}這種形式可以有效的降低源代碼與spring技術的耦合度(無侵入),在spring技術底層及諸多框架的整合中大量使用。
使用這種方法可以加在配置類,且也可以加在配置類當中的bean。
5.AnnotationConfigApplicationContext調用register方法
在容器初始化完畢后使用容器對象手動注入bean
public class App {
public static void main() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
ctx.register(User.class);
// 打印容器中當前的所有bean
String[] names = ctx.getBeanDefinitionNames();
for (String name: names) {
System.out.println(name);
}
}
}必須在容器初始化之后才能使用這種方法。如果重復加載同一個bean,后面加載的會覆蓋前面加載的。
6.@Import導入ImportSelector接口
導入實現(xiàn)了ImportSelector接口的類,實現(xiàn)對導入源的編程式處理
public class MyImportSelector implements ImportSelector {
public String selectImports(AnnotationMetadata metadata) {
// 使用metadata可以獲取到導入該類的元類的大量屬性,通過對這些屬性進行判斷,可以達到動態(tài)注入bean的效果
boolean flag = metadata.hasAnnotation("org.springframework.context.annotation.Import");
if(flag) {
return new String[]{"cn.sticki.pojo.User"};
}
return new String[]{"cn.sticki.pojo.Dog"};
}
}調用處:
@Import(MyImportSelector.class)
public class SpringConfig {
}7.@Import導入ImportBeanDefinitionRegistrar接口
導入實現(xiàn)了ImportBeanDefinitionRegistrar接口的類,通過BeanDefinition的注冊器注冊實名bean,實現(xiàn)對容器中bean的綁定,例如對現(xiàn)有bean的覆蓋,進而達成不修改源代碼的情況下更換實現(xiàn)的效果。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public String registrarBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 使用元數(shù)據(jù)去做判定,然后再決定要注入哪些bean
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
registry.registerBeanDefinition("user",beanDefinition);
}
}調用處和上面第六種方式差不多。
8.@Import導入BeanDefinitionRegistryPostProcessor接口
導入實現(xiàn)了BeanDefinitionRegistryPostProcessor接口的類,通過BeanDefinition的注冊器注冊實名bean,實現(xiàn)對容器中bean的最終裁定。其在@Import中的加載順序為最后一個加載,可以用來做bean覆蓋的最終裁定。
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注意這里注冊的是BookServiceImpl4
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
registry.registerBeanDefinition("bookService",beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}調用處:
// 按照先后順序加載,但 MyPostProcessor.class 最后才加載
@Import(BookServiceImpl1.class,MyPostProcessor.class, BookServiceImpl.class, MyImportSelector.class)
public class SpringConfig {
}后記
這八種加載方式幾乎可以滿足我們所需要的全部場景了,但一般場景下,我們用的其實也就只有那兩三種,真正掌握這八種加載方式的朋友,肯定是大佬了。
到此這篇關于Spring Bean的8種加載方式總結的文章就介紹到這了,更多相關Spring Bean加載方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于Java數(shù)組實現(xiàn)循環(huán)隊列的兩種方法小結
下面小編就為大家分享一篇基于Java數(shù)組實現(xiàn)循環(huán)隊列的兩種方法小結,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
SpringBoot啟動后自動執(zhí)行初始化任務的五種方法
在 Spring Boot 開發(fā)中,我們經(jīng)常需要在應用啟動后立即執(zhí)行初始化任務,本文將深度解析 ??5 種主流實現(xiàn)方案??,大家可以根據(jù)自己的需求自行選擇2025-04-04
使用Java根據(jù)文件路徑下載zip文件到本地代碼示例
在開發(fā)過程中我們會遇到需要對文件進行壓縮并下載的功能需求,這篇文章主要給大家介紹了關于如何使用Java根據(jù)文件路徑下載zip文件到本地的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-03-03

