Spring中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;}@Overridepublic Object getObject() throws Exception {Class[] interfaces = new Class[]{aClass};Object proxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, this);return proxyInstance;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic 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 {@Overridepublic 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的类loadClassClass<?> candidateClass = candidate.loadClass();//反射实现一个对象//这个instantiateClass()方法底层比较复杂/******************************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);}else {/*** 这里重点* 普通类就是加了@component类*///得到所有字符串.//循环引用这类用的是递归,就是说你配置类上有了@Impont,但是你实现了ImportSelector类的类上还是有@Impont//TODO: selector表示你实现ImportSelector接口的类的对象.String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());//把名字传入得到importSourceClasses,把这个类添加到annotation这个变量中去了asSourceClasses()这个方法.//importClassNames=com.shadow.service.TestService3Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);//然后又进行循环判断了.继续调用processImports()方法,刚刚进来的时候也是这个方法.//递归,这里第二次调用processImports.//如果是一个普通类,会进elseprocessImports(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 definitionsClass<?> 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()这个方法,是继续判断当前普通类是否加了@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) ->/*** 这个registrar.registerBeanDefinitions就是自己实现了ImportBeanDefinitionRegistrar接口* 的类中逻辑,注册到beanMap中的方法*/registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}