美文网首页
[记录]Spring注入的对象类型

[记录]Spring注入的对象类型

作者: beldon_wu | 来源:发表于2018-07-03 22:50 被阅读0次

    开篇

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

    案例

    先添加springboot依赖
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.0.2.RELEASE</version>
    </dependency>
    
    添加测试的类
    • 添加Service1
    package beldon.service;
    public interface DemoService {
    }
    
    package beldon.service.impl;
    import beldon.service.DemoService;
    import org.springframework.stereotype.Service;
    @Service
    public class DemoServiceImpl implements DemoService {
    }
    
    
    • 添加Service2
    package beldon.service;
    public interface Demo2Service {
        void asyncDemo();
    }
    
    package beldon.service.impl;
    import beldon.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 beldon.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 beldon.proxycheck;
    import beldon.service.Demo2Service;
    import beldon.service.DemoService;
    import beldon.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:beldon.proxycheck.service.impl.DemoServiceImpl
    Demo2Service:com.sun.proxy.$Proxy37
    Demo3Service:beldon.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 'beldon.service.impl.Demo2ServiceImpl' because it is a JDK dynamic proxy that implements:
        beldon.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:beldon.proxycheck.service.impl.DemoServiceImpl
    Demo2Service:beldon.proxycheck.service.impl.Demo2ServiceImpl$$EnhancerBySpringCGLIB$$c39af2f2
    Demo3Service:beldon.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动态代理

    相关文章

      网友评论

          本文标题:[记录]Spring注入的对象类型

          本文链接:https://www.haomeiwen.com/subject/iohsuftx.html