最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中ImportBeanDefinitionRegistrar源碼和使用方式

 更新時間:2024年11月07日 08:49:45   作者:Dubbo-羅  
Spring容器擴展流程總結(jié):1. 定義Mapper層,2. 通過FactoryBean創(chuàng)建代理對象,3. 使用ImportBeanDefinitionRegistrar修改Bean定義,4. 應(yīng)用自定義注解@LuoyanImportBeanDefinitionRegistrar,5. 配置類中執(zhí)行后置處理器,6. 啟動類中查看源碼,希望對大家有所幫助

ImportBeanDefinitionRegistrar源碼和使用

第一步

定義的Mapper層:

@Mapper
public interface PayMapper {

	@Select("select * from city")
	public List<Map<String,Object>> list();
}

第二步

使用FactoryBean,通過getObject方式,創(chuàng)建一個對象,放入到spring容器中,這里使用代理對象,放入到spring容器中。

public class MyFactoryBean implements FactoryBean, InvocationHandler {
	private Class aClass;

	public MyFactoryBean(Class aClass) {
		this.aClass = aClass;
	}

	@Override
	public Object getObject() throws Exception {
		Class[] interfaces = new Class[]{aClass};
		Object proxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, this);
		return proxyInstance;
	}

	@Override
	public Class<?> getObjectType() {
		return null;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("代理對象,獲取sql語句");
		Method method1 = proxy.getClass().getInterfaces()[0].getMethod(method.getName(), null);
		Select declaredAnnotation = method1.getDeclaredAnnotation(Select.class);
		System.out.println(declaredAnnotation.value()[0]);
		return null;
	}
}

第三步

spring的ImportBeanDefinitionRegistrar處理器,可以對于spring的BeanDefinitionMap進行操作,可以修改Bean的描述,此時還沒有變成對象,這里是把創(chuàng)建注入的類型,創(chuàng)建了構(gòu)造方法中需要的接口,最后取Bean的名字:payServiceTest,一個BeanDefinition描述。

public class MyImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(PayMapper.class);
		AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
		//TODO: 注入類型
		beanDefinition.setBeanClass(MyFactoryBean.class);
		//TODO: 注入構(gòu)造方法
		beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.luoyan.dao.mapper.PayMapper");
		//TODO: 放入到beanDefinitionMap中
		registry.registerBeanDefinition("payServiceTest",beanDefinition);
	}
}

第四步

自定義注解,把@Import(MyImportDefinitionRegistrar.class)注解,MyImportDefinitionRegistrar類放入到sprinig中運行。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MyImportDefinitionRegistrar.class)
public @interface LuoyanImportBeanDefinitionRegistrar {
}

第五步

配置類:需要使用自定義注解@LuoyanImportBeanDefinitionRegistrar,把后置處理器的代碼內(nèi)容執(zhí)行。

@Configuration
@ComponentScan("com.luoyan")
@MapperScan("com.luoyan.dao.mapper")
@LuoyanImportBeanDefinitionRegistrar
public class AppConfig {
	
}

第六步

啟動類:

public static void main(String[] args) {
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
	applicationContext.register(AppConfig.class);
	applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
	applicationContext.refresh();

	PayMapper payServiceTest = (PayMapper) applicationContext.getBean("payServiceTest");
	payServiceTest.list();
}

