【Spring框架三】——Spirng IOC和DI的实现

简介: 【Spring框架三】——Spirng IOC和DI的实现

系列文章目录

【Spring框架一】——Spring框架简介


Spirng IOC和DI的实现


前言

本篇博客主要总结的是以Spring 5为例,通过XML方式和注解的方式分别实现IOC和DI。并使用Spring5 进行基础运用。


一、IDEA新建Spring 项目

  1. 创建Maven项目:使用IDE创建一个maven项目
  2. 添加Spring依赖:在Maven配置文件pom.xml中添加Spring框架的依赖项
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.8</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.8</version>
  </dependency>
</dependencies>
  1. 这样Spring的基础环境已经搭建完毕
    项目的主体结构为三层结构,层与层之间通过接口进行隔离

二、使用XML文件的方式实现IOC和DI

实现依赖注入的方式常用的有构造函数注入setter方法注入

1.创建XML文件

在resources目录下创建applicationContext.xml文件,之后需要在xml文件中配置组件(指Spring容器中的管理的对象)和依赖关系

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

2. 通过构造函数的方式进行注入

IXMLUserDaoImpl类

package com.wangwei.springioc.dao.daoImpl;
import com.wangwei.springioc.dao.IXMLUserDao;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : UserDaoImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/9 9:04]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/9 9:04]
 * @updateRemark : [描述说明本次修改内容]
 */
public class IXMLUserDaoImpl implements IXMLUserDao {
    @Override
    public void addUser(String username, String password) {
        System.out.println("IUserDaoImpl.addUser()"+username+password);
    }
}

IXMLUserDao接口

package com.wangwei.springioc.dao;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : UserDao
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/9 9:04]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/9 9:04]
 * @updateRemark : [描述说明本次修改内容]
 */
public interface IXMLUserDao {
    void addUser(String username, String password);
}

XMLUserManagerImpl类

package com.wangwei.springioc.manager.managerImpl;
import com.wangwei.springioc.dao.IXMLUserDao;
import com.wangwei.springioc.manager.IXMLUserManager;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : UserManagerImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/9 9:03]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/9 9:03]
 * @updateRemark : [描述说明本次修改内容]
 */
public class XMLUserManagerImpl implements IXMLUserManager {
       //构造函数注入
    private  IXMLUserDao ixmlUserDao;
    public XMLUserManagerImpl(IXMLUserDao ixmlUserDao) {
        this.ixmlUserDao=ixmlUserDao;
    }
    @Override
    public void addUser(String name, String password) {
        ixmlUserDao.addUser(name,password);
    }
}

IXMLUserManager接口

package com.wangwei.springioc.manager;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : IUserManager
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/9 9:02]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/9 9:02]
 * @updateRemark : [描述说明本次修改内容]
 */
public interface IXMLUserManager {
    void addUser(String name ,String password);
}

在xml文件中配置通过构造函数的方式进行注入

由于在XMLUserManagerImpl类中通过接口依赖到了IXMLUserDaoImpl类,所以需要在xml配置其依赖关系。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="userDao" class="com.wangwei.springioc.dao.daoImpl.IXMLUserDaoImpl"/>
    <bean id="userManager" class="com.wangwei.springioc.manager.managerImpl.XMLUserManagerImpl">
        <!--构造函数注入-->
        <constructor-arg ref="userDao"/>
     </bean>
</beans>

XMLClient类进行调用

package com.wangwei.springioc.client;
import com.wangwei.springioc.manager.IXMLUserManager;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : Client
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/9 9:11]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/9 9:11]
 * @updateRemark : [描述说明本次修改内容]
 */
public class XMLClient {
    public static void main(String[] args) {
    //通过Spring的XML配置文件创建了一个IOC容器,并读取文件中的定义,创建相应的Bean对象并将它们放到IOC容器中
        BeanFactory factory=new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取名为userManager的Bean对象
        IXMLUserManager IXMLUserManager =(IXMLUserManager) factory.getBean("userManager");
        IXMLUserManager.addUser("wangwei","123");
    }
}

运行结果

3.setter方法进行注入

  1. 需要在依赖方,创建对应的setter方法
    //setter方式注入
    private IXMLUserDao ixmlUserDao;
    public void setIxmlUserDao(IXMLUserDaoImpl ixmlUserDao) {
        this.ixmlUserDao=ixmlUserDao;
    }
  1. xml文件中进行配置
