一文讲透Spring的IOC反转控制

简介: 一文讲透Spring的IOC反转控制

Spring的底层核心是IOC和AOP,本文讲解IOC的两种注入案例,让我们一文掌握全部核心知识!

IOC,英文全称Inversion of Control,意思是反转控制,原先new一对象是手工操作,现在交给spring容器,在大规模项目中减少人工代码,做到解耦、高效的目的!

案例:DI操作(xml驱动)

在之前HelloWorld项目上做个简单扩展,进行DI(Dependency Injection)操作的案例:

这里做了一个最精简的演示,通过演示可以看到,如果有多类适配器(子类),只需要修改配置文件,就完成了装配改装,而没有修改java代码! 这就是spring解耦的魅力!

1、准备demo程序

// 这里准备了一个接口,2个实现类,实现不同语种的欢迎词反馈,用于测试代码的调用时不需要修改一行代码,仅需修改配置文件完成功能的切换!
public interface UserService {
    public String sayHello();
}
public class UserServiceImpl1 implements UserService {
    public String sayHello() {
        return "Nice to meet you!";
    }
}
public class UserServiceImpl2 implements UserService {
    public String sayHello() {
        return "你好啊";
    }
}

2、修改配置文件

<bean class="com.iyyxx.HelloWorld" id="helloWorld">
        <property name="userService" ref="userServiceImpl2"/> <!-- ref这里可以替换为userServiceImpl1或userServiceImpl2查看效果 -->
    </bean>
<bean class="com.iyyxx.service.impl.UserServiceImpl1" id="userServiceImpl1"/>
<bean class="com.iyyxx.service.impl.UserServiceImpl2" id="userServiceImpl2"/>

3、编写测试代码

public class HelloWorld {
    private UserService userService;
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    public String say2(){
        return userService.sayHello();
    }
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class);
        System.out.println(helloWorld.say2());
    }
}

DI的魅力就在于不修改一行java代码,对配置文件进行简单修改就完成了重新装配!

遍历!基于xml的DI注入方式

1、xml配置(这里演示的是set方法的三种注入方式,还可以通过构造函数,还有复杂类型list、set、map等)

<!-- 1、Bean的定义,核心属性class、id -->
<bean class="com.iyyxx.service.impl.UserServiceImpl1" id="userServiceImpl1"/>
<!-- 2、Bean的手工赋值,在set接口采用value入口 -->
<bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao">
  <properties name="userName" value="张三" />
</bean>
<!-- 3、Bean的手工赋值,在构造函数接口采用constructor-arg入口 -->
<bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao">
  <constructor-arg name="userName" value="张三"/>
  <constructor-arg name="userAge" value="15"/>
</bean>
<!-- 4、Bean的引用传递,采用ref入口 -->
<bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao">
  <properties name="userService" ref="userServiceImpl1" /> <!-- 这里ref指向其他被管理Bean,可以是id或class -->
</bean>
<!-- 5、配置文件读取,常见jdbc连接信息尾部设定、spring引用的方式,组合式操作,用${xx.xx}方式进行set或构造函数注入 -->
<bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao">
  <properties name="password" ref="${xx.yy.zz}" />
</bean>
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>  <!--读取properties文件-->
<!-- 6、集合的注入方式 -->
<bean class="com.iyyxx.dao.impl.StudentDaoImpl" id="studentDao">
  <properties name="list">
    <list>
      <value>xxx</value>
      <value>yyy</value>
    </list>
  </properties>
  <properties name="set">
    <set>
      <value>xxx</value>
      <value>yyy</value>
    </set>
  </properties>
  <properties name="aryyay">
    <array>
      <value>xxx</value>
      <value>yyy</value>
    </array>
  </properties>
  <properties name="properties">
    <props>
      <prop key="k1">v1</prop>
      <prop key="k2">v2</prop>
    </props>
  </properties>
  <properties name="map">
    <map>
      <entry key="k1" value-ref="phone"/>
      <entry key="k2" value-ref="phone"/>
    </map>
  </properties>
</bean>

遍历!基于注解的DI注入方式

注解驱动的di注入有两个注解可以使用

  • @Autowired,可作用于
  • 成员变量(常用)
  • 构造函数(官方Spring4推荐,但臃肿不易阅读)
  • 方法上,比较诡异
  • @Value,常用于配置文件读取

前置要求:容器配置类已做了包扫描或手工声明,所需bean均已容器化管理,实例如下:

@Configuration
public class SpringConfig {
    @Bean
    public HelloWorld helloWorld(){
        return new HelloWorld();
    }
    @Bean
    public UserService userService(){
        return new UserServiceImpl1();
    }
}
//方案2,比较常用,需要配置器开启@ComponentScan,所有的bean也有Bean声明标签,如@Component、@Service、@Controller
@ComponentScan(basePackages = "com.iyyxx")
public class SpringConfig {
}
@Component
public class HelloWorld {
}
@Service
public class UserServiceImpl1 implements UserService {
}

使用介绍:有了上面的铺垫,使用是很丝滑的,仅仅只是用上@Autowired,除非有多个实现类则需使用==@Qulifier进行特殊指定==

@Component
public class HelloWorld {
    @Autowired
    @Qualifier("userServiceImpl2") //这里有2个实现类,所以用类型的驼峰命名法可以快速指定,当然也可以在bean上面指定别名!
    private UserService userService;
    public String say(){
        return "Hello Spring by Annotation";
    }
    public String say2(){
        return userService.sayHello();
    }
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class);
        System.out.println(helloWorld.say());
        System.out.println(helloWorld.say2());
    }
}

这里补充下基于构造器、方法的注入方式

//构造器注入方式
@Component
public class HelloWorld {
    private UserService userService;
    @Autowired
    public HelloWorld(@Qualifier("userServiceImpl2") UserService userService) {
        this.userService = userService;
    }
    public String say2(){
        return userService.sayHello();
    }
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class);
        System.out.println(helloWorld.say2());
    }
}
//方法注入方式
@Component
public class HelloWorld {
    private UserService userService;
    @Autowired
    public void setUserService(@Qualifier("userServiceImpl2") UserService userService) {
        this.userService = userService;
    }
    public String say2(){
        return userService.sayHello();
    }
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        HelloWorld helloWorld = (HelloWorld) applicationContext.getBean(HelloWorld.class);
        System.out.println(helloWorld.say2());
    }
}

注解驱动方式下获取properties文件属性有两点:

  • 类上面使用@PropertySource并指定文件名(如果有多级路径就加路径)
  • 类中使用成员变量+@Value标签,并使用${xx.xx}方式获取配置信息

实例如下:

@Service
@PropertySource("jdbc.properties")
public class UserServiceImpl2 implements UserService {
    @Value("${jdbc.username}")
    private String userName;
    public String sayHello() {
        return "你好啊 "+userName;
    }
}

结语

Spring 学习因三种DI的编码方式让学习起来特别辛苦,虽说目前已面向纯注解的开发方式,但依旧存在一些历史项目、复杂架构需要接收,多学点总是没错的,是不是还不过瘾,后面还有一系列的【一文讲解透】系列分享给大家!

相关文章
|
2月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
10月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
786 26
|
6月前
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
201 1
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
7月前
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
|
XML Java 数据格式
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
275 69
|
9月前
|
Java 容器 Spring
什么是Spring IOC 和DI ?
IOC : 控制翻转 , 它把传统上由程序代码直接操控的对象的调用权交给容 器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转 移,从程序代码本身转移到了外部容器。 DI : 依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中。
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
198 21
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
509 12