开篇

之前,在用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,DemoServiceDemo2Service是接口,有实现类。Demo3Service是没有接口,只有单一的类
  • Demo2ServiceDemo3ServiceasyncDemo()方法上有@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

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

结论

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

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

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

最新文章

  1. SQL Server2008 with(lock)用法
  2. Josephu--Java链表实现
  3. 理解Python装饰器
  4. linux 命令大全(转)
  5. HDU 1058 Humble Numbers【DP】
  6. 一种高斯模糊渐变动画的实现-b
  7. jQuery name checked 模糊查找匹配ID
  8. 门面模式 到 socket
  9. 8.0 BOM对象
  10. UML关系总结
  11. POJ 3264 Balanced Lineup【线段树区间查询求最大值和最小值】
  12. SetProcessWorkingSetSize减少内存占用
  13. Linux基础(五) Shell函数
  14. html5-新布局元素header,footer
  15. Nodejs的模块系统
  16. Zookeeper可以干什么
  17. [Algorithm] How to find all the subsets of an n-element set T?
  18. postman的使用方法详解!最全面的教程
  19. R语言输出pdf时,中文乱码处理
  20. Ajax 使用 FormData做为data的参数时 出现Illegal invocation

热门文章

  1. MATLAB 之MATLAB2016b 安装破解教程
  2. js 之 箭头函数 (未学完)
  3. 基于java的OpenCV安装和配置
  4. unix域源码解析
  5. 《LabVIEW 虚拟仪器程序设计从入门到精通(第二版)》一1.3 小结
  6. 01 微信小程序入门
  7. HTML 页面跳转的五种方法
  8. 数位dp H - F(x) HDU - 4734
  9. java运行时跟编译时的区别,欢迎大家指正
  10. c#一些常用知识点