为什么spring 被@Repository注解标识注入后是代理类
背景
今天发现一个奇怪的问题,有一个类是用的@Repository注解标识注入的,并且这个类并没有配置任何带代理和aop配置。但是得到的这个类不是一个原生类,而是一个代理类,如果换成了Component注解这时候得到的类就是原生类 。下面分别演示下这两种情况。
先用@Repository注入得到的class是下面的:
class com.workit.demo.service.ServiceA$$EnhancerBySpringCGLIB$$4ee00fa9
然后@Component注入得到的class是下面的:
class com.workit.demo.service.ServiceA
下面我们就带着这个疑问为什么会出现这样的情况吧。我们可以根据spring ioc创建bean的源码调试最终确认是在哪里为其生成代理类的
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization这个方法如果看过spring ioc源码的人应该都比较熟悉。
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
getBeanPostProcessors() 总共有12个beanProcessors
result = {CopyOnWriteArrayList@4450} size = 12
0 = {ApplicationContextAwareProcessor@4480}
1 = {WebApplicationContextServletContextAwareProcessor@4481}
2 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@4482}
3 = {PostProcessorRegistrationDelegate$BeanPostProcessorChecker@4483}
4 = {ConfigurationPropertiesBindingPostProcessor@4484}
5 = {MethodValidationPostProcessor@4391} "proxyTargetClass=true; optimize=false; opaque=false; exposeProxy=false; frozen=false"
6 = {PersistenceExceptionTranslationPostProcessor@4485} "proxyTargetClass=true; optimize=false; opaque=false; exposeProxy=false; frozen=false"
7 = {WebServerFactoryCustomizerBeanPostProcessor@4486}
8 = {ErrorPageRegistrarBeanPostProcessor@4487}
9 = {CommonAnnotationBeanPostProcessor@4488}
10 = {AutowiredAnnotationBeanPostProcessor@4489}
11 = {ApplicationListenerDetector@4490}
经过断点调试我们最终发现为其生成代理类的是这个PersistenceExceptionTranslationPostProcessor。进入这个类的postProcessAfterInitialization方法,由于PersistenceExceptionTranslationPostProcessor继承了AbstractAdvisingBeanPostProcessor所以调用的是AbstractAdvisingBeanPostProcessor的postProcessAfterInitialization方法创建代理类的方法就是
if (this.isEligible(bean, beanName)) {
ProxyFactory proxyFactory = this.prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
this.evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
this.customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(this.getProxyClassLoader());
至于为什么如果有@Repository这个方法isEligible就会返回true的话,是因为isEligible方法里面会去判断当前类上面是否有注解Repository,如果有,spring则为其创建一个代理类。
总结
spring项目中如果引用了spring-tx的依赖,并且类上面被打上@Repository注解的类,spring都会被为其生存一个代理类。为何会生成一个代理类,主要的原因在PersistenceExceptionTranslationPostProcessor这个类,这个类是位于spring-tx下面的。如果我们希望得到一个原生类的话要么不引入spring-tx模块,或者不在类上面用Repository修饰注入。
为什么spring 被@Repository注解标识注入后是代理类的更多相关文章
- Spring之基于注解的注入
对于DI使用注解,将不再需要在Spring配置文件中声明Bean实例.Spring中使用注解,需要在原有Spring运行环境基础上再做一些改变,完成以下三个步骤. (1)导入AOP的Jar包.因为注解 ...
- Ibatis,Spring整合(注解方式注入)
applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xm ...
- Spring中的注解配置-注入bean
在使用Spring框架中@Autowired标签时默认情况下使用 @Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个.当找不到一个匹配的 Bean ...
- Spring中@Autowired 注解的注入规则
默认根据类型,匹配不到则根据bean名字 1.声明一个service接口 public interface HelloService { void sayHello(); } 2.service接口的 ...
- intellij安装lombok插件,解决注解@Slf4j注入后找不到变量log
1.进入设置 2.搜索插件 3.安装
- Spring MVC常用注解
cp by http://www.cnblogs.com/leskang/p/5445698.html 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由Di ...
- spring mvc常用注解标签
@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model , ...
- spring : springmvc常用注解标签详解(转)
新的项目,新的学习,好久没用这些注解了,同时在学习使用shiro ,lucene 等等.在网上找了些博文,感谢作者的总结和分享. 欢迎交流,言归正传: 1.@Controller 在SpringMVC ...
- Spring MVC学习总结(2)——Spring MVC常用注解说明
使用Spring MVC的注解及其用法和其它相关知识来实现控制器功能. 02 之前在使用Struts2实现MVC的注解时,是借助struts2-convention这个插件,如今我们使 ...
随机推荐
- 第7.12节 可共享的Python类变量
第7.12节 可共享的Python类变量 一. 引言 在上节已经引入介绍了类变量和实例变量,类体中定义的变量为类变量,默认属于类本身,实例变量是实例方法中定义的self对象的变量,对于每个实例都 ...
- Python中str类型的字符串写入二进制文件时报TypeError错的处理方式
在用二进制模式打开文件情况下,写入一个str对象时报错:TypeError: a bytes-like object is required, not 'str' 出现该问题是因为Python严格区分 ...
- PyQt(Python+Qt)学习随笔:树型部件QTreeWidget中当前列currentColumn和选中项selectedItems访问方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 当前列访问方法 树型部件QTreeWidget的currentColumn()方法返回当前项中得到焦 ...
- spring整合mybatis01
title: spring整合mybatis01 date: 2020-03-09 19:47:40 tags:整合的第一种方式 spring整合mybatis 1.mybatis回顾 mybatis ...
- mysql中table schema的基本操作
我们通常对数据库进行的增删插检操作,是针对数据库中的文件.mysql数据库中还有一些表(是view,只能做select操作)记录了现有表的meta data,比如某个column的名字,它的定义是什么 ...
- 乌云wooyun网站硬盘复活
AWD比赛防止没有网络,在移动硬盘里面准备一个乌云漏洞库. 之前也想过弄一个乌云的镜像网站,无奈学生机性能太低下了,部署到公网上服务器存储空间都不够,只能部署在本地硬盘了. 乌云镜像的开源地址:htt ...
- 【面试】关于get和post两种方法的不同。
最近在面试题和笔试题中经常会看到这道题,所以打算系统的整理一下. 一般标准的答案是这样的. GET在浏览器回退时是无害的,而POST会再次提交请求(浏览器应该告知用户数据会被重新提交). GET产生的 ...
- shell 编程 -- 条件判断
1.按照文件类型进行判断(常用的)-b 判断该文件是否存在-d 判断是否存在,并且是否为目录(是目录就为真)-e 判断该文件是否存在(存在为真)-f 判断文件是否存在,并且是否为普通文件(是普通文件为 ...
- 基于gin的golang web开发:实现用户登录
前文分别介绍过了Resty和gin-jwt两个包,Resty是一个HTTP和REST客户端,gin-jwt是一个实现了JWT的Gin中间件.本文将使用这两个包来实现一个简单的用户登录功能. 环境准备 ...
- Jenkins的war包安装
安装Jenkins首先要安装jdk,在官网下载jdk安装并配置环境变量 1.Jenkins下载地址,下载war包 https://www.jenkins.io/download/ 2.打开命令行窗口, ...