亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring中ImportBeanDefinitionRegistrar源碼和使用方式

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

ImportBeanDefinitionRegistrar源碼和使用

第一步

定義的Mapper層:

@Mapper
public interface PayMapper {

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

第二步

使用FactoryBean,通過getObject方式,創(chuàng)建一個(gè)對象,放入到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進(jìn)行操作,可以修改Bean的描述,此時(shí)還沒有變成對象,這里是把創(chuàng)建注入的類型,創(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: 注入類型
		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中運(yùn)行。

@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 {
	
}

第六步

啟動(dòng)類:

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類的報(bào)名+類名。比如:com.shadow.imports.MyImportSelector.
			 * candidate:就表示com.shadow.imports.MyImportSelector
			 */
			for (SourceClass candidate : importCandidates) {
				/**
				 * ImportSelector,判斷這個(gè)MyImportSelector.class是否實(shí)現(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();
					//反射實(shí)現(xiàn)一個(gè)對象
					//這個(gè)instantiateClass()方法底層比較復(fù)雜
					/******************************instantiateClass()這個(gè)方法很重要*************************************/
					//new出來當(dāng)前實(shí)現(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 {
						/**
						 * 這里重點(diǎn)
						 * 普通類就是加了@component類
						 */
						//得到所有字符串.//循環(huán)引用這類用的是遞歸,就是說你配置類上有了@Impont,但是你實(shí)現(xiàn)了ImportSelector類的類上還是有@Impont
						//TODO: selector表示你實(shí)現(xiàn)ImportSelector接口的類的對象.
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						//把名字傳入得到importSourceClasses,把這個(gè)類添加到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)來的時(shí)候也是這個(gè)方法.
						//遞歸,這里第二次調(diào)用processImports.
						//如果是一個(gè)普通類,會進(jìn)else
						processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
					}
				}
				/**
				 * ImportBeanDefinitionRegistrar實(shí)現(xiàn)了這個(gè)接口的類放到了addImportBeanDefinitionRegistrar()方法
				 * importBeanDefinitionRegistrarsMap當(dāng)中去了。
				 * 而
				 * 實(shí)現(xiàn)ImportSelector接口的類卻放到了configurationClassesMap當(dāng)中去了。
				 * 所以在解析這些類的時(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里面主要就是把類放到configrationClasses
					 * 可以看到普通類再掃描出來的時(shí)候就被注冊了
					 * 如果importSelector,回顯放到configurationClasses后面進(jìn)行注冊
					 * 注意這里的processConfigurationClass前面已經(jīng)解釋過這個(gè)方法了
					 */
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					//processConfigurationClass()這個(gè)方法,是繼續(xù)判斷當(dāng)前普通類是否加了@Configuration注解
					//candidate.asConfigClass(configClass)這個(gè)方法,是把通過@Import注解得到的類,執(zhí)行方法后,得到返回回來的類字符串,反射出來的類.放入到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接口
			 * 的類中邏輯,注冊到beanMap中的方法
			 */
			registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}

總結(jié)

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

相關(guān)文章

  • Spring Boot 非web應(yīng)用程序的實(shí)現(xiàn)

    Spring Boot 非web應(yīng)用程序的實(shí)現(xiàn)

    SpringBoot框架中,要?jiǎng)?chuàng)建一個(gè)非Web應(yīng)用程序(純 Java 程序),有兩種方式,下面就來介紹一下,感興趣的可以來了解一下
    2025-03-03
  • struts2實(shí)現(xiàn)簡單文件下載功能

    struts2實(shí)現(xiàn)簡單文件下載功能

    這篇文章主要為大家詳細(xì)介紹了struts2實(shí)現(xiàn)簡單文件下載功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • java如何將list中的某個(gè)元素移動(dòng)位置

    java如何將list中的某個(gè)元素移動(dòng)位置

    在Java編程中我們經(jīng)常會使用List數(shù)據(jù)結(jié)構(gòu)來存儲一組元素,下面這篇文章主要給大家介紹了關(guān)于java如何將list中的某個(gè)元素移動(dòng)位置的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-05-05
  • Spring Boot循環(huán)依賴的癥狀和解決方案

    Spring Boot循環(huán)依賴的癥狀和解決方案

    循環(huán)依賴是指在Spring Boot 應(yīng)用程序中,兩個(gè)或多個(gè)類之間存在彼此依賴的情況,形成一個(gè)循環(huán)依賴鏈。這篇文章主要介紹了SpringBoot循環(huán)依賴的癥狀和解決方法
    2023-04-04
  • Servlet中配置和使用過濾器的步驟記錄

    Servlet中配置和使用過濾器的步驟記錄

    這篇文章主要介紹了在Servlet中配置和使用過濾器的方法,包括創(chuàng)建過濾器類、配置過濾器以及在Web應(yīng)用中使用過濾器等步驟,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-01-01
  • 一文帶你探究Spring中Bean的線程安全性問題

    一文帶你探究Spring中Bean的線程安全性問題

    很多人都想spring中的bean是線程安全的嗎?本文將帶你探究Spring中Bean的線程安全性問題,感興趣的同學(xué)可以參考閱讀下
    2023-05-05
  • Java加解密技術(shù)系列之RSA詳解

    Java加解密技術(shù)系列之RSA詳解

    出于安全考慮,網(wǎng)絡(luò)的傳輸中經(jīng)常對傳輸數(shù)據(jù)做加密和編碼處理,本篇文章主要介紹Java加解密技術(shù)系列之RSA詳解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2016-10-10
  • Java并發(fā)編程示例(二):獲取和設(shè)置線程信息

    Java并發(fā)編程示例(二):獲取和設(shè)置線程信息

    這篇文章主要介紹了Java并發(fā)編程示例(二):獲取和設(shè)置線程信息,本文是系列文章的第二篇,本文著重講解Thread類的幾個(gè)重要屬性,需要的朋友可以參考下
    2014-12-12
  • 基于獲取JAVA路徑,包括CLASSPATH外的路徑的方法詳解

    基于獲取JAVA路徑,包括CLASSPATH外的路徑的方法詳解

    本篇文章是對獲取JAVA路徑,包括CLASSPATH外的路徑的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • Java 替換空格

    Java 替換空格

    本文主要介紹了Java中替換空格的方法。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01

最新評論