源碼:

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
		boolean checkForCircularImports) {

	if (importCandidates.isEmpty()) {
		return;
	}

	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
	}
	else {
		this.importStack.push(configClass);
		try {
			/**
			 *
			 * 因為@Import(xxx.class,xxxx.class)這里可以放多個
			 * importCandidates:表示被放在@Import注解中的class類的報名+類名。比如:com.shadow.imports.MyImportSelector.
			 * candidate:就表示com.shadow.imports.MyImportSelector
			 */
			for (SourceClass candidate : importCandidates) {
				/**
				 * ImportSelector,判斷這個MyImportSelector.class是否實現(xiàn)了ImportSelector類
				 */
				if (candidate.isAssignable(ImportSelector.class)) {
					// Candidate class is an ImportSelector -> delegate to it to determine imports
					//得到Import的類loadClass
					Class<?> candidateClass = candidate.loadClass();
					//反射實現(xiàn)一個對象
					//這個instantiateClass()方法底層比較復(fù)雜
					/******************************instantiateClass()這個方法很重要*************************************/
					//new出來當(dāng)前實現(xiàn)了ImportSelector接口的類對象
					ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
							this.environment, this.resourceLoader, this.registry);
					Predicate<String> selectorFilter = selector.getExclusionFilter();
					if (selectorFilter != null) {
						exclusionFilter = exclusionFilter.or(selectorFilter);
					}
					if (selector instanceof DeferredImportSelector) {
						this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
					}
					else {
						/**
						 * 這里重點
						 * 普通類就是加了@component類
						 */
						//得到所有字符串.//循環(huán)引用這類用的是遞歸,就是說你配置類上有了@Impont,但是你實現(xiàn)了ImportSelector類的類上還是有@Impont
						//TODO: selector表示你實現(xiàn)ImportSelector接口的類的對象.
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						//把名字傳入得到importSourceClasses,把這個類添加到annotation這個變量中去了asSourceClasses()這個方法.
						//importClassNames=com.shadow.service.TestService3
						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
						//然后又進行循環(huán)判斷了.繼續(xù)調(diào)用processImports()方法,剛剛進來的時候也是這個方法.
						//遞歸,這里第二次調(diào)用processImports.
						//如果是一個普通類,會進else
						processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
					}
				}
				/**
				 * ImportBeanDefinitionRegistrar實現(xiàn)了這個接口的類放到了addImportBeanDefinitionRegistrar()方法
				 * importBeanDefinitionRegistrarsMap當(dāng)中去了。
				 * 而
				 * 實現(xiàn)ImportSelector接口的類卻放到了configurationClassesMap當(dāng)中去了。
				 * 所以在解析這些類的時候使用了不同的方法存放this.reader.loadBeanDefinitions(configClasses);
				 *
				 */
				else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
					// Candidate class is an ImportBeanDefinitionRegistrar ->
					// delegate to it to register additional com.luoyan.bean definitions
					Class<?> candidateClass = candidate.loadClass();
					ImportBeanDefinitionRegistrar registrar =
							ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
									this.environment, this.resourceLoader, this.registry);
					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}
				/**
				 * 普通的
				 */
				else {
					// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
					// process it as an @Configuration class
					/**
					 * 否則,加入到importStack后調(diào)用processConfigurationClass進行處理
					 * processConfiguration里面主要就是把類放到configrationClasses
					 * 可以看到普通類再掃描出來的時候就被注冊了
					 * 如果importSelector,回顯放到configurationClasses后面進行注冊
					 * 注意這里的processConfigurationClass前面已經(jīng)解釋過這個方法了
					 */
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					//processConfigurationClass()這個方法,是繼續(xù)判斷當(dāng)前普通類是否加了@Configuration注解
					//candidate.asConfigClass(configClass)這個方法,是把通過@Import注解得到的類,執(zhí)行方法后,得到返回回來的類字符串,反射出來的類.放入到this.importedBy.add(importedBy);集合中
					//真正導(dǎo)入到spring的BeanDefinitionMap中的時候使用到
					processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
				}
			}
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(
					"Failed to process import candidates for configuration class [" +
					configClass.getMetadata().getClassName() + "]", ex);
		}
		finally {
			this.importStack.pop();
		}
	}
}

