能够扫描到包

@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. CCPC 网络赛

    array 做法 比赛中的表现..... 已经无法言语形容了. 题意是,查询前缀中大于某个数字的 mex,在线. 一下把问题转化为偏序问题.... 带修主席树?????这下好,直接一箭穿心,武将被移除 ...

  2. I don't Blame You that You don't Understand Me

    I don't Blame You that You don't Understand Me Every one has a dead corner in himself, with no entry ...

  3. BigDecimal转String

    代码: public static void main(String[] args) { // 浮点数的打印 System.out.println(new BigDecimal("10000 ...

  4. JSP学习笔记(6)—— 自定义MVC框架

    仿照SpringMVC,实现一个轻量级MVC框架,知识涉及到了反射机制.注解的使用和一些第三方工具包的使用 思路 主要的总体流程如下图所示 和之前一样,我们定义了一个DispatchServlet,用 ...

  5. Xpath定位和CssSelector定位的区别

    1.Xpath基本语法: (1)"/":从根节点选取,下级节点 (2)"//":任意节点选取 (3)"*":任意标签选取 (4)" ...

  6. ubuntu16.4 环境移植ubuntu到zynqMp_zcu102

    安装petalinux 下载petalinux https://www.xilinx.com/support/download 下载 zcu102 ZCU102 BSP 安装petaLinux 把sh ...

  7. centos7上部署dubbo管理控制台dubbo-admin

    centos7上部署dubbo管理控制台dubbo-admin 1 准备工作 服务器:系统centos7, 内存4G, 存储60G, ip 192.168.159.128 软件环境: 安装有jdk1. ...

  8. 学生管理系统——ArrayList集合

    此学生管理系统利用了集合ArrayList实现了对学生的增删改查:利用数组中的方法实现分数排序:运用String类的equals实现登录功能的字符串比较. 管理员类: package data; pu ...

  9. 第1次作业:使用Packet Tracer分析HTTP数据包

    个人信息:      •  姓名:李微微       •  班级:计算1811       •  学号:201821121001 一.摘要 本文将会描述使用Packet Tracer工具用到的网络结构 ...

  10. MYSQL之概念基础篇

    1数据库概述 1.1 数据管理技术的产生和发展 数据库技术是应数据库管理任务的需要而产生的.20世纪50年代中期以前,计算机主要是用于科学计算.当时的硬件状况是,外存只有纸带.卡片.磁带,没有磁盘等可 ...