关于Spring Ioc容器的理解和使用

作为一个以项目为驱动的程序员,我以为学习一项技术时,很少在使用它之前就系统地学习过这项技术,深刻地理解这项技术的由来。所以快速学习如何使用技术成为程序员的基本操作,但如果只有基本操作无疑提升很慢,想要进步,还是要根据应用继续学习原理。因此学习顺序从上学时候的"是什么-为什么-怎么做",变成了"怎么用-为什么-是什么"。

所以今天从怎么用容器开始理解。

怎么用

new一个对象

在我们还不懂什么是"面向对象"时,就学会了创建对象。一个类中想调用另一个类中的方法,当然要先new一个对象。TestController中想要使用TestService的方法,需要先初始化一个TestServiceImpl的对象,在哪一步调用,就在哪一步创建对象,因此这两个方法中各创建了一个对象。

java 复制代码
package com.example.demo.controller;

import com.example.demo.service.TestService;
import com.example.demo.service.impl.TestServiceImpl;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/test1")
    public void test1() {
        TestService testService = new TestServiceImpl();
        testService.test1();
    }

    @GetMapping("/test2")
    public void test2() {
        TestService testService = new TestServiceImpl();
        testService.test2();
    }

}
typescript 复制代码
package com.example.demo.service.impl;

import com.example.demo.service.TestService;

public class TestServiceImpl implements TestService {

    @Override
    public void test1() {
        System.out.println("this is test1");
    }

    @Override
    public void test2() {
        System.out.println("this is test2");
    }
}

如果有更多的方法,每个方法都需要这个类的对象,那么更好的方法是把这个对象变成一个公共对象。

kotlin 复制代码
package com.example.demo.controller;

import com.example.demo.service.TestService;
import com.example.demo.service.impl.TestServiceImpl;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {

    TestService testService = new TestServiceImpl();

    @GetMapping("/test1")
    public void test1() {
        testService.test1();
    }

    @GetMapping("/test2")
    public void test2() {
        testService.test2();
    }

}

把testService变成一个成员对象后,就省去了每次调用前先创建对象的步骤。但如果别的类中也需要一个TestService的对象呢?

kotlin 复制代码
package com.example.demo.controller;

import com.example.demo.service.TestService;
import com.example.demo.service.impl.TestServiceImpl;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test2")
public class TestTwoController {

    TestService testService = new TestServiceImpl();

    @GetMapping("/test1")
    public void test1() {
        testService.test1();
    }

    @GetMapping("/test2")
    public void test2() {
        testService.test2();
    }

}

创建全局对象

这样每个需要TestService的类中都需要创建对象,但其实我只需要一个对象,怎么让这个对象再公共一点呢?我想到一个好方法,一个简单的单例模式

java 复制代码
package com.example.demo.util;

import com.example.demo.service.TestAService;
import com.example.demo.service.TestBService;
import com.example.demo.service.TestService;
import com.example.demo.service.impl.TestAServiceImpl;
import com.example.demo.service.impl.TestBServiceImpl;
import com.example.demo.service.impl.TestServiceImpl;

public class ObjectUtil {

    private static TestService testService = new TestServiceImpl();

    private static TestAService testAService = new TestAServiceImpl();

    private static TestBService testBService = new TestBServiceImpl();

    public static TestService getTestService() {
        return testService;
    }

    public static TestAService getTestAService() {
        return testAService;
    }

    public static TestBService getTestBService() {
        return testBService;
    }

}

这样每个需要引用这个对象的地方,只需要获取就可以了

ini 复制代码
TestService testService = ObjectUtil.getTestService();

TestAService testAService = ObjectUtil.getTestAService();

TestBService testBService = ObjectUtil.getTestBService();

写到这里,还有一些问题需要解决,比如,每一个需要全局对象的类都要创建,一个项目中那么多类,写的完吗?比如,初始化对象时如果需要参数怎么办?比如,每个对象有没有作用域之分?

这就是Spring容器要解决的问题了。

@Component注解的使用

在web项目中,controller层要用@RestController的注解,service层要用@Service的注解,配置要用@Configuration,这些注解都是由一个@Component衍生来的。@Component就是需要创建对象的信号了。

typescript 复制代码
package com.example.demo.service.impl;

import com.example.demo.service.TestService;
import org.springframework.stereotype.Service;

@Service
public class TestServiceImpl implements TestService {

    @Override
    public void test1() {
        System.out.println("this is test1");
    }

    @Override
    public void test2() {
        System.out.println("this is test2");
    }
}
kotlin 复制代码
package com.example.demo.controller;

import com.example.demo.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    TestService testService;

    @GetMapping("/test1")
    public void test1() {
        testService.test1();
    }

    @GetMapping("/test2")
    public void test2() {
        testService.test2();
    }

}

首先在TestServiceImpl上加@Service的注解,然后在需要用到TestService对象的地方加上@Autowired的注解,这两个注解配合,在项目中就完全省去了创建对象这个步骤。

至此,虽然还不完全理解容器,但已经会使用容器了。

为什么

关于为什么这么用,以上述简单的操作可以得到浅显的认知:每次都要创建对象,管理对象太麻烦,对象又要占用堆内存。我想要一个工具,能帮我实现管理对象,包括对象的初始化、对象的保存、对象的使用、对象的销毁等等。并且这个工具最好让我写代码时能无感使用,我不需要关心每个对象的具体创建过程,直接能使用每个对象的核心方法。

是什么

那么容器到底是什么?

概念层面看,管理对象的东西就叫容器。 代码层面看,以上操作中的ObjectUtil,就是我们自己写的容器。Spring中的容器叫ApplicationContext,而Spring容器所管理的对象,就是bean。

以上操作从我们自己创建对象变成了由容器创建对象,这就是控制反转,即Inversion of Control (IoC)。

相关推荐
先睡2 小时前
Redis的缓存击穿和缓存雪崩
redis·spring·缓存
Piper蛋窝5 小时前
深入 Go 语言垃圾回收:从原理到内建类型 Slice、Map 的陷阱以及为何需要 strings.Builder
后端·go
Bug退退退1236 小时前
RabbitMQ 高级特性之死信队列
java·分布式·spring·rabbitmq
六毛的毛8 小时前
Springboot开发常见注解一览
java·spring boot·后端
AntBlack8 小时前
拖了五个月 ,不当韭菜体验版算是正式发布了
前端·后端·python
31535669138 小时前
一个简单的脚本,让pdf开启夜间模式
前端·后端
uzong8 小时前
curl案例讲解
后端
一只叫煤球的猫9 小时前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
大鸡腿同学10 小时前
身弱武修法:玄之又玄,奇妙之门
后端
轻语呢喃12 小时前
JavaScript :字符串模板——优雅编程的基石
前端·javascript·后端