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

Spring中ImportBeanDefinitionRegistrar源碼和使用方式

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

ImportBeanDefinitionRegistrar源碼和使用

第一步

定義的Mapper層:

@Mapper
public interface PayMapper {

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

第二步

使用FactoryBean,通過(guò)getObject方式,創(chuàng)建一個(gè)對(duì)象,放入到spring容器中,這里使用代理對(duì)象,放入到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("代理對(duì)象,獲取sql語(yǔ)句");
		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處理器,可以對(duì)于spring的BeanDefinitionMap進(jìn)行操作,可以修改Bean的描述,此時(shí)還沒(méi)有變成對(duì)象,這里是把創(chuàng)建注入的類(lèi)型,創(chuàng)建了構(gòu)造方法中需要的接口,最后取Bean的名字:payServiceTest,一個(gè)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: 注入類(lèi)型
		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類(lèi)放入到sprinig中運(yùn)行。

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

第五步

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

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

第六步

啟動(dòng)類(lèi):

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 {
			/**
			 *
			 * 因?yàn)锧Import(xxx.class,xxxx.class)這里可以放多個(gè)
			 * importCandidates:表示被放在@Import注解中的class類(lèi)的報(bào)名+類(lèi)名。比如:com.shadow.imports.MyImportSelector.
			 * candidate:就表示com.shadow.imports.MyImportSelector
			 */
			for (SourceClass candidate : importCandidates) {
				/**
				 * ImportSelector,判斷這個(gè)MyImportSelector.class是否實(shí)現(xiàn)了ImportSelector類(lèi)
				 */
				if (candidate.isAssignable(ImportSelector.class)) {
					// Candidate class is an ImportSelector -> delegate to it to determine imports
					//得到Import的類(lèi)loadClass
					Class<?> candidateClass = candidate.loadClass();
					//反射實(shí)現(xiàn)一個(gè)對(duì)象
					//這個(gè)instantiateClass()方法底層比較復(fù)雜
					/******************************instantiateClass()這個(gè)方法很重要*************************************/
					//new出來(lái)當(dāng)前實(shí)現(xiàn)了ImportSelector接口的類(lèi)對(duì)象
					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 {
						/**
						 * 這里重點(diǎn)
						 * 普通類(lèi)就是加了@component類(lèi)
						 */
						//得到所有字符串.//循環(huán)引用這類(lèi)用的是遞歸,就是說(shuō)你配置類(lèi)上有了@Impont,但是你實(shí)現(xiàn)了ImportSelector類(lèi)的類(lèi)上還是有@Impont
						//TODO: selector表示你實(shí)現(xiàn)ImportSelector接口的類(lèi)的對(duì)象.
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						//把名字傳入得到importSourceClasses,把這個(gè)類(lèi)添加到annotation這個(gè)變量中去了asSourceClasses()這個(gè)方法.
						//importClassNames=com.shadow.service.TestService3
						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
						//然后又進(jìn)行循環(huán)判斷了.繼續(xù)調(diào)用processImports()方法,剛剛進(jìn)來(lái)的時(shí)候也是這個(gè)方法.
						//遞歸,這里第二次調(diào)用processImports.
						//如果是一個(gè)普通類(lèi),會(huì)進(jìn)else
						processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
					}
				}
				/**
				 * ImportBeanDefinitionRegistrar實(shí)現(xiàn)了這個(gè)接口的類(lèi)放到了addImportBeanDefinitionRegistrar()方法
				 * importBeanDefinitionRegistrarsMap當(dāng)中去了。
				 * 而
				 * 實(shí)現(xiàn)ImportSelector接口的類(lèi)卻放到了configurationClassesMap當(dāng)中去了。
				 * 所以在解析這些類(lèi)的時(shí)候使用了不同的方法存放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進(jìn)行處理
					 * processConfiguration里面主要就是把類(lèi)放到configrationClasses
					 * 可以看到普通類(lèi)再掃描出來(lái)的時(shí)候就被注冊(cè)了
					 * 如果importSelector,回顯放到configurationClasses后面進(jìn)行注冊(cè)
					 * 注意這里的processConfigurationClass前面已經(jīng)解釋過(guò)這個(gè)方法了
					 */
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					//processConfigurationClass()這個(gè)方法,是繼續(xù)判斷當(dāng)前普通類(lèi)是否加了@Configuration注解
					//candidate.asConfigClass(configClass)這個(gè)方法,是把通過(guò)@Import注解得到的類(lèi),執(zhí)行方法后,得到返回回來(lái)的類(lèi)字符串,反射出來(lái)的類(lèi).放入到this.importedBy.add(importedBy);集合中
					//真正導(dǎo)入到spring的BeanDefinitionMap中的時(shí)候使用到
					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) ->
			/**
			 * 這個(gè)registrar.registerBeanDefinitions就是自己實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口
			 * 的類(lèi)中邏輯,注冊(cè)到beanMap中的方法
			 */
			registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

總結(jié)

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

相關(guān)文章

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

    Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件 FTP本地文件管理模塊實(shí)現(xiàn)(9)

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

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

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

    Spring3整合MyBatis實(shí)現(xiàn)分頁(yè)查詢(xún)和搜索功能

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

    java中synchronized鎖的升級(jí)過(guò)程

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評(píng)論

大理市| 建昌县| 乌鲁木齐市| 开封市| 绥化市| 浪卡子县| 读书| 漳浦县| 历史| 德兴市| 红河县| 阿坝县| 黔东| 剑川县| 富宁县| 潢川县| 星子县| 临高县| 璧山县| 佳木斯市| 沂源县| 汉寿县| 宁安市| 绵阳市| 任丘市| 溧水县| 宾川县| 齐齐哈尔市| 迭部县| 虎林市| 东港市| 永嘉县| 湘西| 北川| 吉安县| 西平县| 郯城县| 方正县| 泰宁县| 新河县| 习水县|