Spring注入的对象到底是什么类型
开篇
之前,在用spring编码调试的时候,有时候发现被自动注入的对象是原始类的对象,有时候是代理类的对象,那什么时候注入的原始类对象呢,有什么时候注入的是代理类的对象呢?心里就留下了这个疑问。后来再次看spring aop的时候变有了大胆的想法。
案例
先添加springboot依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
添加测试的类
- 添加Service1
package jfound.service;
public interface DemoService {
}
package jfound.service.impl;
import jfound.service.DemoService;
import org.springframework.stereotype.Service;
@Service
public class DemoServiceImpl implements DemoService {
}
- 添加Service2
package jfound.service;
public interface Demo2Service {
void asyncDemo();
}
package jfound.service.impl;
import jfound.service.Demo2Service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class Demo2ServiceImpl implements Demo2Service {
@Override
@Async
public void asyncDemo() {
System.out.println("Demo2Service:" + Thread.currentThread().getName());
}
}
- 添加Service3
package jfound.service.impl;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class Demo3Service {
@Async
public void asyncDemo() {
System.out.println("Demo3Service:" + Thread.currentThread().getName());
}
}
- Application
package jfound.proxycheck;
import jfound.service.Demo2Service;
import jfound.service.DemoService;
import jfound.service.impl.Demo3Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import javax.annotation.PostConstruct;
@SpringBootApplication
@EnableAsync
public class CheckApplication {
@Autowired
private DemoService demoService;
@Autowired
private Demo2Service demo2Service;
@Autowired
private Demo3Service demo3Service;
@PostConstruct
public void init() {
System.out.println("------------");
System.out.println("DemoService:"+demoService.getClass().getName());
System.out.println("Demo2Service:"+demo2Service.getClass().getName());
System.out.println("Demo3Service:"+demo3Service.getClass().getName());
System.out.println("------------");
demo2Service.asyncDemo();
demo3Service.asyncDemo();
System.out.println("CheckApplication:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
SpringApplication.run(CheckApplication.class);
}
}
代码描述
- 添加了3个service,DemoService、Demo2Service是接口,有实现类。Demo3Service是没有接口,只有单一的类
- Demo2Service和Demo3Service 的asyncDemo()方法上有@Async注解
- CheckApplication方法上有 @EnableAsync,用来开启异步
运行结果
------------
DemoService:jfound.proxycheck.service.impl.DemoServiceImpl
Demo2Service:com.sun.proxy.$Proxy37
Demo3Service:jfound.proxycheck.service.impl.Demo3Service$$EnhancerBySpringCGLIB$$b4ca4e7c
------------
Demo2Service:SimpleAsyncTaskExecutor-1
CheckApplication:main
Demo3Service:SimpleAsyncTaskExecutor-2
结果可以看出DemoService是被注入的是原始类的对象,Demo2Service被注入的对象是jdk代理的对象,Demo3Service被注入的对象是cglib的代理对象
将注入的demo2Service改为实现类注入
@Autowired
private Demo2ServiceImpl demo2Service;
运行结果如下:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'demo2ServiceImpl' could not be injected as a 'jfound.service.impl.Demo2ServiceImpl' because it is a JDK dynamic proxy that implements:
jfound.service.Demo2Service
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.
上面错误描述的是demo2ServiceImpl是实现Demo2Service接口的一个jdk动态代理,不能直接被注入
强制使用cglib
修改CheckApplication中的 @EnableAsync如下
@EnableAsync(proxyTargetClass = true)
运行结果如下:
------------
DemoService:jfound.proxycheck.service.impl.DemoServiceImpl
Demo2Service:jfound.proxycheck.service.impl.Demo2ServiceImpl$$EnhancerBySpringCGLIB$$c39af2f2
Demo3Service:jfound.proxycheck.service.impl.Demo3Service$$EnhancerBySpringCGLIB$$b074e2af
CheckApplication:main
Demo2Service:SimpleAsyncTaskExecutor-1
Demo3Service:SimpleAsyncTaskExecutor-2
上面结果是Demo2Service、Demo3Service被注入的都是cglib代理类
结论
spring很多功能都是通过aop来实现,如果事务,缓存注解,异步、还有一些自定义的aop等等,而aop是通过动态代理来实现的,spring主要用到的动态代理有jdk的动态代理和cglib。
- Spring 在没有使用aop的时候自动注入的时候是原始类型对象
- 在发生aop的时候,若代理对象有实现接口,则默认会使用jdk动态代理
- 在发生aop的时候,若代理对象没有实现接口,则默认会使用cglib动态代理
- jdk动态代理必须有实现接口
- 可以强制使用cglib来做spring动态代理
微信关注我,发现更多java领域知识

Spring注入的对象到底是什么类型的更多相关文章
- spring学习——注入静态对象属性
spring注入静态对象属性时,因为虚拟机类加载问题,直接在属性上使用@Autowired 是不可以的.需要在属性对应的set方法上@Autowired,并且,set方法不能定义为static. 1. ...
- 拦截器通过Spring获取工厂类,注入bean对象
// 这里需要注意一点,我们在拦截器内无法通过SpringBean的方式注入LoggerJPA,我只能通过另外一种形式. /** * 根据传入的类型获取spring管理的对应dao * @param ...
- Spring注入属性、对象
对Category和Product注入属性,并且对Product对象,注入一个Category对象 一.新建项目 二.导包 三.新建Category类 package com.yyt.pojo; pu ...
- 没有纳入spring管理的类如何注入spring管理的对象
spring 如何在普通类中调用注入的对象? spring 在Thread中注入@Resource失败,总为null~解决 springmvc 注入总是空指针异常? 以上的几个问题就是我在项目中遇到的 ...
- 1.JSON 转换对象失败问题 2.spring注入失效
今天做项目中将一个json 字符串转换为对象,但结果怎么都转换不了!——————最后发现问题,原来是因为这个类我给他添加了带参数的构造器!导致转换失败! 在添加一个无参的构造器就好了! 第二个:今天调 ...
- 谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?
本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 推荐阅读: Spring官网阅读 | 总结篇 Spring杂 ...
- Spring注入中byType和byName的总结
1.首先,区分清楚什么是byType,什么是byName. <bean id="userServiceImpl" class="cn.com.bochy.servi ...
- 一个Java对象到底占用多大内存?
最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...
- 一个Java对象到底占用多大内存
在网上搜到了一篇博客讲的非常好,里面提供的这个类也非常实用: import java.lang.instrument.Instrumentation; import java.lang.reflect ...
随机推荐
- 关于用C-free进行C语言编程在电脑中生成的.exe和.o文件
在使用C-free进行C语言编程时,程序运行后会自动在电脑文件中生成以.exe和.o为后缀名的文件: 1,生成的.exe文件为系统自动打包完成的应用程序,该程序可直接在其他无C-free环境的电脑上运 ...
- 预测球队比赛结果及利用pyinstaller打包文件
一.预测乒乓球球队比赛成绩 1.乒乓球比赛规则 一局比赛:在一局比赛中,先得11分的一方为胜方:10平后,先多得2分的一方为胜方. 一场比赛:单打的淘汰赛采用七局四胜制,双打淘汰赛和团体赛采用五局三胜 ...
- 【三剑客】awk命令2
1. 程序结构: Begin 和 End模块 awk的程序的结构:Begin块,Body块,End块. BEGIN块:BEGIN {awk-commands} BEGIN块在被程序启动时启动,且只执行 ...
- HTML中使用CSS样式(上)
在每一个标签上都可以设置style属性,这就是CSS样式: <div style="height:48px;border: 1px solid red;text-align:cente ...
- Qt之QListWidget:项目的多选与单选设置
2019独角兽企业重金招聘Python工程师标准>>> #include "widget.h" #include <QApplication> #in ...
- 华为设备RIP实施和理论详解
1.路由协议基础 共同的目的:更新.维护和控制3层的路由 工作机制: RIP,封装在UDP这个协议上,端口号520(优先级100) OSPF,封装在IP层,协议号89(优先级,内部10,外部是150- ...
- Xapian实战(四):搜索
参考资料: 学习Xapian(1)-基础的建索引和搜索 1. Xapian中用于搜索的类 Enquire - 提供了检索的接口:(Enquire API) QueryParser(QueryParse ...
- USB设备驱动模型
嵌入式设备驱动的编写,基本上都要按照一定的驱动模型编写.不这么做的话,一旦设备发生了更新和改变,大部分的驱动代码都要推倒重来,代码的重用率低,不具备移植性.所以在新版linux2.6.22以后的内核版 ...
- python数据统计分析
1. 常用函数库 scipy包中的stats模块和statsmodels包是python常用的数据分析工具,scipy.stats以前有一个models子模块,后来被移除了.这个模块被重写并成为了 ...
- HTTP接口测试
HTTP接口测试 1.1 get接口 请求URL http://api.nnzhp.cn/api/user/stu_info 请求方式 get 请求参数 参数名 必选 类型 说明 stu_name 是 ...