Spring学习系列(三) 通过Java代码装配Bean
上面梳理了通过注解来隐式的完成了组件的扫描和自动装配,下面来学习下如何通过显式的配置的装配bean
二、通过Java类装配bean
在前面定义了HelloWorldConfig类,并使用@ComponentScan和@Configuration注解,@Configuration注解表明了这个类是一个java配置类,该类用在获取Spring应用上下文时,告诉Spring创建bean的细节,通过@ComponentScan,我们启用了Spring的自动组件扫描,现在就让我们来看如果通过java类来显式的配置bean,下面我们通过一个音乐播放器的案例来实践一下。
我们播放音乐,首先需要一个播放器,然后需要音乐资源,首先我们定义一个播放器接口和音乐资源接口
package com.seven.springTest.service;
// 播放器
public interface MediaPlayer {
void play();
}
package com.seven.springTest.service;
// 音乐资源
public interface MusicSource {
void play();
}
本次播放音乐我们是光驱来播放cd音乐,下面我们来实现上面的接口,
package com.seven.springTest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.seven.springTest.service.MusicSource;
import com.seven.springTest.service.MediaPlayer;
//定义光驱播放器
public class CDPlayer implements MediaPlayer {
@Autowired
// 定义一个音乐资源,这里通过@Autowired来声明需要注入MusicSource的依赖
private MusicSource cd ;
@Override
public void play() {
//播放音乐
cd.play();
}
}
实现音乐资源为光盘
package com.seven.springTest.service.impl;
import com.seven.springTest.service.MusicSource;
public class CDSource implements MusicSource {
private String title = "七里香";
private String artist = "周杰伦";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
到目前为止我们已经完成播放器、音乐资源的接口定义和具体的实现,那么我们如果告诉Spring应该创建哪么bean,并为它们注入什么依赖呢?在第一部分,我们通过@Component注解来隐式的告诉Spring,现在我们通过java类来配置bean组件。
@Bean
@Bean注解告诉Spring函数将返回一个对象,该对象需要注册为Spring应用上下文中的bean,该方法中包含了产生bean实例的逻辑
package com.seven.springTest.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.seven.springTest.service.MusicSource;
import com.seven.springTest.service.MediaPlayer;
import com.seven.springTest.service.impl.CDPlayer;
import com.seven.springTest.service.impl.CDSource;
@Configuration
public class MediePlayerConfig {
@Bean //该方法返回的MusicSource对象需要注册为Spring应用上下文中的bean
public MusicSource cdsource(){
return new CDSource();
}
@Bean //该方法返回的MediaPlayer对象需要注册为Spring应用上下文中的bean
public MediaPlayer cdplayer(){
return new CDPlayer();
}
}
MediePlayerConfig类中,我们只添加了@Configuration注解,之前的@ComponentScan注解移除了,没有配置启动Spring的组件扫描,另外接口的实现类也没有添加@Component注解,我们通过@Bean注解来告诉Spring哪些对象需要被注册为Spring应用上下文中的bean。cdsource()方法返回了一个MusicSource类型的实例对象CDSource,该对象被注册到Spring应用上下文,同样的cdplayer()方法返回了一个MediaPlayer类型的实例CDPlayer注册到Spring应用上下文中。下面我们来测试下
package com.seven.springTest.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.seven.springTest.Configuration.MediePlayerConfig;
import com.seven.springTest.Configuration.HelloWorldConfig;
import com.seven.springTest.service.MediaPlayer;
public class MediaPlayerTest {
public static void main(String[] args) {
//加载java配置类获取Spring应用上下文
ApplicationContext ac = new AnnotationConfigApplicationContext(MediePlayerConfig.class);
//获取播放器
MediaPlayer player= ac.getBean(MediaPlayer.class);
//播放
player.play();
}
}
我们在获取播放器bean的时候,其实获取到的就是MediePlayerConfig类中cdplayer()返回的对象CDPlayer,在CDPlayer中我们依赖MusicSource,通过@Autowired注解,Spring自动为该bean注入了对MusicSource的依赖,所以在测试代码中我们只是获取了MediaPlayer对象的实例player,至于player有哪些依赖,我们都不知道,都是由Spring容器来给我注入,这里只关心播放器player,这就是Spring给我们带来的便捷,我们不需要用代码去管理对象的依赖关系,对象所有依赖的资源都有Spring容器来为我们注入。
随着技术的发展,有一天光驱也可以插入U盘播放MP3音乐了,这个时候我们来实现一个MP3的音乐资源
package com.seven.springTest.service.impl;
import com.seven.springTest.service.MusicSource;
public class MP3Source implements MusicSource {
private String title = "外婆";
private String artist = "周杰伦";
@Override
public void play() {
// TODO Auto-generated method stub
System.out.println("MP3 Playing " + title + " by " + artist);
}
}
在第一部分自动装配中,如果Spring发现了多个bean满足依赖关系,Spring就无法选择了,那么如果我们定义了MP3Source的实现,现在会不会也出现这样的情况呢?通过运行程序,我们发现没有产生任何影响,CDPlayer bean被注入的MusicSource依赖还是CDSource。这是因为我们在MediePlayerConfig中通过cdsource()告知了Spring产生bean的实现逻辑,那我们来修改下cdsource()
@Bean //该方法返回的MusicSource对象需要注册为Spring应用上下文中的bean
public MusicSource cdsource(){
//返回MP3Source实例
return new MP3Source();
}
我们再运行下测试方法,发现输出内容变成了“MP3 Playing 外婆 by 周杰伦”,说明注入的依赖对象实现发生变化了,这是因为 cdsource()内实现的是返回MP3Source的实例。
同之前@Component一样,添加@Bean注解的方法返回的bean也会被默认分配一个ID,默认情况下和方法名相同,如cdsource()方法返回的bean的ID就为“cdsource”,我们也可以指定bean的ID,如下:
@Bean(name="myCdplayer") //该方法返回的MediaPlayer对象需要注册为Spring应用上下文中的bean
public MediaPlayer cdplayer(){
return new CDPlayer();
}
这样在获取bean的时候就可以通过ID来获取
public class MediaPlayerTest {
public static void main(String[] args) {
//加载java配置类获取Spring应用上下文
ApplicationContext ac = new AnnotationConfigApplicationContext(MediePlayerConfig.class);
//根据ID获取bean
MediaPlayer player= (MediaPlayer) ac.getBean("myCdplayer");
//播放
player.play();
}
}
上面的案例中CDPlayer bean它依赖了MusicSource的依赖,我们在CDPlayer类中通过@Autowired声明了CDPlayer需要的依赖,这里还是一种通过注解隐式的配置,下面我们来通过java配置类来实现。
如果是显式的配置,由于MediePlayerConfig中配置的bean都是通过方法返回的,所以需要在返回对象bean的方法里注入依赖:
@Bean(name="myCdplayer") //该方法返回的MediaPlayer对象需要注册为Spring应用上下文中的bean
public MediaPlayer cdplayer(){
return new CDPlayer(cdsource()); //通过对象的构造函数注入依赖
}
或者
@Bean(name="myCdplayer") //该方法返回的MediaPlayer对象需要注册为Spring应用上下文中的bean
public MediaPlayer cdplayer(MusicSource musicSource){
return new CDPlayer(musicSource); //通过对象的构造函数注入依赖
}
通过上面2中方式配置,Spring都可以对CDPlayer中的MusicSource对象完成依赖注入,下面我们在定义一个bean配置
@Bean(name="myCdplayer") //该方法返回的MediaPlayer对象需要注册为Spring应用上下文中的bean
public MediaPlayer cdplayer(){
return new CDPlayer(cdsource()); //通过对象的构造函数注入依赖
}
@Bean(name="otherCdplayer") //定义另外一个bean对象,
public MediaPlayer othercdplayer(){
return new CDPlayer(cdsource());
}
MediaPlayer接口增加一个获取播放资源的方法
package com.seven.springTest.service;
public interface MediaPlayer {
/**
* 获取播放器加载的资源
* @return MusicSource
*/
MusicSource getResource();
/**
* 播放
*/
void play();
}
解下列,我们修改下Test代码
package com.seven.springTest.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.seven.springTest.Configuration.MediePlayerConfig;
import com.seven.springTest.Configuration.HelloWorldConfig;
import com.seven.springTest.service.MediaPlayer;
public class MediaPlayerTest {
public static void main(String[] args) {
// 加载java配置类获取Spring应用上下文
ApplicationContext ac = new AnnotationConfigApplicationContext(MediePlayerConfig.class);
// 获取播放器
MediaPlayer player = (MediaPlayer) ac.getBean("myCdplayer");
MediaPlayer otherplayer = (MediaPlayer) ac.getBean("otherCdplayer");
if (player.getResource().equals(otherplayer.getResource())) {
System.out.println("true");
}
// 播放
//player.play();
}
}
运行后,我们发现输出“true”,这说明的什么情况呢,我们在cdplayer()和othercdplayer()方法中在调用CDPlayer(cdsource())构造时,通过cdsource()获取的音乐资源对象是相同的,在默认情况下,Spring中的bean都是单例的,Spring会拦截对cdsource()的调用,并确保返回的是Spring创建的bean,也就是Spring本身在第一次调用cdsource()所创建的bean。
三、通过XML来装配bean
Spring学习系列(三) 通过Java代码装配Bean的更多相关文章
- Spring 之通过 Java 代码装配 bean
[关于IoC的几点认识] 1.面向接口编程 --> 每层只向上层提供接口 2.inversion of control (IoC) -->参考百度百科 3.DI是IoC的一种实现方式 [ ...
- Spring装配之——JAVA代码装配Bean
首先创建几个普通的JAVA对象,用于测试JAVA代码装配bean的功能. package soundsystemJava; //作为接口 定义了CD播放器对一盘CD所能进行的操作 public int ...
- .net reactor 学习系列(三)---.net reactor代码自动操作相关保护功能
原文:.net reactor 学习系列(三)---.net reactor代码自动操作相关保护功能 接上篇,上篇已经学习了界面的各种功能以及各种配置,这篇准备学习下代码控制许可证. ...
- 第2章—装配Bean—通过java代码装配bean
通过java代码装配bean 在进行显式装配的时候,有两种选型方案:java和XML配置,这里先介绍java的配置方式. 2.3.1创建配置类 先复习下上一章的配置内容: @Configurati ...
- 通过Java代码装配Bean
上面梳理了通过注解来隐式的完成了组件的扫描和自动装配,下面来学习下如何通过显式的配置的装配bean 二.通过Java类装配bean 在前面定义了HelloWorldConfig类,并使用@Compon ...
- Spring实战——通过Java代码装配bean
上篇说的是无需半行xml配置完成bean的自动化注入.这篇仍然不要任何xml配置,通过Java代码也能达到同样的效果. 这么说,是要把上篇的料拿出来再煮一遍? 当然不是,上篇我们几乎都在用注解的方式如 ...
- Spring装配Bean之Java代码装配bean
尽管通过组件扫描和自动装配实现Spring的自动化配置很方便也推荐,但是有时候自动配置的方式实现不了,就需要明确显示的配置Spring.比如说,想要将第三方库中的组件装配到自己的应用中,这样的情况下, ...
- Spring 通过Java代码装配bean
1. 背景 书接上文Spring自动化装配bean 尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化扫描配置是更为推荐的方式,但在有些情况下自动化扫描的方案行不通,如想要将第三方库中的组 ...
- Sping实战之通过JAVA代码装配Bean
尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化配置是更为推荐的方式,但有时候自动化配置的方案行不通,因此需要明确配置Spring.比如说,你想要将第三方库中的组件装配到你的应用中,在这 ...
随机推荐
- 简单的JavaScript互斥锁
去年有几个项目需要使用JavaScript互斥锁,所以写了几个类似的,这是其中一个: //Published by Indream Luo //Contact: indreamluo@qq.com / ...
- C语言 · 动态数组的使用
从键盘读入n个整数,使用动态数组存储所读入的整数,并计算它们的和与平均值分别输出.要求尽可能使用函数实现程序代码.平均值为小数的只保留其整数部分. 样例输入: 5 3 4 0 0 2样例输出:9 1样 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-13 在基类中应用条件 问题 你想从一个已存在的模型中的实体派生一个新的实体, ...
- WPF入门教程系列十九——ListView示例(一)
经过前面的学习,今天我做一个比较综合的WPF程序示例,主要包括以下功能: 1) 查询功能.从数据库(本地数据库(local)/Test中的S_City表中读取城市信息数据,然后展示到WPF的Windo ...
- Eclipse迁移到Android studio步骤如下:
一.从Eclipse中导出:1.将你的ADT插件版本升级到22.0以上.2.在Eclipse中,选择File-->Export.3.在弹出的导出窗口中,打开Android的文件夹,选择“Gene ...
- Bootstrap Metronic 学习记录(二)菜单栏
1.简介 1) .环境配置 2) .提取页面 2).动态生成菜单(无限级别树) 2.系统环境配置 项目需要程序数据支撑,这里选择MVC5.0+EF6.0[SQLSERVER](不对MVC架构和SQ ...
- 【开源】OSharp框架解说系列(3):扩展方法
OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...
- JavaScript阻塞剖析与改善
一.阻塞特性 <高性能JavaScript>一书中,关于第一章“Loading and Execution”,提到了无阻塞加载JavaScript技术,目的是为了提高页面呈现速度. 说到无 ...
- Android随笔之——跨进程通信(一) Activity篇
在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...
- IDDD 实现领域驱动设计-SOA、REST 和六边形架构
上一篇:<IDDD 实现领域驱动设计-架构之经典分层> 阅读目录: SOA-面向服务架构 REST 与 RESTful 资源(Resources) 状态(State) 六边形架构 DDD ...