<bean id="userDao" class="com.wangwei.springioc.dao.daoImpl.IXMLUserDaoImpl"/>
    <bean id="userManager" class="com.wangwei.springioc.manager.managerImpl.XMLUserManagerImpl">
        <!--setter方法注入-->
        <property name="ixmlUserDao" ref="userDao"/>
     </bean>

三、使用注解的方式实现IOC和DI

Spring 5中的常用注解

@Component

@Component是Spring框架中最基本的注解之一,它的作用是将Java类定义为一个Bean,并在程序启动的时候告诉Spring这个类需要被Spring 管理。


@Service

@Service用于标记一个类为服务类(Service class),通常是指该类用于处理业务逻辑的类。并在程序启动的时候告诉Spring这个类需要被Spring 管理。


@Repository

用于将数据访问层 (DAO) 类标记为 Spring Bean,并为其提供 Spring 特定的异常转换。在程序启动的时候告诉Spring这个类需要被Spring 管理。


@Autowired

它可以自动地为我们进行依赖注入。当一个类中有一个属性需要依赖注入时,我们可以在这个属性上面使用@Autowired注解,而在程序启动的时候Spring框架会自动找到这个属性对应的Bean,并将其注入到类中。

@Autowired注解可以用在属性、构造方法、和方法上。如果被注入的类有多个实现,可以使用@Qualifier注解来指定具体注入哪个实现。


@Bean

用于在配置类中定义一个Bean,@Bean 注解只有在 Spring 配置类中才会生效。

@Bean注解可以用在一个方法上,该方法可以创建一个对象并返回该对象的实例。这个对象会被Spring容器管理并可以被其他对象注入。

使用@Bean注解时,可以将其放置在一个类的任意方法上(通常是@Configuration注解的类中),方法返回的对象实例可以被Spring容器进行管理。在程序启动的时候告诉Spring这个类需要被Spring 管理。


@Configuration

用于标记类为配置类。在 Spring 中,配置类是一种特殊的类,用于配置应用程序上下文中的 bean。使用 @Configuration 注解的类可以包含 @Bean 注解,用于声明 bean 定义。这些 bean 可以是被 Spring 托管的任何类型。在程序启动的时候告诉Spring这个类需要被Spring 管理。


示例代码:

@Configuration
public class AppConfig {
    @Bean
    public PaymentService paymentService() {
        return new NewClassB();
    }
}

@ComponentScan

用于扫描和注册组件(包括 @Component、@Service、@Controller、@Repository 等注解修饰的类)

通过使用 @ComponentScan 注解,Spring 将会在指定的包或类中扫描组件(在 Spring 应用程序中,组件通常是指 Spring 管理的对象),然后将其实例化、初始化并将其添加到 Spring 的应用程序上下文中,以便在整个应用程序中可以使用这些组件。

@ComponentScan的常用属性:

basePackages:指定要扫描的包,可以指定多个包;

basePackageClasses:指定要扫描的类,可以指定多个类;

excludeFilters:指要排除的组件,可以使用正则表达式、类型过滤器等方式进行排除;

需要注意的是,使用 @ComponentScan 注解需要在 Spring 配置类上添加该注解,如:

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // ...
}

使用注解方式实现构造函数注入

先创建各层的类

IAnnotateDao接口

package com.wangwei.springioc.dao;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : IAnnotateDao
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 8:58]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 8:58]
 * @updateRemark : [描述说明本次修改内容]
 */
public interface IAnnotateDao {
    void addUser(String username, String password);
}

AnnotateUserDaoImpl类

package com.wangwei.springioc.dao.daoImpl;
import com.wangwei.springioc.dao.IAnnotateDao;
import org.springframework.stereotype.Repository;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : AnnotateUserDaoImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 8:59]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 8:59]
 * @updateRemark : [描述说明本次修改内容]
 */
@Repository
public class AnnotateUserDaoImpl implements IAnnotateDao {
    @Override
    public void addUser(String username, String password) {
        System.out.println("IUserDaoImpl.addUser()"+username+password);
    }
}

IAnnotateManager接口

package com.wangwei.springioc.manager;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : IAnnotateManager
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 9:03]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 9:03]
 * @updateRemark : [描述说明本次修改内容]
 */
public interface IAnnotateManager {
    void addUser(String name ,String password);
}

