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注解的扩展,即它是最通用的。

相关推荐
何苏三月1 小时前
SpringCloud系列 - Seata 分布式事务(六)
分布式·spring·spring cloud
写不出来就跑路1 小时前
SpringBoot静态资源与缓存配置全解析
java·开发语言·spring boot·spring·springboot
墨着染霜华1 小时前
Caffeine的tokenCache与Spring的CaffeineCacheManager缓存区别
java·spring·缓存
vx_bscxy3222 小时前
springboot排课系统 -计算机毕业设计源码-23791
spring boot·后端·课程设计
程序猿小D3 小时前
[附源码+数据库+毕业论]基于Spring Boot+mysql+vue结合内容推荐算法的学生咨询系统
数据库·vue.js·spring boot·mysql·毕业设计·推荐算法·学生咨询系统
大菠萝学姐3 小时前
基于Spring Boot和Vue的高校图书馆座位预约系统的设计与实现
java·vue.js·spring boot·后端·python·mysql·vue
信码由缰3 小时前
Spring框架中的Component与Bean注解
java·spring
Re2754 小时前
快速理解Spring Bean 实例化与初始化全过程
后端·spring
程序员秘密基地4 小时前
基于html,css,vue,vscode,java,springboot,mysql数据库,在线考勤,管理系统
java·vue.js·spring·html·web app
paopaokaka_luck4 小时前
基于Spring Boot+Vue的巴彦淖尔旅游网站(AI问答、腾讯地图API、WebSocket及时通讯、支付宝沙盒支付)
数据库·vue.js·spring boot·websocket·mysql·毕业设计·旅游