能够扫描到包

@ComponentScan("org.zxp.esclientrhl")

ESCRegistrar类主要实现ImportBeanDefinitionRegistrar接口

@Configuration
public class ESCRegistrar extends AbstractESCRegister implements BeanFactoryAware,ApplicationContextAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

实现下面方法,会在spring启动早期调用生成代理bean

public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
//扫描entity new ESIndexProcessor().scan(annotationMetadata,beanFactory,applicationContext);
//扫描接口
super.registerBeanDefinitions(beanFactory, environment, resourceLoader, annotationMetadata, registry);
}

扫描entity,通过注解配置或者启动目录扫描实体类并托管给Spring管理(和自动代理接口实现类无关,用于自动创建索引)

public void scan(AnnotationMetadata annotationMetadata,BeanFactory beanFactory,ApplicationContext applicationContext){
GetBasePackage getBasePackage = new GetBasePackage(EnableESTools.class);
ESEntityScanner scanner = new ESEntityScanner((BeanDefinitionRegistry) beanFactory);
scanner.setResourceLoader(applicationContext);
scanner.scan(getBasePackage.getEntityPackage(annotationMetadata).toArray(String[]::new));
}

通过getCandidates方法获取继承ESCRepository的接口

public Stream<BeanDefinition> getCandidates(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
ESCRepositoryComponentProvider scanner = new ESCRepositoryComponentProvider(registry);
scanner.setEnvironment(environment);
scanner.setResourceLoader(resourceLoader);
//输入是basepackages,输出是BeanDefinition的Stream
return getBasePackage(annotationMetadata).flatMap(it -> scanner.findCandidateComponents(it).stream());
}

下面这两种scan不同,第一个就是扫描后能被spring识别,第二个是扫描到后返回BeanDefinition

scanner.findCandidateComponents(it)
scanner.scan(getBasePackage.getEntityPackage(annotationMetadata).toArray(String[]::new));

获取继承ESCRepository的接口(BeanDefinition)并遍历

通过BeanDefinitionBuilder给RepositoryFactorySupport传递扫描到接口的类类型、以及要生成代理bean的name

调用beanDefinitionRegistry.registerBeanDefinition(beanName, bd);将RepositoryFactorySupport托管给spring(注意RepositoryFactorySupport并不是目的,是通过RepositoryFactorySupport生成代理bean)

RepositoryFactorySupport的作用就是注册bean

public void registerBeanDefinitions(BeanFactory factory, Environment environment, ResourceLoader resourceLoader, AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
getCandidates(annotationMetadata, registry, environment, resourceLoader).forEach(beanDefinition -> {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RepositoryFactorySupport.class);
String beanClassName = beanDefinition.getBeanClassName();
//传入要实例化的接口
beanDefinitionBuilder.addConstructorArgValue(beanClassName);
//获取bean的定义
BeanDefinition bd = beanDefinitionBuilder.getRawBeanDefinition();
//生成beanname
String beanName = beanClassName.substring(beanClassName.lastIndexOf(".") + );
if(org.zxp.esclientrhl.auto.util.EnableESTools.isPrintregmsg()){
logger.info("generate ESCRegistrar beanClassName:" + beanClassName);
logger.info("generate ESCRegistrar beanName:" + beanName);
}
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) factory;
//注册bean beanName是代理bean的名字 不是RepositoryFactorySupport的名字
beanDefinitionRegistry.registerBeanDefinition(beanName, bd);
});
}

repositoryInterface用于接收传入的接口类类型(准备通过动态代理生成)

通过afterPropertiesSet在RepositoryFactorySupport注册完成后生成并注册真正的代理bean

public class RepositoryFactorySupport<T extends ESCRepository<S, ID>, S, ID> implements ApplicationContextAware, ResourceLoaderAware, InitializingBean, FactoryBean<T>, BeanClassLoaderAware,
BeanFactoryAware, ApplicationEventPublisherAware {
……
private final Class<? extends T> repositoryInterface;
public RepositoryFactorySupport(Class<? extends T> repositoryInterface) {
this.repositoryInterface = repositoryInterface;
}
@Override
public void afterPropertiesSet() {
try {
this.repository = this.getRepository(repositoryInterface);
} catch (Exception e) {
logger.error("ESCRepository proxy create fail !", e);
}
}

生成代理bean的细节注意注释:

public <T> T getRepository(Class<T> repositoryInterface) throws Exception {
SimpleESCRepository target = new SimpleESCRepository(applicationContext);//传入applicationContext的目的是为了能让代理bean在运行时能通过applicationContext获取需要注入的bean
getMetadata(target);//下面单独说,获取对应实体类的类类型以及主键类型
//spring动态代理用法
ProxyFactory result = new ProxyFactory();
result.setTarget(target);
result.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
return result;
}
});
result.setInterfaces(this.repositoryInterface, ESCRepository.class);
T repository = (T) result.getProxy(classLoader);
return repository;
}

只要拿到了接口或者类,是能通过api获得定义接口的泛型名称的(不能获得全限定类名,有类名就可以匹配)

getEntityList()方法通过缓存的entitypaths遍历所有的entity并与之匹配

