Spring注入模型怎么应用

今天小编给大家分享一下Spring注入模型怎么应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    Spring注入bean的方式

    DI exists in two major variants: Constructor-based dependency injection and Setter-based dependency injection.

    从Spring的官网中可以得知,Spring注入bean的方式由两种,一种是通过构造方法进行注入,另外一种是通过setter方法进行注入。
    但熟悉Spring开发的同学在实际的开发中经常使用的注入方式是通过@Autowired以及@Resource的方式来注入bean的。那么通过注解的方式注入是跟上面两种注入方式是一样的吗?在研究这个问题之前,我们需要来了解Spring的注入模型。

    Spring的注入模型

    如果不深入到Spring的源码,是很少有机会了解到Spring的注入模型(AutowireMode)。但是为了扫清我们学习Spring源码的障碍,我们有必要了解下Spring的注入模型。
    Spring的注入模型有四种,分别是:

    • autowire_no(0):默认的注入模型,如果在beanA中注入beanB,如果没有提供注解或者xml的注入方式,beanB是无法注入到beanA中的。

    • autowire_name(1):通过set方法注入,并且set的参数名必须和注入的bean名称一样,在xml中是通过byName

    • autowire_type(2):通过set方法注入,set的参数名可以随意命名,但是类型必须和注入的bean的类型一样,在xml中是通过byType的方式配置

    • autowire_constructor(3):通过构造器注入

    代码示例

    多说无益,我们直接上代码来加深对这一概念的了解。

    定义bean对象

    我们简单定义两个类,分别是Student和Address,并且将他们注入到Spring容器中。
    Student.java如下

    @Component
    @Slf4j
    public class Student {
    
        private Address address;
    
        public Student(){
            log.info("default constructor...");
        }
    
        public Student(Address address){
            log.info("constructor inject...{}", address);
            this.address = address;
        }
    
        public void setAddress(Address address){
            log.info("setter...{}", address);
            this.address = address;
        }
    
        public void showAddress(){
            this.address.info();
        }
    }

    Address.java如下

    @Component
    public class Address {
    
        public void info(){
            System.out.println("广东省广州市白云区");
        }
    }

    我们可以看到在Student中有一个属性是Address,并且提供了默认的构造方法以及带参数的构造方法,同时还有一个 set方法。

    定义配置类

    我们再定义一个config类,用来扫描这两个类所在的包路径,把这两个类注入到Spring容器中。

    @ComponentScan("org.example.autoModel.model")
    public class MyBeanConfig {
    }

    定义后置处理器

    在Spring中,我们可以在自己定义的后置处理器BeanFactoryPostProcessor,获取到对应的BeanDefinition。
    相信大家在学习Spring的时候有了解过BeanDefinition,不熟悉的可以搜索下BeanDefinition的概念,如果阅读过Spring的源码的话,对BeanDefinition应该就更加熟悉了。这里就不做过多的解释了,后面在解读Spring源码的时候应该也会涉及到这部分的知识。
    简单的来说,就是一个对象被注入到Spring中,实际是被解析成BeanDefinition对象,里面保存了各种需要用到的信息,并且可以在后置处理器中获取到对应的BeanDefinition对象,然后对其做一些操作。

    @Slf4j(topic = "e")
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition("student");
    //        beanDefinition.setAutowireMode(3);
            log.debug("mode:{}",beanDefinition.getAutowireMode());
        }
    }

    上面代码所示,我们可以获取这个beanDefinition在Spring容器中对应的autowireMode的值,并且可以修改这个autowireMode的值,来观察下注入模型的改变,对bean的注入方式有什么影响。

    定义测试方法

    @Test
    public void modelTest(){
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
       context.register(MyBeanConfig.class);
       context.register(MyBeanFactoryPostProcessor.class);
       context.refresh();
       Student student = context.getBean(Student.class);
       student.showAddress();
    }

    执行测试方法,得出如下的结果。

    Spring注入模型怎么应用

    如上面所示,我们可以得到对应的autowireMode的值是0,并且是执行了Student的默认构造方法,由于没有将address属性注入到student中,所在调用address对应的方法的时候,抛出了空指针的异常。
    针对上面的对象,我们可以简单分析下:

    • Spring默认的注入模型是0

    • 注入模型是0,意味着执行默认的构造方法,并且不会执行set方法去进行注入address这个对象,所以抛出了空指针异常

    我们可以在后置处理器中,修改对应autowioreMode的值,将autowireMode的值修改成1。

    beanDefinition.setAutowireMode(1);

    然后执行该测试方法,得到下面的结果。

    Spring注入模型怎么应用

    可以看到我们将注入模型的值修改成1,之后,spring就会通过set方法,将address注入到student中,就可以成功调用address的方法了。
    当然,我们将注入模型的值修改成2,也是注入成功的,并且也是通过set方法,只不过是byType和byName的区别。这个同学们可以自己尝试下。
    下面,我们将注入模型的值修改成3来看下执行的结果。

    beanDefinition.setAutowireMode(3);

    结果如下:

    Spring注入模型怎么应用

    可以看到,如果将注入模型的值修改成了3,那么Spring是通过带参的构造方法来注入给student的。
    通过上面简单的例子,我们就可以了解到注入模型autowireMode对注入方式的影响,这为我们以后阅读Spring的源码打下了基础。

    自动注入和手动注入

    上面我们将autowireMode值修改成1、2、3,就可以完成属性的自动注入。那如果我们不去修改autowireMode的值,而是使用注解来将属性注入到student中,会是怎样的结果呢?
    我们来看下面的代码:

    @Component
    @Slf4j
    public class Student {
    
        @Autowired
        private Address address;
    
        public Student(){
            log.info("default constructor...");
        }
    
        public Student(Address address){
            log.info("constructor inject...{}", address);
            this.address = address;
        }
    
        public void setAddress(Address address){
            log.info("setter...{}", address);
            this.address = address;
        }
    
        public void showAddress(){
            this.address.info();
        }
    }
    @Slf4j(topic = "e")
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition("student");
    //        beanDefinition.setAutowireMode(3);
            log.debug("mode:{}",beanDefinition.getAutowireMode());
        }
    }

    查看结果

    Spring注入模型怎么应用

    我们发现使用@Autowired注解注入属性的时候,注入模型的值是0,也就是默认的值。
    对于@Autowired的注解,我的看法是,使用注解注入属性是手动注入的方式,Spring提供自动注入的方式只有set方法以及带参的构造方法。而注解的注入方式,只不过是xml手动注入的一种简化,Spring内部处理的机制都是类似的。
    了解过xml配置的同学大概有些印象,我们需要指定bean中属性所对应的类的全路径。而使用自动注入,我们可以指定byType或者byName。由于xml方式太久没用了,大概就是这么个意思吧。
    所以我认为@Autowired注入的方式,不是自动注入,而是手动注入,只不过Spring容器内部帮我们处理了。

    以上就是“Spring注入模型怎么应用”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程之家行业资讯频道。

    相关文章

    这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原...
    今天小编给大家分享的是一文解析spring中事务的传播机制,相...
    这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区...
    本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。...
    本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有...
    这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓...