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

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

回调注入


在Spring容器中一般以Aware作为结尾命名的对象都是能够接收一些特殊的回调通知功能,因此在Spring回调相关对象的时候可以注入一些依赖,从而实现基于回调的依赖注入。


代码案例如下:


package org.idea.spring.dependency.inject.aware;
import org.idea.spring.ioc.bean.Person;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
 * @Author linhao
 * @Date created in 11:11 上午 2021/4/23
 */
public class AwareInjectDemo implements BeanFactoryAware, ApplicationContextAware {
    private  BeanFactory beanFactory;
    private  ApplicationContext applicationContext;
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(AwareInjectDemo.class);
        annotationConfigApplicationContext.refresh();
        AwareInjectDemo awareInjectDemo = annotationConfigApplicationContext.getBean(AwareInjectDemo.class);
        Person person = (Person) awareInjectDemo.beanFactory.getBean("person");
        System.out.println(annotationConfigApplicationContext.getBeanFactory() == awareInjectDemo.beanFactory);
        //当前的上下文和回调注入的上下文是同一个对象
        System.out.println(awareInjectDemo.applicationContext == annotationConfigApplicationContext);
        System.out.println(person);
        annotationConfigApplicationContext.close();
    }
    @Bean
    public Person person(){
        return new Person(1,"idea");
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
       this.applicationContext = applicationContext;
    }
}
复制代码


关于Spring内部的依赖注入类型大致整理了一下如下所示:


网络异常,图片无法展示
|


而在实际使用过程中,我们还有可能会遇到一些复杂参数的注入,这里我也做了一些相关的技术整理。


特殊格式参数的注入


枚举字段注入


基于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="user" class="org.idea.spring.dependency.inject.type.User">
        <property name="id" value="1"></property>
        <property name="name" value="idea"></property>
        <property name="age" value="11"></property>
        <property name="cities" value="WUHAN,BEIJING,SHANGHAI" ></property>
    </bean>
</beans>
复制代码


代码案例:


package org.idea.spring.dependency.inject.type;
import javax.annotation.PostConstruct;
import java.util.Arrays;
public class User {
        private int id;
        private String name;
        private Integer age;
        private City[] cities;
        public User() {
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public City[] getCities() {
            return cities;
        }
        public void setCities(City[] cities) {
            this.cities = cities;
        }
        @PostConstruct
        public void init(){
            System.out.println("this is init");
        }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", cities=" + Arrays.toString(cities) +
                '}';
    }
}
复制代码


枚举对象


package org.idea.spring.dependency.inject.type;
public enum City{
        WUHAN,
        BEIJING,
        SHANGHAI;
        City() {
        }
    }
复制代码


注入代码案例


package org.idea.spring.dependency.inject.type;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
 * 关于枚举的注入
 *
 * @Author linhao
 * @Date created in 12:28 下午 2021/4/23
 */
public class EnumInjectDemo {
    public static void main(String[] args) {
        DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
        String xmlPath = "classpath:/META-INF/type-independency-inject.xml";
        xmlBeanDefinitionReader.loadBeanDefinitions(xmlPath);
        User user = defaultListableBeanFactory.getBean(User.class);
        System.out.println(user);
    }
}
复制代码


List集合的注入


代码案例:


package org.idea.spring.dependency.inject.type;
import java.util.List;
/**
 * @Author linhao
 * @Date created in 3:51 下午 2021/4/23
 */
