Spring实战(第四版)IoC之Bean的装配

1 篇文章 0 订阅

我对IoC(控制反转)/DI(依赖注入)的理解:

       原来我们写java代码时,在A类中调用B类,则直接在A类中new一个B类对象即可调用B中的方法。这在平时的课程作业里显得非常合理而且通俗易懂,但是,接触了一个java项目之后才发现,尽管是一个小型的java项目,其中的类也是非常多的,算上javabean、工具类等少说也有十几个类。若要仍然使用new方法在一个类中调用另一个类,那类的关系将会错综复杂并且要一个一个地打开java文件才能理得清。若有一个容器盛放好了所有的类对象,并且帮我们理清了他们的关系就太好了,这个容器就是Spring的应用上下文或Bean工厂。另一方面,根据面向对象原则,一个类只需要做好自己的职责工作就够了,要使用别人的职责时,也只管把别人喊过来调用即可,不应该承担生产别人的功能。在学习spring之前,我们使用工厂模式,把生产这一功能交给工厂类来做,这样做可以使调用者类只管知道怎么生产工厂即可,但是我们还想让调用者什么都不用生产,有一样东西帮调用者生产好放在那里,调用者只管拿来用即可。这就是Spring的IoC原理,Spring容器将调用者需要的所有类对象生产好放在容器里面,并且将这些对象之间的依赖关系注入到这些对象中,调用者要某个对象只要从容器中拿就行了,不用创建对象,也不用管对象是否依赖其他对象。

        太口语化了,因为我也是初学者。。。

下面来介绍Spring是如何装配Bean的。

首先创建一下本文需要模拟的项目场景

这是一个CD磁带接口,模拟所有的CD:

package soundsystem;
//CD接口
public interface CompactDisc {
	void play();
}

Spring有三种装配Bean的方式:

一、隐式的bean发现机制和自动装配

    自动化装配Bean也分两种角度:组件扫描和自动装配,组件扫描是扫描项目中有哪些需要创建Bean的类,自动装配是自动根据扫描结果将依赖关系装配到spring容器中。

    1)组件扫描

步骤:

①创建可被发现的Bean(创建一个具体的CD光盘)

调用者需要使用哪些类对象,就让那个对象注入到spring容器中被调用者使用。

具体方法:在类签名前面添加@Component注解

package soundsystem;

import org.springframework.stereotype.Component;

//@Component注解,为了告诉Spring为该类创建Bean
//括号中内容为该Bean设置id,若无后面的括号参数,则spring默认为该Bean配置的id就为类名首字母小写
@Component("sgtPeppers")
public class SgtPeppers implements CompactDisc{

	private String title="Sgt.Pepper's Lonely Hearts Club Band";
	private String artist="The Beatles";
	@Override
	public void play() {
		System.out.println("Playing "+title+" by "+artist);
	}
}

可以使用Java依赖注入规范中的@Named注解来代替@Component


②组件扫描在默认情况下是不启用的,因此我们要让Spring容器的组件扫描启动起来(生产那个CD光盘)

第一种方式是通过java配置

package soundsystem;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//告诉spring这个java文件是配置文件
@Configuration
//@ComponentScan告诉Spring该配置文件使用的是组件扫描
//括号中参数为组件扫描需要扫描的基础包包名
@ComponentScan("soundsystem")
public class CDPlayerConfig {
}

为了清晰表明你想扫描的是基础包,可用以下参数

@ComponentScan(basePackages="soundsystem")

若想扫描多个基础包,可用数组表示

@ComponentScan(basePackages={"......","......"})

如果注解后面没有括号表明具体的基础包,则spring扫描当前配置文件所在的包及其子包

上面的方法的参数都是用String类型的值表示,这种类型编译时不会检查字符串是否正确,是类型不安全的,因此spring提供以下方法扫描基础包:指定包中所含的类或接口

@ComponentScan(basePackages={CDPlayer.class,DVDPlayer.class})

第二种方式是通过XML配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:Context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">
	//报错了,不知为何
	<context:component-scan base-package="soundsystem"/>
</beans>

③编写测试程序查看SgtPepper对象是否创建成功(光盘是否生产成功)

package soundsystem;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//测试开始时自动创建Spring应用上下文
@RunWith(SpringJUnit4ClassRunner.class)
//告诉Spring配置文件的位置,这里使用了javaconfig的配置文件
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest {
	//自动装配
	@Autowired
	private CompactDisc cd;
	@Test
	public void cdShouldNotBeNull(){
		System.out.println(cd==null?"Null":"notNull");
	}
}
输出:
五月 10, 2018 8:26:56 下午 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners
信息: Could not instantiate TestExecutionListener class [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their dependencies) available.
五月 10, 2018 8:26:57 下午 org.springframework.context.support.GenericApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.GenericApplicationContext@3c5a99da: startup date [Thu May 10 20:26:57 CST 2018]; root of context hierarchy
notNull
五月 10, 2018 8:26:58 下午 org.springframework.context.support.GenericApplicationContext doClose
信息: Closing org.springframework.context.support.GenericApplicationContext@3c5a99da: startup date [Thu May 10 20:26:57 CST 2018]; root of context hierarchy

说明创建Bean成功


下面是播放器接口,模拟所有的播放器

package soundsystem;

public interface MediaPlayer {
	void play();
}

2)自动装配

创建CD播放器类,该类也是要在spring中创建Bean实例的,并且CD播放器需要一张CD光盘才能正常播放,将之前在spring中创建好的CD光盘自动注入到这个CD播放器中

在构造方法上自动依赖注入

package soundsystem;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CDPlayer implements MediaPlayer{

	private CompactDisc cd;
	
	//自动依赖注入,可用于构造方法、setter方法和其他任意方法上
	@Autowired
	public CDPlayer(CompactDisc cd){
		this.cd=cd;
	}
	
	public void play() {
		cd.play();	
	}	
}

如果没有spring中没有满足这个依赖关系的Bean(CompactDisc)存在,则在创建应用上下文时会抛出异常,为避免异常,可设置如下:

@Autowired(required=false) 此时,若无匹配的Bean存在,这个CDPlayer Bean就会处于未装配状态,若代码中不进行null检查,可能造成空指针异常

如果有多个Bean都满足匹配,也会抛出异常

可用@Inject代替@Autowired

二、java中显式配置

三、XML中显式配置


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值