深入挖掘Spring系列 -- 依赖注入专题(上)

简介: 深入挖掘Spring系列 -- 依赖注入专题(上)

在上一篇的文章中,我们着重讲解了Spring内部的依赖查找这玩意,这一次着重介绍关于spring的依赖注入模块。


关于依赖注入这块,本篇重点介绍实战方面的内容,实战案例的代码有些多,希望在分享结束后能对各位读者对Spring的依赖注入有个更加清晰的认识。


依赖注入的模式


我们通常在使用Spring的时候主要是用注解或者xml的方式进行注入,如果做过基于Spring容器的二次开发的朋友应该还清楚直接基于Spring的API方式进行依赖注入。


依赖注入的模式主要可以分为两个大类别:


  • 手动模式的注入
  • 自动模式的注入


手动模式


  • XML模式的资源配置
  • Java注解的配置方式
  • API配置方式(一般如果没有对于容器进行开发,使用会比较少)


自动模式


Autowiring 的自动绑定模式


了解清楚了这两个大的模式之后,我们再来继续细分,依赖注入的几种常用类型。


Setter注入

XML模式

代码案例:


PersonBean对象(后边会多次用到这个对象)


package org.idea.spring.dependency.inject.setter;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.idea.spring.ioc.bean.Person;
/**
 * 自动绑定
 *
 * @Author linhao
 * @Date created in 10:44 下午 2021/4/21
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PersonHolder {
    private Person person;
}
Person代码
package org.idea.spring.ioc.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @Author idea
 * @Date created in 10:45 下午 2020/4/30
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    Integer id;
    String name;
}
复制代码


XML内容


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="malePerson" class="org.idea.spring.ioc.bean.Person" >
    <property name="id" value="1"></property>
    <property name="name" value="idea"></property>
</bean>
    <bean class="org.idea.spring.dependency.inject.setter.PersonHolder">
        <property name="person" ref="malePerson"></property>
    </bean>
</beans>
复制代码


PersonHolder内部引用了一个Person对象。


Spring容器的代码


package org.idea.spring.dependency.inject.setter;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
 * 基于xml的依赖注入方式案例
 *
 * @Author linhao
 * @Date created in 8:29 上午 2021/4/20
 */
public class InDependencyInjectDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        String xmlPath = "classpath:/META-INF/independency-inject.xml";
        xmlBeanDefinitionReader.loadBeanDefinitions(xmlPath);
        PersonHolder personHolder = beanFactory.getBean(PersonHolder.class);
        System.out.println(personHolder);
    }
}
复制代码


注解模式


Spring内部代码块


package org.idea.spring.dependency.inject.setter;
import org.idea.spring.ioc.bean.Person;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import java.util.Map;
/**
 * 基于注解的依赖注入
 *
 * @Author linhao
 * @Date created in 10:53 下午 2021/4/21
 */
public class AnnotationDependencyInjectDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AnnotationConfigApplicationContext.class);
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
        xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/bean-ioc.xml");
        applicationContext.register(PersonHolder.class);
        applicationContext.refresh();
        Map<String,Person> personMap= applicationContext.getBeansOfType(Person.class);
        for (String key : personMap.keySet()) {
            System.out.println(key);
        }
        PersonHolder personHolder = applicationContext.getBean(PersonHolder.class);
        System.out.println(personHolder);
        applicationContext.close();
    }
    /**
     * 这里需要先对person的bean进行初始化才能注入
     *
     * @param
     * @return
     */
    @Bean
    public PersonHolder personHolder(Person person){
        return new PersonHolder(person);
    }
}
复制代码


API模式


基于Spring容器的内部api进行其实也可以实现依赖的注入:


package org.idea.spring.dependency.inject.setter;
import org.idea.spring.ioc.bean.Person;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
 * 通过api的方式进行注入实现
 *
 * @Author linhao
 * @Date created in 11:11 下午 2021/4/21
 */
public class ApiDependencyInjectDemo {
    @Bean
    public Person myPerson(){
        return new Person(1,"idea");
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(ApiDependencyInjectDemo.class);
        BeanDefinition personBeanDefinition = createUserBeanDefinition();
        applicationContext.registerBeanDefinition("personHolder",personBeanDefinition);
        applicationContext.refresh();
        PersonHolder personHolder = applicationContext.getBean(PersonHolder.class);
        System.out.println(personHolder.getPerson());
        applicationContext.close();
    }
    private static BeanDefinition createUserBeanDefinition() {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(PersonHolder.class);
        //注意这里的add方法有多种类型,需要注意下细节点
        beanDefinitionBuilder.addPropertyReference("person","myPerson");
        return beanDefinitionBuilder.getBeanDefinition();
    }
}
复制代码


