Spring只定义接口自动代理接口实现类
能够扫描到包
@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只定义接口自动代理接口实现类的更多相关文章
- Spring AOP使用整理:自动代理以及AOP命令空间
三.自动代理的实现 1.使用BeanNameAutoProxyCreator 通过Bean的name属性自动生成代理Bean. <bean class="org.springframe ...
- Spring框架学习08——自动代理方式实现AOP
在传统的基于代理类的AOP实现中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大.解决方案:自动创 ...
- Dubbo原理实现之代理接口的定义
Dubbo有很多的实现采用了代码模式,Dubbo由代理工厂ProxyFactory对象创建代理对象. ProxyFactory接口的定义如下: @SPI("javassist") ...
- Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring 非原创[只为记录],原博文地址:https://www.cnblogs.com/ ...
- Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring
上一篇文章我们讲了SqlSessionFactoryBean,通过这个FactoryBean创建SqlSessionFactory并注册进Spring容器,这篇文章我们就讲剩下的部分,通过Mapper ...
- Spring Boot(九)Swagger2自动生成接口文档和Mock模拟数据
一.简介 在当下这个前后端分离的技术趋势下,前端工程师过度依赖后端工程师的接口和数据,给开发带来了两大问题: 问题一.后端接口查看难:要怎么调用?参数怎么传递?有几个参数?参数都代表什么含义? 问题二 ...
- MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
Mybatis在与Spring集成的时候可以配置 MapperFactoryBean来生成Mapper接口的代理. 例如 <bean id="userMapper" clas ...
- (转)Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置MapperFactoryBea ...
- Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 - 推酷 - 360安全浏览器 7.1
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring - 大新博客 时间 2014-02-11 21:08:00 博客园-所有随笔区 ...
随机推荐
- 懒人必备:.NetCore快速搭建ELK分布式日志中心
该篇内容由个人博客点击跳转同步更新!转载请注明出处! 前言 ELK是什么 它是一个分布式日志解决方案,是Logstash.Elastaicsearch.Kibana的缩写,可用于从不同的服务中收集日志 ...
- redis 原理系列之--字符串存储的实现原理(1)
背景 redis功能强大,几乎已经成了现代大中型服务必备的缓存技术了. 除了十分给力的缓存功能,redis当做消息队列,数据库也有着不错的表现. 我们都知道,redis 有五种数据类型,string, ...
- 2019DX#2
Solved Pro.ID Title Ratio(Accepted / Submitted) 1001 Another Chess Problem 8.33%(1/12) 1002 Beau ...
- 一篇文章看懂JS执行上下文
壹 ❀ 引 我们都知道,JS代码的执行顺序总是与代码先后顺序有所差异,当先抛开异步问题你会发现就算是同步代码,它的执行也与你的预期不一致,比如: function f1() { console.lo ...
- Netty源码分析 (七)----- read过程 源码分析
在上一篇文章中,我们分析了processSelectedKey这个方法中的accept过程,本文将分析一下work线程中的read过程. private static void processSele ...
- 【LeetCode】75-颜色分类
题目描述 给定一个包含红色.白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色.白色.蓝色顺序排列. 此题中,我们使用整数 0. 1 和 2 分别表示红色.白色 ...
- Java SSM三端分离开发在线教育平台实战视频教程
目录: 1-01——在线网校实战课程介绍1-02——Eclipse.Maven.JDK介绍1-03——Maven构建Project1-04——新浪SAE介绍2-01——平台业务结构概览2-02——平台 ...
- 浅谈独立特征(independent features)、潜在特征(underlying features)提取、以及它们在网络安全中的应用
1. 关于特征提取 0x1:什么是特征提取 特征提取研究的主要问题是,如何在数据集未明确表示结果的前提下,从中提取出重要的潜在特征来.和无监督聚类一样,特征提取算法的目的不是为了预测,而是要尝试对数据 ...
- Vue中的slot(占坑,预留位置)
Vue中的slot(占坑,预留位置) 子模板不使用slot 子模板使用slot 子模板使用使用name属性,且传递data 文件名:Slots.vue //slot组件 <template> ...
- Android-WebView支持input file启用相机/选取照片
webview要调起input-file拍照或者选取文件功能,可以在webview.setWebChromeClient方法中重写指定的方法,来拦截webview的input事件,并做我们相应的操作. ...