AnnotateManagerImpl类

成员变量被声明为 final,这是为了避免在类的其他地方意外地修改它的引用,保证其只能在构造函数中被初始化,并且在对象创建后不会再被更改。

package com.wangwei.springioc.manager.managerImpl;
import com.wangwei.springioc.dao.IAnnotateDao;
import com.wangwei.springioc.manager.IAnnotateManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : AnnotateManagerImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 9:03]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 9:03]
 * @updateRemark : [描述说明本次修改内容]
 */
@Service
public class AnnotateManagerImpl implements IAnnotateManager {
    //构造函数注入
    private final IAnnotateDao iAnnotateDao;
    @Autowired
    public AnnotateManagerImpl(IAnnotateDao iAnnotateDao) {
        this.iAnnotateDao = iAnnotateDao;
    }
    @Override
    public void addUser(String name, String password) {
        iAnnotateDao.addUser(name,password);
    }
}

AnnotateClient类

程序启动类

package com.wangwei.springioc.client;
import com.wangwei.springioc.manager.IAnnotateManager;
import com.wangwei.springioc.manager.managerImpl.AnnotateManagerImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : AnnotateClient
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 8:56]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 8:56]
 * @updateRemark : [描述说明本次修改内容]
 */
//使用@Configuration注解来告诉Spring这是一个配置类,并将其放入到ioc容器中
@Configuration
//@ComponentScan注解来指定要扫描的包路径,@ComponentScan注解会告诉Spring去哪里查找组件,它会扫描指定的包及其子包,查找使用了特定注解的类,并将它们注册为Spring的bean。
@ComponentScan(basePackages = "com.wangwei.springioc")
public class AnnotateClient {
    public static void main(String[] args) {
            //我们使用AnnotationConfigApplicationContext来加载配置类,使用MyAppApplication.class作为配置类,即告诉Spring使用MyAppApplication这个类中的注解来构建应用程序上下文
            ApplicationContext context = new AnnotationConfigApplicationContext(AnnotateClient.class);
            //使用context对象来获取我们的bean并进行依赖注入和使用。
            IAnnotateManager iAnnotateManager = context.getBean(AnnotateManagerImpl.class);
            iAnnotateManager.addUser("wangwei","123");
    }
}

运行结果

使用注解方式实现Setter方式注入

AnnotateManagerImpl类

package com.wangwei.springioc.manager.managerImpl;
import com.wangwei.springioc.dao.IAnnotateDao;
import com.wangwei.springioc.manager.IAnnotateManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : AnnotateManagerImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 9:03]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 9:03]
 * @updateRemark : [描述说明本次修改内容]
 */
@Service
public class AnnotateManagerImpl implements IAnnotateManager {
  //Setter方式进行注入
    private  IAnnotateDao iAnnotateDao;
    @Autowired
    public void setiAnnotateDao(IAnnotateDao iAnnotateDao) {
        this.iAnnotateDao = iAnnotateDao;
    }
    @Override
    public void addUser(String name, String password) {
        iAnnotateDao.addUser(name,password);
    }
}

运行效果

使用注解方式实现字段方式注入

package com.wangwei.springioc.manager.managerImpl;
import com.wangwei.springioc.dao.IAnnotateDao;
import com.wangwei.springioc.manager.IAnnotateManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : AnnotateManagerImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 9:03]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 9:03]
 * @updateRemark : [描述说明本次修改内容]
 */
@Service
public class AnnotateManagerImpl implements IAnnotateManager {
    @Autowired
    private IAnnotateDao iAnnotateDao;
    @Override
    public void addUser(String name, String password) {
        iAnnotateDao.addUser(name,password);
    }
}

运行效果

使用注解方式实现通过方法注入

AnnotateManagerImpl类

package com.wangwei.springioc.manager.managerImpl;
import com.wangwei.springioc.dao.IAnnotateDao;
import com.wangwei.springioc.manager.IAnnotateManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * @author : [WangWei]
 * @version : [v1.0]
 * @className : AnnotateManagerImpl
 * @description : [描述说明该类的功能]
 * @createTime : [2023/5/10 9:03]
 * @updateUser : [WangWei]
 * @updateTime : [2023/5/10 9:03]
 * @updateRemark : [描述说明本次修改内容]
 */
