Spring Framework 作为一个抢先的企业级开发结构,以其强壮的依靠注入(Dependency Injection,DI)机制而出名。DI使得开发者可以愈加灵敏地办理目标之间的联络,而不用过多重视目标的创建和拼装。在Spring Framework中,依靠注入可以分为两种类型:依据Bean称号注入、依据Bean类型注入,在本文中,咱们将聚焦于 Spring 中的一种依靠注入办法——按类型注入,并经过一个简略的示例来说明其运用和优势。

什么是依靠注入?

don’t call us, we’ll call you

依靠注入是一种先进的设计思维,它经过外部注入依靠目标来完成组件之间的松耦合。在 Spring 结构中,依靠注入的中心完成便是经过操控回转(Inversion of Control,IoC)容器。IoC 容器担任实例化、装备和拼装应用中的目标,并在需求时将它们智能地注入到其他目标中。相较于传统的面向目标思维,当业务代码变得复杂时,经过直接运用 new 进行目标结构目标间的联络,容易导致代码耦合度的上升。Spring 经过操控回转巧妙地处理了这一问题,运用了好莱坞原则的理念:不要给咱们打电话,咱们会给你打电话。这种思维使得代码愈加灵敏、可保护,并促进了更优雅的代码结构。

Spring Framework IoC依靠注入-按Bean类型注入


Spring 中的依靠注入

在 Spring 中,依靠注入有多种办法,包括结构函数注入、Setter 办法注入、接口注入等。示例中展现的是一种基于 XML 装备的 Setter 办法注入。

结构函数注入的事例:

public class UserService {
    private final EmailService emailService;
    // 结构函数注入
    public UserService(EmailService emailService) {
        this.emailService = emailService;
    }
    public void sendWelcomeEmail(String username) {
        String message = "Welcome, " + username + "!";
        emailService.sendEmail("welcome@example.com", message);
    }
}

Setter 办法注入的事例:

public class NotificationServiceClient {
    private NotificationService notificationService;
    // Setter 办法注入
    public void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
    public void sendNotification(String message) {
        notificationService.notifyUser(message);
    }
}
```java
### 接口注入的事例:

public class LoggingService {

private Logger logger;
// 接口注入
public void setLogger(Logger logger) {
    this.logger = logger;
}
public void logMessage(String message) {
    logger.log(message);
}

}


在本文中以闻名IP:小马哥在《小马哥讲 Spring 中心编程思维》中运用的代码事例打开。
Github源码:
[GeekTime](https://gitee.com/geektime-geekbang/geekbang-lessons.git)
dependency-injection-context.xml
```xml
<!-- 经过导入复用 dependency-lookup-context.xml -->
<import resource="dependency-lookup-context.xml"/>
<!-- Auto-Wiring: 按类型注入 -->
<bean id="userRepository" class="org.thinging.in.spring.ioc.overview.repository.UserRepository" autowire="byType">
</bean>

dependency-lookup-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
<!--    <context:annotation-config/>-->
<!--    <context:component-scan base-package="org.acme" />-->
    <!-- Root BeanDefinition 不需求兼并,不存在 parent -->
    <!-- 一般 beanDefinition GenericBeanDefinition -->
    <!-- 经过兼并后 GenericBeanDefinition 变成 RootBeanDefinition -->
    <bean id="user" class="org.geekbang.thinking.in.spring.ioc.overview.domain.User">
        <property name="id" value="1"/>
        <property name="name" value="小马哥"/>
        <property name="city" value="HANGZHOU"/>
        <property name="workCities" value="BEIJING,HANGZHOU"/>
        <property name="lifeCities">
            <list>
                <value>BEIJING</value>
                <value>SHANGHAI</value>
            </list>
        </property>
        <property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
    </bean>
    <!-- 一般 beanDefinition GenericBeanDefinition -->
    <!-- 兼并后 GenericBeanDefinition 变成 RootBeanDefinition,而且覆盖 parent 相关装备-->
    <!-- primary = true , 增加了一个 address 属性 -->
    <bean id="superUser" class="org.geekbang.thinking.in.spring.ioc.overview.domain.SuperUser" parent="user"
          primary="true">
        <property name="address" value="杭州"/>
    </bean>
    <bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
        <property name="targetBeanName" value="user"/>
    </bean>
</beans>

在这个比如中,咱们经过 XML 装备文件导入了 dependency-lookup-context.xml,并装备了一个名为 userRepositoryUserRepository Bean,并经过 autowire=”byType” 完成了自动按类型注入。这样,Spring 容器会在运行时查找并注入与 UserRepository 类型匹配的 User 目标。

UserRepository 类

public class UserRepository {
    /**
     * 自定义Bean
     */
    private Collection<User> users;
    public Collection<User> getUsers() {
        return users;
    }
    public void setUsers(Collection<User> users) {
        this.users = users;
    }
}

UserRepository 类中定义了一个名为 users 的调集属性,并供给了相应的 Getter 和 Setter 办法。经过 Setter 办法,咱们可以在 Spring 容器中装备的时候注入一组 User 目标。

主程序

public static void main(String[] args) {
    // 装备 XML 装备文件
    // 发动 Spring 应用上下文
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
    UserRepository userRepository = beanFactory.getBean("userRepository", UserRepository.class);
    System.out.println(userRepository.getUsers());
}

在主程序中,咱们经过 ClassPathXmlApplicationContext 加载了 XML 装备文件,获取了名为 userRepositoryUserRepository Bean,并输出了其间包括的 User 目标调集。

定论

经过这个简略的示例,咱们了解了 Spring Framework 中依靠注入的基本原理。依靠注入经过操控回转容器完成,使得应用程序中的目标不再担任办理自己的依靠联络,而是由 IoC 容器担任。这种设计模式降低了组件之间的耦合度,提高了代码的可测试性和可保护性,是 Spring 成功的要害之一。在实践项目中,咱们可以依据需求选择合适的依靠注入办法,使代码愈加明晰、灵敏且易于保护。

后续内容文章持续更新中…

近期发布。


关于我

你好,我是Debug.c。微信大众号:种颗代码技能树 的保护者,一个跨专业自学Java,对技能保持酷爱的bug猿,同样也是在某二线城市打拼四年余的Java Coder。

在、CSDN、大众号我将共享我最近学习的内容、踩过的坑以及自己对技能的理解。

假如您对我感兴趣,请联络我。

若有收成,就点个赞吧,喜欢原图请私信我。