• 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,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领域知识
    JFound

  • 相关阅读:
    Linux 服务器注意事项
    维基逃离MySQL 力挺开源数据库 MariaDB
    服务器性能优化
    1 Nginx + 12 Tomcat +2DB 实现2个程序负载均衡
    服务器虚拟化技术 对比简介
    vSphere虚拟系统 添加虚拟服务器
    IIS停止服务 报错Connections_Refused
    windows服务器 IIS FTP服务
    tomcat solr服务无法搜索中文
    查看php相关信息
  • 原文地址:https://www.cnblogs.com/jfound/p/12908527.html
Copyright © 2020-2023  润新知