public class ListObject {
    private Integer id;
    private String username;
    private List<String> list;
    public ListObject() {
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public ListObject(Integer id, String username, List<String> list) {
        this.id = id;
        this.username = username;
        this.list = list;
    }
}
复制代码


针对list类型参数的依赖注入


package org.idea.spring.dependency.inject.type;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
 * @Author linhao
 * @Date created in 3:53 下午 2021/4/23
 */
public class ListObjectInjectDemo {
    public static void main(String[] args) {
        String xmlPath = "classpath:/META-INF/type-list-independency-inject.xml";
        DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
        xmlBeanDefinitionReader.loadBeanDefinitions(xmlPath);
        ListObject listObject = defaultListableBeanFactory.getBean(ListObject.class);
        System.out.println(listObject);
    }
}
复制代码


资源文件的注入


关于资源这块的注入我们需要先引入一些properties文件作为基础


网络异常,图片无法展示
|


properties内容


user.passowrd=10001
user.email=idea@qq.com
复制代码


对应的Bean对象中使用org.springframework.core.io.Resource作为引用。


public class ResourceObject {
    private Long id;
    private String name;
    private Integer age;
    private Resource configFileResource;
    //gett sett 省略
 }
复制代码


而对应的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="user" class="org.idea.spring.dependency.inject.type.ResourceObject">
        <property name="id" value="1"></property>
        <property name="name" value="idea"></property>
        <property name="age" value="11"></property>
        <property name="configFileResource" value="classpath:/META-INF/user-config.properties" ></property>
    </bean>
</beans>
复制代码


Qualifier注解的注入


这里介绍下Qualifier这款注解。


我们常用的@Autowired注解是根据类型进行自动装配的,如果Spring的上下文中按照类型匹配出现了多个重复的bean的时候,就会抛出异常。例如下边这段代码中,存在user1,user2两个Bean,但是他们的Bean类型都是User,因此在进行自动装配的时候就会抛出异常,此时如果多加入一个@Qualifier注解,就能够同时支持@Autowired区分Bean名称来进行注入的效果了。


但是我个人习惯一般是比较推崇使用@Resource方式的注入,而且官方也并不是特别推崇@Autowired 注解。


package org.idea.spring.dependency.inject.type;
import org.idea.spring.ioc.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import javax.annotation.Resource;
/**
 * @Author linhao
 * @Date created in 4:02 下午 2021/4/23
 */
public class QualifierInjectDemo {
    @Autowired
//    @Resource
    //按照user2的名字进行字段注入,这里会注入user2的对象实例
    //如果加入了@Resource注解的话,就会注入user1对象,而且优先级比user2要高
    @Qualifier("user2")
    private User user1;
//    @Autowired
    @Resource
    private User user2;
    @Autowired
    @Qualifier //这里带有@Qualifier注解之后,会自动注入person() 这个bean
    private Person person;
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(QualifierInjectDemo.class);
        applicationContext.refresh();
        QualifierInjectDemo beanDemo = applicationContext.getBean(QualifierInjectDemo.class);
        System.out.println("user1:" + beanDemo.user1);
        System.out.println("user2:" + beanDemo.user2) ;
        System.out.println("普通:" + beanDemo.user1);
        System.out.println("person 分组:"+beanDemo.person);
        applicationContext.close();
    }
    @Bean
    @Qualifier
    public Person person(){
        return new Person(1,"idea");
    }
    @Bean
    public Person femalePerson(){
        return new Person(2,"idea2");
    }
    @Bean
    public User user1(){
        return createUser("user1");
    }
    @Bean
    public User user2(){
        return createUser("user2");
    }
    private static User createUser(String name) {
        User user = new User();
        user.setName(name);
        return user;
    }
}
复制代码


总结思考


本篇文章主要还是以实践为主,因为我个人觉得在实际工作中,用得最多方式也是


@Resource,

@Autowired这两种基于字段的注入方式,对于Spring容器有过二次开发的朋友可能会对Api的注入方式了解颇深。


在通过上述的种种实践案例分析之后,再回过头来进行思考。


依赖注入和依赖查找的比对


网络异常,图片无法展示
|


相比于主动查找来说,依赖注入总是能够一步到位地将所需要的bean给注入到容器里面,从而不需要后边再做主动查找,更加简单方便。依赖查找中肯定是要使用相应的api接口去主动查询,这对于业务代码是具有一定的侵害性,所以两种方案的选择需要进过自己去深入琢磨。


Setter注入和构造器注入有什么差别


对比两种方式来说,我个人认为都有好坏


1.首先构造器注入有着很明显的先后顺序限制,它和setter注入不同,setter注入的时候通常是由调用方来限制先后顺序的,没法像构造器一样有序地控制注入顺序。


2.构造器注入的方式来说,如果一个类里面需要注入的bean过多的时候,使用构造器注入反而写起来代码会很臃肿,比较难以维护。


3.sett注入的时候,bean可能会有新的变化,也就是说它要比构造器注入更加灵活,动态化控制注入的bean信息。


4.如果某个引入的bean需要在容器启动的时候就被初始化注入,那么使用构造器注入的方式可能更加适合。


5.对于父子继承的对象来说,使用bean的setter注入可以同时影响到子类的注入。


6.构造器注入的方式通常对于注入的bean都是具有统一的状态管理。而且java里面也是推荐一旦对象生成了,后边就不做过多的修改。


Spring内部的bean注入来源有哪些


1.自定义的bean

2.容器内初始化构建好的bean(例如说我们的enviorment对象)

3.容器内建的依赖对象 (例如说我们的beanfactory,无法通过getbean来获取)

目录
相关文章
|
14天前
|
Java 数据库 数据安全/隐私保护
轻松掌握Spring依赖注入:打造你的登录验证系统
本文以轻松活泼的风格,带领读者走进Spring框架中的依赖注入和登录验证的世界。通过详细的步骤和代码示例,我们从DAO层的创建到Service层的实现,再到Spring配置文件的编写,最后通过测试类验证功能,一步步构建了一个简单的登录验证系统。文章不仅提供了实用的技术指导,还以口语化和生动的语言,让学习变得不再枯燥。
30 2
|
5月前
|
XML Java 测试技术
Spring Boot中的依赖注入和控制反转
Spring Boot中的依赖注入和控制反转
|
4月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
62 0
|
4月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
44 2
|
4月前
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
125 0
|
5月前
|
缓存 Java Spring
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
|
6月前
|
设计模式 Java 测试技术
Spring Boot中的依赖注入详解
Spring Boot中的依赖注入详解
|
6月前
|
Java Spring 容器
spring如何进行依赖注入,通过set方法把Dao注入到serves
spring如何进行依赖注入,通过set方法把Dao注入到serves
|
5月前
|
XML Java 数据格式
深入理解Spring中的依赖注入原理
深入理解Spring中的依赖注入原理
|
5月前
|
Java Spring 容器
深入理解Spring Boot中的容器与依赖注入
深入理解Spring Boot中的容器与依赖注入
下一篇
DataWorks