源碼:

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
	registrars.forEach((registrar, metadata) ->
			/**
			 * 這個registrar.registerBeanDefinitions就是自己實現(xiàn)了ImportBeanDefinitionRegistrar接口
			 * 的類中邏輯,注冊到beanMap中的方法
			 */
			registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java語言實現(xiàn)簡單FTP軟件 FTP本地文件管理模塊實現(xiàn)(9)

    Java語言實現(xiàn)簡單FTP軟件 FTP本地文件管理模塊實現(xiàn)(9)

    這篇文章主要為大家詳細介紹了Java語言實現(xiàn)簡單FTP軟件,F(xiàn)TP本地文件管理模塊的實現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 使用Java和Redis實現(xiàn)高效的短信防轟炸方案

    使用Java和Redis實現(xiàn)高效的短信防轟炸方案

    在當(dāng)今互聯(lián)網(wǎng)應(yīng)用中,短信驗證碼已成為身份驗證的重要手段,然而,這也帶來了"短信轟炸"的安全風(fēng)險?-?惡意用戶利用程序自動化發(fā)送大量短信請求,導(dǎo)致用戶被騷擾和企業(yè)短信成本激增,本文將詳細介紹如何使用Java和Redis實現(xiàn)高效的短信防轟炸解決方案,需要的朋友可以參考下
    2025-04-04
  • Spring3整合MyBatis實現(xiàn)分頁查詢和搜索功能

    Spring3整合MyBatis實現(xiàn)分頁查詢和搜索功能

    本文詳細介紹了如何在SpringBoot和MyBatis框架下實現(xiàn)分頁查詢和搜索功能,結(jié)合Vue和ElementUI構(gòu)建前端界面,通過配置PageHelper插件,編寫動態(tài)SQL,封裝統(tǒng)一的請求工具,本文結(jié)合示例代碼講解的非常詳細,感興趣的朋友一起看看吧
    2026-01-01
  • java中synchronized鎖的升級過程

    java中synchronized鎖的升級過程

    這篇文章主要介紹了java中synchronized鎖的升級過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java利用WatchService監(jiān)聽文件變化示例

    Java利用WatchService監(jiān)聽文件變化示例

    本篇文章主要介紹了Java利用WatchService監(jiān)聽文件變化示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 基于springcloud異步線程池、高并發(fā)請求feign的解決方案

    基于springcloud異步線程池、高并發(fā)請求feign的解決方案

    這篇文章主要介紹了基于springcloud異步線程池、高并發(fā)請求feign的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 在Spring Boot中集成RabbitMQ的實戰(zhàn)記錄

    在Spring Boot中集成RabbitMQ的實戰(zhàn)記錄

    本文介紹SpringBoot集成RabbitMQ的步驟,涵蓋配置連接、消息發(fā)送與接收,并對比兩種定義Exchange與隊列的方式:手動聲明(適合復(fù)雜路由)和注解綁定(適合快速開發(fā)),感興趣的朋友跟隨小編一起看看吧
    2025-06-06
  • springboot整合mybatis分頁攔截器的問題小結(jié)

    springboot整合mybatis分頁攔截器的問題小結(jié)

    springboot整合mybatis分頁攔截器,分頁攔截實際上就是獲取sql后將sql拼接limit,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-07-07
  • 詳解Spring Security 中的四種權(quán)限控制方式

    詳解Spring Security 中的四種權(quán)限控制方式

    這篇文章主要介紹了詳解Spring Security 中的四種權(quán)限控制方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • SpringBoot傳遞單一參數(shù)時@RequestParam和@RequestBody的區(qū)別小結(jié)

    SpringBoot傳遞單一參數(shù)時@RequestParam和@RequestBody的區(qū)別小結(jié)

    用SpringBoot框架做項目時,經(jīng)常需要前端給后端傳遞參數(shù),本文主要介紹了SpringBoot傳遞單一參數(shù)時@RequestParam和@RequestBody的區(qū)別,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08

最新評論

万源市| 改则县| 鄢陵县| 林周县| 乳山市| 广德县| 恩施市| 龙川县| 临洮县| 金昌市| 偏关县| 陵川县| 和林格尔县| 海城市| 海城市| 莱芜市| 兴文县| 茶陵县| 卓资县| 镇江市| 五台县| 噶尔县| 铜川市| 遂宁市| 尉氏县| 洪江市| 固始县| 广元市| 松溪县| 灵璧县| 都安| 宁海县| 榆林市| 三门峡市| 宁蒗| 阿坝| 商丘市| 邓州市| 灵丘县| 吐鲁番市| 南投县|