spring依赖注入

IOC容器

首先我们需要知道Spring框架的核心组件,那就是IOC容器,如果没有IOC容器,那么就没有Spring框架。

SpringBean

在Spirng中,任何的java对象都会通过IOC容器而被转化成Bean,这其实是spring对象的一种称呼,在Spring框架里面,我们通常称JAVA对象为bean。而由应用程序主干和IOC容器管理的Java对象统称为beans。其实大部分的bean都是由接口+实现类组成的。因此用户想要获得bean直接从IOC容器里面获得就可以了,而不需要关心实现类。

Spring的配置元数据的格式

Spring配置元数据的格式有两种,第一种是基于xml的,另一种则就是基于Annotation的。我们暂且不管第一种,先用第二种实现。

Spring的Annotation类型来启动IOC容器

其中Annotation对应的类如下所示:

kotlin 复制代码
org.springframework.context.annotation.AnnotationConfigApplicationContext

我们直接举一个例子来启动:

java 复制代码
package fm.douban;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import fm.douban.service.SongService;
import fm.douban.model.Song;

/**
 * Application
 */
public class Application {

  public static void main(String[] args) {
    //这里则是启动fm.douban包下引用了spring注解的类
    ApplicationContext context = new AnnotationConfigApplicationContext("fm.douban");
    // 从容器中获取歌曲服务。
    SongService songService = context.getBean(SongService.class);
    // 获取歌曲
    Song song = songService.get("001");
    System.out.println("得到歌曲:" + song.getName());

  }
}

大家可以看出,上面的从容器中获得歌曲服务为什么不直接这样子写呢?

ini 复制代码
SongService sogService = new SongServiceImpl();
Song song = songService.get("001");

这样子不是更简单嘛?但是我想问你一下。假如出现以下的情况:

即一个Service依赖了非常多的Service,我们需要写多少行代码啊。如下面代码所示:

ini 复制代码
SubjectService subjectService = new SujectServiceImpl();
SongService songService = new SongServiceImpl();
MusicService MusicService = new MusicServiceImpl();
songService.setMusicService(MusicService);
subjectService.setSongService(songService);

使用注解来解决方案

但是如果我们添加了注解让Spring自动管理实例。例如添加 @Service 注解将SongServiceImplSubjectServiceImpl的服务都实现,都标记成 Spring Bean 。如果我们想要使用服务,那么直接使用 AutoWired 注解标记即可。如下面代码所示:

typescript 复制代码
public class SubjectServiceImpl implements SubjectService {

    private SongService songService;
    
    private MusicService musicService;

    //缓存所有专辑数据
    private static Map<String, Subject> subjectMap = new HashMap<>();

    static {
        Subject subject = new Subject();
        //... 省略初始化数据的过程
        subjectMap.put(subject.getId(), subject);
    }

    @Override
    public Subject get(String subjectId) {
        Subject subject = subjectMap.get(subjectId);
        //调用 SongService 获取专辑歌曲
        List<Song> songs = songService.list(subjectId);
        subject.setSongs(songs);
        return subject;
    }

    public void setSongService(SongService songService) {
        this.songService = songService;
    }
}

上面的代码是没有添加注解的,我们可以看到还需要调用setSongService()方法来传入实例,非常麻烦。但是如果将其转化为下面就非常简便了。

java 复制代码
import fm.douban.model.Song;
import fm.douban.model.Subject;
import fm.douban.service.SongService;
import fm.douban.service.SubjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SubjectServiceImpl implements SubjectService {

    @Autowired
    private SongService songService;
    
    @AutoWired
    private MusicService musicService;

    //缓存所有专辑数据
    private static Map<String, Subject> subjectMap = new HashMap<>();

    //这里的static代码块代表这个代码块只会在类的加载时被执行一次。
    static {
        Subject subject = new Subject();
        subject.setId("s001");
        //... 省略初始化数据的过程
        subjectMap.put(subject.getId(), subject);
    }

    @Override
    public Subject get(String subjectId) {
        Subject subject = subjectMap.get(subjectId);
        //调用 SongService 获取专辑歌曲
        List<Song> songs = songService.list(subjectId);
        subject.setSongs(songs);
        return subject;
    }
}

Spring注解总结和拓展

总结

@Service@AutoWired这两个注解是相辅相成的,即如果没有前者的Spring自动管理,又或者没有后者的注解标记。都无法完成依赖注入。

拓展

Spring官方声明为Spring Bean的注解有以下几种。

  • org.springframework.stereotype.Service
  • org.springframework.stereotype.Component
  • org.springframework.stereotype.Controller
  • org.springframework.stereotype.Repository

这四个注解都可以被IOC容器加载,一般的实现类都用Service注解,而web服务则使用Controller注解,其中的三种注解都是Component注解的扩展,即它是最通用的。

相关推荐
直奔標竿16 分钟前
Java开发者AI转型第二十五课!Spring AI 个人知识库实战(四)——RAG来源追溯落地,拒绝AI幻觉
java·开发语言·人工智能·spring boot·后端·spring
薪火铺子2 小时前
Spring Security 6.x 实战指南
java·后端·spring
敖正炀2 小时前
WebFlux 深度:Reactor 线程模型、背压与错误处理
spring boot
BING_Algorithm2 小时前
一文搞定 AOP 所有核心知识点
spring boot·后端·spring
Cyan_RA92 小时前
SpringMVC 请求数据绑定与参数映射 详解
java·后端·spring·mvc·springmvc·映射请求数据
勿忘初心12213 小时前
【Java实战】SpringBoot 集成 freemarker 导出 Word 模板
java·spring boot·freemarker·模板引擎·word导出·后端实战
绿草在线3 小时前
SpringBoot项目实战:从零搭建高效开发环境
java·spring boot·后端
Java成神之路-4 小时前
多 Filter、多 Interceptor 执行优先级控制方案
spring·java web
java1234_小锋4 小时前
Spring AI 2.0 开发Java Agent智能体 - Spring AI项目调用本地Ollama模型
java·人工智能·spring·spring ai2.0
二哈赛车手4 小时前
新人笔记---多策略搭建策略执行链实现RAG检索后过滤
java·笔记·spring·设计模式·ai·策略模式