开篇

之前,在用spring编码调试的时候,有时候发现被自动注入的对象是原始类的对象,有时候是代理类的对象,那什么时候注入的原始类对象呢,有什么时候注入的是代理类的对象呢?心里就留下了这个疑问。后来再次看spring aop的时候变有了大胆的想法。

案例

先添加springboot依赖
  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter</artifactId>
  4. <version>2.3.0.RELEASE</version>
  5. </dependency>
添加测试的类
  • 添加Service1
  1. package jfound.service;
  2. public interface DemoService {
  3. }
  1. package jfound.service.impl;
  2. import jfound.service.DemoService;
  3. import org.springframework.stereotype.Service;
  4. @Service
  5. public class DemoServiceImpl implements DemoService {
  6. }
  • 添加Service2
  1. package jfound.service;
  2. public interface Demo2Service {
  3. void asyncDemo();
  4. }
  1. package jfound.service.impl;
  2. import jfound.service.Demo2Service;
  3. import org.springframework.scheduling.annotation.Async;
  4. import org.springframework.stereotype.Service;
  5. @Service
  6. public class Demo2ServiceImpl implements Demo2Service {
  7. @Override
  8. @Async
  9. public void asyncDemo() {
  10. System.out.println("Demo2Service:" + Thread.currentThread().getName());
  11. }
  12. }
  • 添加Service3
  1. package jfound.service.impl;
  2. import org.springframework.scheduling.annotation.Async;
  3. import org.springframework.stereotype.Service;
  4. @Service
  5. public class Demo3Service {
  6. @Async
  7. public void asyncDemo() {
  8. System.out.println("Demo3Service:" + Thread.currentThread().getName());
  9. }
  10. }
  • Application
  1. package jfound.proxycheck;
  2. import jfound.service.Demo2Service;
  3. import jfound.service.DemoService;
  4. import jfound.service.impl.Demo3Service;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.SpringApplication;
  7. import org.springframework.boot.autoconfigure.SpringBootApplication;
  8. import org.springframework.scheduling.annotation.EnableAsync;
  9. import javax.annotation.PostConstruct;
  10. @SpringBootApplication
  11. @EnableAsync
  12. public class CheckApplication {
  13. @Autowired
  14. private DemoService demoService;
  15. @Autowired
  16. private Demo2Service demo2Service;
  17. @Autowired
  18. private Demo3Service demo3Service;
  19. @PostConstruct
  20. public void init() {
  21. System.out.println("------------");
  22. System.out.println("DemoService:"+demoService.getClass().getName());
  23. System.out.println("Demo2Service:"+demo2Service.getClass().getName());
  24. System.out.println("Demo3Service:"+demo3Service.getClass().getName());
  25. System.out.println("------------");
  26. demo2Service.asyncDemo();
  27. demo3Service.asyncDemo();
  28. System.out.println("CheckApplication:"+Thread.currentThread().getName());
  29. }
  30. public static void main(String[] args) {
  31. SpringApplication.run(CheckApplication.class);
  32. }
  33. }
代码描述
  • 添加了3个service,DemoServiceDemo2Service是接口,有实现类。Demo3Service是没有接口,只有单一的类
  • Demo2ServiceDemo3ServiceasyncDemo()方法上有@Async注解
  • CheckApplication方法上有 @EnableAsync,用来开启异步
运行结果
  1. ------------
  2. DemoService:jfound.proxycheck.service.impl.DemoServiceImpl
  3. Demo2Service:com.sun.proxy.$Proxy37
  4. Demo3Service:jfound.proxycheck.service.impl.Demo3Service$$EnhancerBySpringCGLIB$$b4ca4e7c
  5. ------------
  6. Demo2Service:SimpleAsyncTaskExecutor-1
  7. CheckApplication:main
  8. Demo3Service:SimpleAsyncTaskExecutor-2

结果可以看出DemoService是被注入的是原始类的对象,Demo2Service被注入的对象是jdk代理的对象,Demo3Service被注入的对象是cglib的代理对象

将注入的demo2Service改为实现类注入
  1. @Autowired
  2. private Demo2ServiceImpl demo2Service;

运行结果如下:

  1. ***************************
  2. APPLICATION FAILED TO START
  3. ***************************
  4. Description:
  5. The bean 'demo2ServiceImpl' could not be injected as a 'jfound.service.impl.Demo2ServiceImpl' because it is a JDK dynamic proxy that implements:
  6. jfound.service.Demo2Service
  7. Action:
  8. 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如下

  1. @EnableAsync(proxyTargetClass = true)

