Spring的自动化装配
作者:互联网
在Spring中,对象无需自己查找和创建与其所关联的其他对象。相反,容易负责把需要相互协作的对象引用赋予各个对象。例如,一个订单管理的组件需要信用卡认证组件,但它不需要自己创建信用卡认证组件。订单管理组件只需要表明自己两手空空,容器就会主动赋予它一个信用卡认证组件。创建应用对象之间协作关系的行为通常称为装配,这也是依赖注入(DI)的本质。
Spring容器负责创建应用程序的bean并通过DI来协调这些对象之间的关系。但是,作为开发人员,你需要告诉Spring要创建那些bean并且如何将其装配在一起。当描述bean如何进行装配时,Spring具有非常大的灵活性,它提供了三种主要的装配机制:
- 在XML中进行显式配置;
- 在Java中进行显式配置;
- 隐式的bean发现机制和自动装配;
1.自动化装配
Spring 从两个角度来实现自动化装配:
组件扫描(component scanning):Spring 会自动发现应用上下文中所创建的 bean。
自动装配(autowiring):Spring 自动满足 bean 之间的依赖。
1.1 创建可被发现的 bean
目录结构
CD 为我们阐述 DI 如何运行提供了一个很好的样例。如果你不将 CD 插入(注入)到 CD 播放器中,那么 CD 播放器其实是没有太大用处的。所以,可以这样说,CD 播放器依赖于 CD 才能完成它的使命。
为了在 Spring 中阐述这个例子,让我们首先在 Java 中建立 CD 的概念。以下展现了 CompactDisc,它是定义 CD 的一个接口:
package soundsystem;
/**
* @author 国洪志
* @description 光盘
* @since 2022-08-22 09:55
**/
public interface CompactDisc {
/**
* 演奏
*/
void play();
}
CompactDisc 的具体内容并不重要,重要的是你将其定义为一个接口。作为接口,它定义了 CD 播放器对一盘 CD 所能进行的操作。它将 CD 播放器的任意实现与 CD 本身的耦合降低到了最小的程度。
我们还需要一个 CompactDisc 的实现,实际上,我们可以有 CompactDisc 接口的多个实现。在本例中,我们首先会创建其中的一个实现,带有 @Component 注解的 CompactDisc 实现类 SgtPeppers:
package soundsystem;
import org.springframework.stereotype.Component;
/**
* @author 国洪志
* @description
* @since 2022-08-22 09:58
**/
@Component
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);
}
}
你需要注意的就是 SgtPeppers 类上使用了 @Component 注解。这个简单的注解表明该类会作为组件类,并告知 Spring 要为这个类创建 bean。没有必要显式配置 SgtPeppersbean,因为这个类使用了 @Component 注解,所以 Spring 会为你把事情处理妥当。
不过,组件扫描默认是不启用的。我们还需要显式配置一下 Spring, 从而命令它去寻找带有 @Component 注解的类,并为其创建 bean。以下的配置类展现了完成这项任务的最简洁配置,@ComponentScan 注解启用了组件扫描:
package soundsystem;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
/**
* @author 国洪志
* @description
* @since 2022-08-22 10:49
**/
@Configurable
@ComponentScan
public class CdPlayerConfig {
}
如果你更倾向于使用 XML 来启用组件扫描的话,那么可以使用 Spring context 命名空间的元素。以下展示了启用组件扫描的最简洁 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"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
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>
为了测试组件扫描的功能,我们创建一个简单的 JUnit 测试,它会创建 Spring 上下文,并判断 CompactDisc 是不是真的创建出来 了。CDPlayerTest 就是用来完成这项任务的,测试组件扫描能够发现 CompactDisc:
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;
import static org.junit.Assert.assertNotNull;
/**
* @author 国洪志
* @description
* @since 2022-08-22 10:51
**/
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(classes = CdPlayerConfig.class) JavaConfig使用这个
@ContextConfiguration(value = "/soundsystem.xml") // xml文件使用这个
public class CdPlayerTest {
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotBeNull(){
assertNotNull(cd);
}
}
1.2 为组件扫描的 bean 命名
Spring应用上下文中所有的bean都会给定一个ID.在前面的例子中,尽管我们没有明确地为
SgtPeppersbean设置ID,但是Spring会根据类名为其指定一个ID。具体来讲,这个bean所给定的ID为sgtPeppers,也就是将类名的第一个字母变为小写。
如果想为这个beans设置不同的ID,你所要做的就是将期望的ID作为值传递给@Component注解。比如说,如果想将这个bean标识为lonelyHeartsClub,那么你需要将 SgtPeppers 类的 @Component 注解配置为如下所示:
package soundsystem;
import org.springframework.stereotype.Component;
import javax.inject.Named;
/**
* @author 国洪志
* @description
* @since 2022-08-22 09:58
**/
@Component(value = "lonelyHeartsClub")
//@Named(value = "lonelyHeartsClub")//另一种命名方式:Java 依赖注入规范(Java Dependency Injection)中所提供的 @Named 注解来为 bean 设置 ID:
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);
}
}
1.3 设置组件扫描的基础包
到现在为止,我们没有为 @ComponentScan 设置任何属性。这意味着,按照默认规则,它会以配置类所在的包作为基础包(base package)来扫描组件。但是,如果你想扫描不同的包,那该怎么办呢?或者,如果你想扫描多个基础包,那又该怎么办呢?
有一个原因会促使我们明确地设置基础包,那就是我们想要将配置类 放在单独的包中,使其与其他的应用代码区分开来。如果是这样的话,那默认的基础包就不能满足要求了。
要满足这样的需求其实也完全没有问题!为了指定不同的基础包,你所需要做的就是在 @ComponentScan 的 value 属性中指明包的名称:
package soundsystem;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
/**
* @author 国洪志
* @description
* @since 2022-08-22 10:49
**/
@Configurable
@ComponentScan("soundsystem") //value属性指定包名
//@ComponentScan(basePackages = "soundsystem") // 根据basePackages指定包名
//@ComponentScan(basePackages = {"soundsystem", "video"})// 根据basePackages指定多个包名
public class CdPlayerConfig {
}
标签:装配,Spring,org,CD,bean,自动化,组件,import 来源: https://www.cnblogs.com/guohongzhi/p/16610970.html