@Service
public class AnnotateManagerImpl implements IAnnotateManager {
    private IAnnotateDao iAnnotateDao;
    @Autowired
    public void anotateIAnnotateDao(IAnnotateDao iAnnotateDao){
        this.iAnnotateDao=iAnnotateDao;
    }
    @Override
    public void addUser(String name, String password) {
        iAnnotateDao.addUser(name,password);
    }
}

运行结果

每种注入方式的优缺点

构造函数注入的优缺点

优点:

  1. 对象的完整性:通过构造函数注入,可以保证在创建对象时所需要的所有依赖都被满足,从而确保对象的完整性。
  2. 对象不可变:通过构造函数注入,可以将依赖关系作为对象的不可变属性,防止意外修改对象依赖。

缺点:

  1. 冗长:需要编写额外的构造函数,增加代码量。
  2. 限制:在对象创建后无法更改依赖关系。

Setter方法注入的优缺点

优点:

  1. 灵活:可以在任何时候更改依赖关系,不受对象创建时依赖关系的限制。
  2. 可选性:某些依赖关系不是必需的,可以使用setter方法注入来提供可选依赖项。

缺点:

  1. 对象可变性:setter方法注入会使对象变得可变,因为依赖关系可以随时更改。
  2. 不够显式:相对于构造函数注入,setter方法注入可能导致依赖关系不够显式和清晰。

字段注入的优缺点

优点:

  1. 简单方便:字段注入是一种简单方便的依赖注入方式,无需编写额外的代码。
  2. 可选性:某些依赖关系不是必需的,可以使用字段注入来提供可选依赖项。

缺点:

  1. 对象可变性:字段注入会使对象变得可变,因为依赖关系可以随时更改。
  2. 不够显式:相对于构造函数注入,字段注入可能导致依赖关系不够显式和清晰。

方法注入的优缺点

优点:

  1. 灵活性:方法注入可以在任何时候更改依赖关系,不受对象创建时依赖关系的限制。

缺点:

  1. 冗长:需要编写额外的方法,增加代码量。

四、总结

  1. XML和注解实现的IOC和DI是两种不同的方式,它们都可以用于管理应用程序中的组件和依赖关系。
  2. 在实际开发中,通常使用注解来代替XML,这是因为注解更加方便、简洁和易于维护,而且可以让开发者更加专注于业务逻辑的实现。
  3. 相比之下,XML需要编写更多的代码,需要手动配置依赖关系,维护起来相对麻烦一些。不过,使用XML的好处是可以更加灵活地配置和管理应用程序,可以在不修改代码的情况下改变应用程序的行为。

总的来说,使用注解可以使开发更加高效,使用XML可以使配置更加灵活,具体使用哪种方式取决于项目的需求和开发者的偏好。

目录
相关文章
|
6天前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld
|
3天前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
13 4
|
9天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
527 5
|
7天前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
29 3
|
7天前
|
XML 前端开发 Java
控制spring框架注解介绍
控制spring框架注解介绍
|
7天前
|
存储 NoSQL Java
Spring Session框架
Spring Session 是一个用于在分布式环境中管理会话的框架,旨在解决传统基于 Servlet 容器的会话管理在集群和云环境中的局限性。它通过将用户会话数据存储在外部介质(如数据库或 Redis)中,实现了会话数据的跨服务器共享,提高了应用的可扩展性和性能。Spring Session 提供了无缝集成 Spring 框架的 API,支持会话过期策略、并发控制等功能,使开发者能够轻松实现高可用的会话管理。
Spring Session框架
|
14天前
|
Java 应用服务中间件 开发者
深入探索并实践Spring Boot框架
深入探索并实践Spring Boot框架
25 2
|
14天前
|
机器学习/深度学习 数据采集 JavaScript
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
ADR药品不良反应监测系统是一款智能化工具,用于监测和分析药品不良反应。该系统通过收集和分析病历、处方及实验室数据,快速识别潜在不良反应,提升用药安全性。系统采用Java开发,基于SpringBoot框架,前端使用Vue,具备数据采集、清洗、分析等功能模块,并能生成监测报告辅助医务人员决策。通过集成多种数据源并运用机器学习算法,系统可自动预警药品不良反应,有效减少药害事故,保障公众健康。
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
|
2月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
4月前
|
XML Java 数据格式
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
40 1
下一篇
无影云桌面