上边的三种注入方式主要是基于Bean对象内部的setter方法和getter方法作为基础进行注入引用的,除此之外,其实还可以基于对象的构造函数来实现字段的引入。


构造器注入


XML模式


首先是xml文件的内容:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="femalePerson" class="org.idea.spring.ioc.bean.FemalePerson"></bean>
    <bean class="org.idea.spring.dependency.inject.setter.PersonHolder">
       <constructor-arg name="person" ref="femalePerson"></constructor-arg>
    </bean>
</beans>
复制代码


Spring容器的相关代码:


package org.idea.spring.dependency.inject.constructor;
import org.idea.spring.dependency.inject.setter.PersonHolder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
 * @Author linhao
 * @Date created in 10:21 下午 2021/4/22
 */
public class XmlDependencyInjectDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
        xmlBeanDefinitionReader.loadBeanDefinitions("classpath:/META-INF/independency-constructor-inject.xml");
        PersonHolder personHolder = defaultListableBeanFactory.getBean(PersonHolder.class);
        System.out.println(personHolder.getPerson());
    }
}
复制代码


注解模式


基于注解的实现方式比较简单,这里我也直接贴出代码了:


package org.idea.spring.dependency.inject.constructor;
import org.idea.spring.dependency.inject.setter.PersonHolder;
import org.idea.spring.ioc.bean.Person;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
 * @Author linhao
 * @Date created in 10:25 下午 2021/4/22
 */
public class AnnotationDependencyInjectDemo {
    @Bean
    public Person femalePerson(){
        return new Person(1,"idea2");
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(AnnotationDependencyInjectDemo.class);
        annotationConfigApplicationContext.refresh();
        PersonHolder personHolder = annotationConfigApplicationContext.getBean(PersonHolder.class);
        System.out.println(personHolder);
        annotationConfigApplicationContext.close();
    }
    /**
     * 自动会进行bean的注入
     *
     * @param femalePerson
     * @return
     */
    @Bean
    public PersonHolder personHolder(Person femalePerson){
        return new PersonHolder(femalePerson);
    }
}
复制代码


代码中的personHolder bean在进行初始化的时候会自动通过名称匹配给femalePerson进行依赖注入。


Api模式


如果有遇到过对Spring容器做改造的需求,可能就会需要了解到类似下边的这种代码:


package org.idea.spring.dependency.inject.constructor;
import org.idea.spring.dependency.inject.setter.PersonHolder;
import org.idea.spring.ioc.bean.Person;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
 * @Author linhao
 * @Date created in 10:28 下午 2021/4/22
 */
public class ApiDependencyInjectDemo {
    @Bean
    public Person myPerson(){
        return new Person(1,"idea");
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(ApiDependencyInjectDemo.class);
        BeanDefinition personBeanDefinition = createUserBeanDefinition();
        applicationContext.registerBeanDefinition("personHolder",personBeanDefinition);
        applicationContext.refresh();
        PersonHolder personHolder = applicationContext.getBean(PersonHolder.class);
        System.out.println(personHolder.getPerson());
        applicationContext.close();
    }
    private static BeanDefinition createUserBeanDefinition() {
        //spring官方比较推荐的一种注入方式
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(PersonHolder.class);
        //注意这里的add方法有多种类型,需要注意下细节点
        beanDefinitionBuilder.addConstructorArgReference("myPerson");
        return beanDefinitionBuilder.getBeanDefinition();
    }
}
复制代码


其实不管是注解还是xml,在底层都是基于使用BeanDefinition的构建,然后再使用Spring容器注册这个BeanDefinition来实现依赖注入的。


字段注入


字段注入的模式就是我们比较常在工作中使用的案例了,常见的注入注解有:


@Autowired

@Resource


例如下边的代码:


package org.idea.spring.dependency.inject.field;
import org.idea.spring.dependency.inject.setter.PersonHolder;
import org.idea.spring.ioc.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import javax.annotation.Resource;
/**
 * @Author linhao
 * @Date created in 10:48 下午 2021/4/22
 */