运行结果如下:

  1. ------------
  2. DemoService:jfound.proxycheck.service.impl.DemoServiceImpl
  3. Demo2Service:jfound.proxycheck.service.impl.Demo2ServiceImpl$$EnhancerBySpringCGLIB$$c39af2f2
  4. Demo3Service:jfound.proxycheck.service.impl.Demo3Service$$EnhancerBySpringCGLIB$$b074e2af
  5. CheckApplication:main
  6. Demo2Service:SimpleAsyncTaskExecutor-1
  7. Demo3Service:SimpleAsyncTaskExecutor-2

上面结果是Demo2ServiceDemo3Service被注入的都是cglib代理类

结论

spring很多功能都是通过aop来实现,如果事务,缓存注解,异步、还有一些自定义的aop等等,而aop是通过动态代理来实现的,spring主要用到的动态代理有jdk的动态代理和cglib。

  • Spring 在没有使用aop的时候自动注入的时候是原始类型对象
  • 在发生aop的时候,若代理对象有实现接口,则默认会使用jdk动态代理
  • 在发生aop的时候,若代理对象没有实现接口,则默认会使用cglib动态代理
  • jdk动态代理必须有实现接口
  • 可以强制使用cglib来做spring动态代理

微信关注我,发现更多java领域知识

Spring注入的对象到底是什么类型的更多相关文章

  1. spring学习——注入静态对象属性

    spring注入静态对象属性时,因为虚拟机类加载问题,直接在属性上使用@Autowired 是不可以的.需要在属性对应的set方法上@Autowired,并且,set方法不能定义为static. 1. ...

  2. 拦截器通过Spring获取工厂类,注入bean对象

    // 这里需要注意一点,我们在拦截器内无法通过SpringBean的方式注入LoggerJPA,我只能通过另外一种形式. /** * 根据传入的类型获取spring管理的对应dao * @param ...

  3. Spring注入属性、对象

    对Category和Product注入属性,并且对Product对象,注入一个Category对象 一.新建项目 二.导包 三.新建Category类 package com.yyt.pojo; pu ...

  4. 没有纳入spring管理的类如何注入spring管理的对象

    spring 如何在普通类中调用注入的对象? spring 在Thread中注入@Resource失败,总为null~解决 springmvc 注入总是空指针异常? 以上的几个问题就是我在项目中遇到的 ...

  5. 1.JSON 转换对象失败问题 2.spring注入失效

    今天做项目中将一个json 字符串转换为对象,但结果怎么都转换不了!——————最后发现问题,原来是因为这个类我给他添加了带参数的构造器!导致转换失败! 在添加一个无参的构造器就好了! 第二个:今天调 ...

  6. 谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?

    本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 推荐阅读: Spring官网阅读 | 总结篇 Spring杂 ...

  7. Spring注入中byType和byName的总结

    1.首先,区分清楚什么是byType,什么是byName. <bean id="userServiceImpl" class="cn.com.bochy.servi ...

  8. 一个Java对象到底占用多大内存?

    最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...

  9. 一个Java对象到底占用多大内存

    在网上搜到了一篇博客讲的非常好,里面提供的这个类也非常实用: import java.lang.instrument.Instrumentation; import java.lang.reflect ...

随机推荐

  1. Gym 101194D Ice Cream Tower

    被一道数位DP折磨得欲仙欲死之后,再做这道题真是如同吃了ice cream一样舒畅啊 #include<bits/stdc++.h> using namespace std; #defin ...

  2. CF1324 --- Maximum White Subtree

    CF1324 --- Maximum White Subtree 题干 You are given a tree consisting of \(n\) vertices. A tree is a c ...

  3. 【Linux常见命令】route命令

    route - show / manipulate the IP routing table route命令用于显示和操作IP路由表. route命令用来显示并设置Linux内核中的网络路由表,rou ...

  4. Ubuntu+FastDFS+Nginx

    一.安装libfastcommon 1.wget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz 2.tar - ...

  5. Qt之QListWidget:项目的多选与单选设置

    2019独角兽企业重金招聘Python工程师标准>>> #include "widget.h" #include <QApplication> #in ...

  6. ACM算法--二分法--模板

    // 在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继) while (l < r) { int mid = (l + r) / 2; if (a[mid] >= x) ...

  7. CodeForces - 1176A Divide it! (模拟+分类处理)

    You are given an integer nn. You can perform any of the following operations with this number an arb ...

  8. RF(自定义关键字)

    1.在 D:\work_software\python\Lib\site-packages 文件夹下, 新建 python package 包 ,例如我的是 TestLibrary 建好后的完整路径: ...

  9. 利用github的webhook进行自动部署

    利用github的webhook进行自动部署 github提供了webhook功能,大概意思就是,当你提交了代码,git检测到你进行了push,可以调起你一个你知道的url. 这个功能有什么用了?比如 ...

  10. Idea中查看一个类的所有资料及其层级关系

    在Idea中直接Ctrl + t 查看类的子类是可以看到,但是他没有那种层级顺序! 我们可以在类中点击顶部菜单Navigate -----> Type Hierarchy