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 注解将SongServiceImpl
和SubjectServiceImpl
的服务都实现,都标记成 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
注解的扩展,即它是最通用的。