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

相关文章
|
15小时前
|
XML Java 数据格式
Spring IoC容器初始化过程(xml形式)
Spring IoC容器初始化过程(xml形式)
52 0
|
15小时前
|
Java Spring
Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)
Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)
|
15小时前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
22 0
|
15小时前
|
Java 数据库连接 API
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
55 0
|
15小时前
|
XML Java 程序员
Spring特性之二——IOC控制反转
Spring特性之二——IOC控制反转
15 4
|
15小时前
|
安全 Java 开发者
在Spring框架中,IoC和AOP是如何实现的?
【4月更文挑战第30天】在Spring框架中,IoC和AOP是如何实现的?
22 0
|
15小时前
|
XML Java 程序员
什么是Spring的IoC容器?
【4月更文挑战第30天】什么是Spring的IoC容器?
20 0
|
15小时前
|
Java Spring 容器
【Spring系列笔记】IOC与DI
IoC 和 DI 是面向对象编程中的两个相关概念,它们主要用于解决程序中的依赖管理和解耦问题。 控制反转是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入和依赖查找。
34 2
|
15小时前
|
Java 测试技术 数据库连接
Spring中ioc的优点
总之,Spring中的IoC提供了一种更加灵活、可维护、可测试和可扩展的方式来管理组件之间的依赖关系,从而提高了应用程序的质量和可维护性。这使得开发人员能够更专注于业务逻辑而不是底层的技术细节。
32 1
|
15小时前
|
Java 应用服务中间件 Spring