private void getMetadata(SimpleESCRepository target) throws Exception {
Type[] types = repositoryInterface.getGenericInterfaces();
ParameterizedType parameterized = (ParameterizedType) types[];
//实体类类型名称
String domainClassName = parameterized.getActualTypeArguments()[].getTypeName();
//实体类主键类型名称
String idClassName = parameterized.getActualTypeArguments()[].getTypeName();
if (org.zxp.esclientrhl.auto.util.EnableESTools.isPrintregmsg()) {
logger.info("domainClassName:" + domainClassName + " idClassName:" + idClassName);
}
//按照实体类类型名称匹配实体类类型
List<String> entityList = getEntityList();
for (int i = ; i < entityList.size(); i++) {
if (entityList.get(i).lastIndexOf("." + domainClassName) != -) {
if (target.getDomainClass() == null) {
target.setDomainClass(Class.forName(entityList.get(i)));
break;
} else {
target.setDomainClass(null);
throw new Exception("Entity Overmatched !");
}
}
}
//按照实体类主键类型名称主键类型
Map<String, Class> idTypeMap = getIdTypeMap();
if (idTypeMap.containsKey(idClassName)) {
target.setIdClass(idTypeMap.get(idClassName));
} else {
throw new Exception("Not Supported ID Type !");
}
}

实现了FactoryBean可以将生成的代理bean托管给spring

/**
* 实现了FactoryBean可以将生成的代理bean托管给spring
*
* @return
* @throws Exception
*/
@Override
public T getObject() throws Exception {
return this.repository;
}
/**
* 实现了FactoryBean可以将生成的代理bean托管给spring
*
* @return
*/
@Override
public Class<?> getObjectType() {
return repositoryInterface;
}

Spring只定义接口自动代理接口实现类的更多相关文章

  1. Spring AOP使用整理:自动代理以及AOP命令空间

    三.自动代理的实现 1.使用BeanNameAutoProxyCreator 通过Bean的name属性自动生成代理Bean. <bean class="org.springframe ...

  2. Spring框架学习08——自动代理方式实现AOP

    在传统的基于代理类的AOP实现中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大.解决方案:自动创 ...

  3. Dubbo原理实现之代理接口的定义

    Dubbo有很多的实现采用了代码模式,Dubbo由代理工厂ProxyFactory对象创建代理对象. ProxyFactory接口的定义如下: @SPI("javassist") ...

  4. Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring 非原创[只为记录],原博文地址:https://www.cnblogs.com/ ...

  5. Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring

    上一篇文章我们讲了SqlSessionFactoryBean,通过这个FactoryBean创建SqlSessionFactory并注册进Spring容器,这篇文章我们就讲剩下的部分,通过Mapper ...

  6. Spring Boot(九)Swagger2自动生成接口文档和Mock模拟数据

    一.简介 在当下这个前后端分离的技术趋势下,前端工程师过度依赖后端工程师的接口和数据,给开发带来了两大问题: 问题一.后端接口查看难:要怎么调用?参数怎么传递?有几个参数?参数都代表什么含义? 问题二 ...

  7. MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

    Mybatis在与Spring集成的时候可以配置 MapperFactoryBean来生成Mapper接口的代理. 例如 <bean id="userMapper" clas ...

  8. (转)Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置MapperFactoryBea ...

  9. Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 - 推酷 - 360安全浏览器 7.1

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 时间 2014-02-11 21:08:00  博客园-所有随笔区 ...

随机推荐

  1. Linux下手动安装JDK

    一.删除自带的JDK 查询系统自带JDK rpm -qa | grep java rpm -qa | grep jdk 删除查询出来的文件名 rpm -e --nodeps 文件名 命令执行成功后重新 ...

  2. [翻译] .NET Core 3.0 Preview 9 发布

    原文: Announcing .NET Core 3.0 Preview 9 今天,我们宣布推出 .NET Core 3.0 Preview 9.就像 Preview 8 一样,我们专注于打磨 .NE ...

  3. 利用python定位网页上的元素

    1. 想对网页上的元素进行操作,首先需要定位到元素. 以百度首页为例: 输入以下代码,打开百度首页: # coding = gbk from selenium import webdriver chr ...

  4. poj2186Popular Cows+tarjan缩点+建图

    传送门: 题意: 给出m条关系,表示n个牛中的崇拜关系,这些关系满足传递性.问被所有牛崇拜的牛有几头: 思路: 先利用tarjan缩点,同一个点中的牛肯定就是等价的了,建立新的图,找出其中出度为0的点 ...

  5. POJ 2230 Watchcow 欧拉图

    Watchcow Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 8800   Accepted: 3832   Specia ...

  6. Flask大型项目框架结构理解

    导语:前段时间学习狗书的flask大型项目框架结构的时候有点混乱,到现在也知道是个啥了,想着,把关系理一理,写一篇博客.也方便后来学习的人查阅.以下是我创建项目时候的结构. myproject --- ...

  7. 第二章(Kotlin基础)

    基本要素:函数和变量 函数 函数定义规则 函数通过关键字 fun 用来声明一个函数 参数的类型与函数返回类型写在它的名称后面,这和变量声明一样 函数可以定义在文件的最外层,不一定要把它放在类中 示例: ...

  8. pandas数据分析输出excel产生文本形式存储的百分比数据,如何处理?

    关键词: python.pandas.to_excel.文本形式存储的数据 需求描述: 我用 python pandas 写了数据统计与分析脚本,并把计算结果用 pandas 的 to_excel() ...

  9. Vert.x 学习之MongoDB Client

    Vert.x MongoDB Client 原文档:Vert.x MongoDB Client 组件介绍 您的 Vert.x 应用可以使用 Vert.x MongoDB Client(以下简称客户端) ...

  10. Maven学习归纳(五)——继承与聚合实例讲解

    一.Maven的继承 1.1 什么是继承? 继承:父工程拆分出很多子工程,可以通过父工程,统一管理依赖的版本 1.2 为什么要使用继承呢? 在A.jar 依赖着——>B.jar依赖着——> ...