开发者

Spring中ImportBeanDefinitionRegistrar源码和使用方式

目录
  • ImportBeanDefinitionRegistrar源码和使用
    • 第一步
    • 第二步
    • 第三步
    • 第四步
    • 第五步
    • 第六步
  • 总结

    ImportBeanDefinitionRegistrar源码和使用

    第一步

    定义的Mapper层:

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

    第二步

    使用FactoryBean,通过getObject方式,创建一个对象,放入到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的描述,此时还没有变成对象,这里是把创建注入的类型,创建了构造方法中需要的接口,最后取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: 注入构造方法
    		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,把后置处理器的代码内容执行。

    @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是否实现了ImportSelector类
    				 */
    				if (candidate.isAssignable(ImportSelector.class)) {
    					// Candidate class is an ImportSelector -> delegate to it to determine imports
    					//得到Import的类loadClass
    					Class<?> candidateClass = candidate.loadClass();
    					//反射实现一个对象
    					//这个instantiafVdAXUeteClass()方法底层比较复杂
    					/******************************instantiateClass()这个方法很重要*************************************/
    					//new出来当前实现了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);
    		android			}
    					else {
    						/**
    						 * 这里重点
    						 * 普通类就是加了@component类
    						 */
    						//得到所有字符串.//循环引用这类用的是递归,就是说你配置类上有了@Impont,但是你实现了ImportSelector类的类上还是有@Impont
    						//TODO: selector表示你实现ImportSelector接口的类的对象.
    						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
    						//把名字传入得到importSourceClasses,把这个类添加到annotation这个变量中去了asSourceClasses()这个方法.
    						//importClassNames=com.shadow.service.TestService3
    						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
    						//然后又进行循环判断了.继续调用processImports()方法,刚刚进来的时候也是这个方法.
    						//递归,这里第二次调用processImports.
    						//如果是一个普通类,会进else
    						processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
    					}
    				}
    				/**
    				 * ImportBeanDefinitionRegistrar实现了这个接口的类放到了addImportBeanDefinitionRegistrar()方法
    				 * importBeanDefinitionRegistrarsMap当中去了。
    				 * 而
    				 * 实现ImportSelector接口的类却放到了configurationClassesMap当中去了。
    				 * 所以在解析这些类的时候使用了不同的方法存放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后调用processConfigurationClass进行处理
    					 * processConfiguration里面主要就是把类放到configrationClasses
    					 * 可以看到普通类再扫描出来的时候就被注册了
    					 * 如果importSelector,回显放到configurationClasses后面进行注册
    					 * 注意这里的processConfigurationClass前面已经解释过这个方法了
    					 */
    					this.importStack.registerImport(
    							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
    					//processConfigurationClass()这个方法,是继续判断当前普通类是否android加了@Configuration注解
    					//candidate.asConfigClass(configClass)这个方法,是把通过@Import注解得到的类,执行方法后,得到返回回来的类字符串,反射出来的类.放入到this.importedBy.add(importedBy);集合中
    					//真正导入到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) ->
    	android		/**
    			 * 这个registrar.registerBeanDefinitions就是自己实现了ImportBeanDefinitionRegistrar接口
    			 * 的类中逻辑,注册到beanMap中的方法
    			 */
    			registrar.registerBeanDefinitions(metadata, this.registry, this.imhttp://www.devze.comportBeanNameGenerator));
    }

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