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 博客园-所有随笔区 ...
随机推荐
- 海量数据搜索---demo展示百度、谷歌搜索引擎的实现
在我们平常的生活工作中,百度.谷歌这些搜索网站已经成为了我们受教解惑的学校,俗话说得好,“有问题找度娘”.那么百度是如何在海量数据中找到自己需要的数据呢?为什么它搜索的速度如此之快?我们都知道是因为百 ...
- 提升RabbitMQ消费速度的一些实践
RabbitMQ是一个开源的消息中间件,自带管理界面友好.开发语言支持广泛.没有对其它中间件的依赖,而且社区非常活跃,特别适合中小型企业拿来就用.这篇文章主要探讨提升RabbitMQ消费速度的一些方法 ...
- CF - 1106 E Lunar New Year and Red Envelopes DP
题目传送门 题解: 首先要处理出每个时间点会选择哪一个线段. 对于这个问题,可以用multiset去维护信息. 当时间线开始的时候,往mutiset里面插入这个信息,当时间线结束的时候,删除这个信息. ...
- codeforces H. Queries for Number of Palindromes(区间dp)
题目链接:http://codeforces.com/contest/245/problem/H 题意:给出一个字符串还有q个查询,输出每次查询区间内回文串的个数.例如aba->(aba,a,b ...
- yzoj P2349 取数 题解
题意 1到n个自然数中选k个自然数要求两两不相邻,问有多少种方法,模m eg(1 3 5 ) 又是一道打表规律题,正常解法dp可以通过前缀和优化到O(N* K).另外我们可以重新定义F[I,J]表示从 ...
- odoo12从零开始:三、1)创建你的第一个应用模型(module)
前言 以前,我一直都不知道为什么好多框架的入门都是“hello world”开始,当我思前想后我要如何介绍odoo的model.record.template等继承等高级特性时,发现在那之前便需要清楚 ...
- JavaScript漫谈之理解类型操作符typeof
在本文中,将简述JavaScript类型系统和数据类型,以及如何使用typeof操作符执行类型检查. 还讲解了使用typeof操作符进行某些数据类型检查是不完善的,并介绍其他几种类型检查的方法. 更多 ...
- 小白的消费为何被迫升级?-java数据类型的转换
背景 小白最近有点烦恼,原因也很简单,不知道为何?小白的消费不知不觉被迫升级了,请看费用清单: for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; ...
- SqlServer2014怎样还原数据库
场景 在SqlServer2014企业版上怎样进行数据库的还原,首先你得有一个其他数据 的备份文件. 实现 打开cmd,输入sql,打开SqlServer 2014 Management Studio ...
- Visual Studio Code 安装美化合集
这是一个关于VSCode编辑器的各种配置. 你可以在这里找到VSCode 的各种操作,如果这里找不到,请移步官方文档C++ programming with Visual Studio Code以及各 ...