public class AnnotationDependencyInjectDemo {
    @Autowired
    private PersonHolder personHolder2;
    @Resource
    private PersonHolder personHolder;
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AnnotationDependencyInjectDemo.class);
        applicationContext.refresh();
        AnnotationDependencyInjectDemo annotationDependencyInjectDemo = applicationContext.getBean(AnnotationDependencyInjectDemo.class);
        System.out.println(annotationDependencyInjectDemo.personHolder);
        System.out.println(annotationDependencyInjectDemo.personHolder2);
        //这里面的两个bean都是同一个,因为bean的作用域是一致相同的
        System.out.println(annotationDependencyInjectDemo.personHolder == annotationDependencyInjectDemo.personHolder2);
        applicationContext.close();
    }
    @Bean
    public PersonHolder personHolder(){
        return new PersonHolder(new Person(1,"idea"));
    }
}
复制代码


这里面容易让人有所疑惑的点:


在同一个类里面声明了一个Bean,然后在该Bean中直接引用是否会报错?

经过实践后发现,并不会有影响。


代码案例中的personHolder2和personHolder是否是同一个对象?


如果我们的PersonHolder是单例模式的话,那么就是同一个对象。


方法注入


所谓的方法注入,我个人的理解就是对方法的入参也支持依赖注入的功能。例如下边这段代码案例:


package org.idea.spring.dependency.inject.method;
import org.idea.spring.dependency.inject.setter.PersonHolder;
import org.idea.spring.ioc.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import javax.annotation.Resource;
/**
 * spring内部的方法注入实现
 * @Author linhao
 * @Date created in 10:24 上午 2021/4/23
 */
public class MethodInjectDemo {
    private PersonHolder personHolder;
    private PersonHolder personHolder_resource;
    @Resource
    public void initPersonHolderResource(PersonHolder personHolder){
        this.personHolder_resource = personHolder;
    }
    @Autowired
    public void initPersonHolder(PersonHolder personHolder){
        this.personHolder = personHolder;
    }
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(MethodInjectDemo.class);
        annotationConfigApplicationContext.refresh();
        MethodInjectDemo methodInjectDemo = annotationConfigApplicationContext.getBean(MethodInjectDemo.class);
        System.out.println(methodInjectDemo.personHolder);
        System.out.println(methodInjectDemo.personHolder_resource);
        //修改bean的作用域则可以判断为不相同
        System.out.println(methodInjectDemo.personHolder == methodInjectDemo.personHolder_resource);
//        annotationConfigApplicationContext
        annotationConfigApplicationContext.close();
    }
    @Bean
    @Scope(value = "prototype")
    public Person femalePerson(){
        return new Person(1,"female");
    }
    @Bean
    @Scope(value = "prototype")
    public PersonHolder personHolder(Person person){
        return new PersonHolder(person);
    }
}
复制代码


这里你会发现我将PersonHolder的@Scope属性做了调整,所以@AutoWired注解和@Resource注解引入的对象就不会是同一个对象。


目录
相关文章
|
4月前
|
XML Java 测试技术
Spring Boot中的依赖注入和控制反转
Spring Boot中的依赖注入和控制反转
|
3月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
52 0
|
3月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
36 2
|
3月前
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
107 0
|
4月前
|
缓存 Java Spring
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
|
5月前
|
设计模式 Java 测试技术
Spring Boot中的依赖注入详解
Spring Boot中的依赖注入详解
|
5月前
|
Java Spring 容器
spring如何进行依赖注入,通过set方法把Dao注入到serves
spring如何进行依赖注入,通过set方法把Dao注入到serves
|
4月前
|
XML Java 数据格式
深入理解Spring中的依赖注入原理
深入理解Spring中的依赖注入原理
|
4月前
|
Java Spring 容器
深入理解Spring Boot中的容器与依赖注入
深入理解Spring Boot中的容器与依赖注入
|
5月前
|
XML Java 数据格式
使用 Spring 实现控制反转和依赖注入
自动装配允许Spring容器通过检查已定义的bean来自动解决协作bean之间的依赖关系。 使用XML配置有四种自动装配bean的模式: • no:默认值 - 这意味着不使用自动装配,我们必须显式地命名依赖项。 • byName:按属性名称进行自动装配,因此Spring将查找与需要设置的属性同名的bean。 • byType:类似于按名称进行自动装配,仅基于属性的类型。这意味着Spring将查找具有相同类型的属性来设置的bean。如果有多个bean具有该类型,则框架会抛出异常。 • constructor:基于构造函数参数进行自动装配,意味着Spring将查找具有与构造函数参数相同类型的bea