当前位置: 首页 > news >正文

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));
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • idea使用free流程,2024idea、2023idea都可以安装免费使用
  • 【Scene Transformer】scene transformer论文阅读笔记
  • jupyter支持跨机器远程访问
  • C语言——数组和排序
  • 赛蓝企业管理系统 AuthToken/Index 身份认证绕过漏洞复现
  • Redis1
  • vscode的json文件解析
  • Halcon学习之create_shape_model案例分解
  • TiDB系列之:使用Flink TiDB CDC Connector采集数据
  • Java中的Map(如果想知道Java中有关Map的知识点,那么只看这一篇就足够了!)
  • 【过题记录】 8.3
  • CTFHUB-SSRF-DNS重绑定 Bypass
  • [米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-01 以太网协议介绍
  • ai web 1.0靶机漏洞渗透详解
  • 搭建个人的金融系统-----第一章,数据库设计
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Java读取Properties文件的六种方法
  • JSONP原理
  • Js基础——数据类型之Null和Undefined
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • opencv python Meanshift 和 Camshift
  • Tornado学习笔记(1)
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • Vue学习第二天
  • 二维平面内的碰撞检测【一】
  • 前嗅ForeSpider中数据浏览界面介绍
  • 推荐一个React的管理后台框架
  • 为什么要用IPython/Jupyter?
  • ​Python 3 新特性:类型注解
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #pragma once与条件编译
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (7) cmake 编译C++程序(二)
  • (苍穹外卖)day03菜品管理
  • (动态规划)5. 最长回文子串 java解决
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (十六)视图变换 正交投影 透视投影
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • ***利用Ms05002溢出找“肉鸡
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • @Bean有哪些属性
  • [ C++ ] STL---stack与queue
  • [ solr入门 ] - 利用solrJ进行检索
  • []error LNK2001: unresolved external symbol _m
  • []指针
  • [1525]字符统计2 (哈希)SDUT
  • [2015][note]基于薄向列液晶层的可调谐THz fishnet超材料快速开关——
  • [20170728]oracle保留字.txt
  • [240607] Jina AI 发布多模态嵌入模型 | PHP 曝新漏洞 | TypeScript 5.5 RC 发布公告