Spring 配置的可选方案
- 在 XML 中进行显示配置;
- 在 Java 中进行显示配置;
- 隐匿的 bean 发现机制和自动装配;
尽可能地使用自动装配机制,当必须要显示配置 bean 的时候(比如,有些源码不是由你来维护的,而当你需要为这些代码配置 bean 的时候),推荐使用类型安全并且比 XML 更加强大的 JavaConfig。
自动化装配 bean
Spring 从两个角度来实现自动化装配:
- 组件扫描(component scanning):Spring 会自动发现应用上下文中所创建的 bean;
- 自动装配(autowiring):Spring 自动满足 bean 之间的依赖;
组件扫描和自动装配组合在一起就能发挥出强大的威力,它们能够将代码的显式配置降低到最少。
创建可被发现的 bean
package com.y.gui.spring.soundsystem;
public interface CompactDisc {
void play();
}
package com.y.gui.spring.soundsystem.impl;
import com.y.gui.spring.soundsystem.CompactDisc;
import org.springframework.stereotype.Component;
@Component
public class SgtPeppers implements CompactDisc {
@Override
public void play() {
System.out.println("SgtPeppers.play");
}
}
为组件扫描的 bean 命名
@Component
import org.springframework.stereotype.Component;
@Component 注解的类表明该类会被做为组件类,但组件扫描默认是关闭的。
bean 的默认 ID 为 sgtPeppers,即类名第一个字母变为小写。
为 bean 指定 ID:@Component("sgtABC")
@Named
import javax.inject.Named;
@Named 属于Java依赖注入规范(Java Dependency Injection)。
Spring 支持将 @Named 作为 @Component 注解的替代方案。
所以为 bean 命名的另一种方式为
@Named("sgtABC")
设置扫描组件的基础包
@ComponentScan
import org.springframework.context.annotation.ComponentScan;
@ComponentScan 启动 Spring 的组件扫描功能
Spring 默认扫描 @ComponentScan 配置类相同的包及子包,查找带有 @Component 注解的类并为其创建 bean。
指明扫描的基础包
@ComponentScan(“com.y.gui.spring.soundsystem”)
@ComponentScan(basePackages
=“com.y.gui.spring.soundsystem”)
指明多个扫描的基础包
@ComponentScan(
basePackages
={“com.a”, “com.b”})
通过类或接口指明扫描基础包
可以考虑在包中创建一个用来进行扫描的空标记接口,更安全
@ComponentScan(
basePackageClasses
={A.class, B.class})
通过Java配置启动组件扫描
package com.y.gui.spring.soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@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"
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="com.y.gui.spring.soundsystem" />
</beans>
测试
SpringJUnit4ClassRunner
自动创建 Spring 应用上下文
@ContextConfiguration
表明要在 CDPlayerConfig 中加载配置
package com.y.gui.soundsystem;
import com.y.gui.spring.soundsystem.CDPlayerConfig;
import com.y.gui.spring.soundsystem.CompactDisc;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
private CompactDisc compactDisc;
@Test
public void play() {
compactDisc.play();
}
}
运行结果
15:41:25.119 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@22e357dc size = 1, maxSize = 32, parentContextCount = 0, hitCount = 2, missCount = 1]
15:41:25.119 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Retrieved ApplicationContext [928466577] from cache with key [[MergedContextConfiguration@6366ebe0 testClass = CDPlayerTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@30a3107a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@52feb982, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@25af5db5], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
15:41:25.119 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@22e357dc size = 1, maxSize = 32, parentContextCount = 0, hitCount = 3, missCount = 1]
15:41:25.576 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Retrieved ApplicationContext [928466577] from cache with key [[MergedContextConfiguration@6366ebe0 testClass = CDPlayerTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@30a3107a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@52feb982, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@25af5db5], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
15:41:25.576 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@22e357dc size = 1, maxSize = 32, parentContextCount = 0, hitCount = 4, missCount = 1]
SgtPeppers.play
基于XML的运行测试
package com.y.gui.spring.soundsystem;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class XmlMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("static/spring-context.xml");
CompactDisc cd = context.getBean(CompactDisc.class);
cd.play();
context.close();
}
}
运行结果
15:43:55.415 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [C:\IdeaProjects\gui\target\classes\com\y\gui\spring\soundsystem\impl\SgtPeppers.class]
15:43:55.567 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
15:43:55.570 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
15:43:55.570 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
15:43:55.570 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
15:43:55.587 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'CDPlayerConfig'
15:43:55.596 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'sgtPeppers'
SgtPeppers.play
通过为 bean 添加注解实现自动装配
package com.y.gui.spring.soundsystem.cd;
public interface MediaPlayer {
void play();
}
package com.y.gui.spring.soundsystem.cd.impl;
import com.y.gui.spring.soundsystem.CompactDisc;
import com.y.gui.spring.soundsystem.cd.MediaPlayer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
@Override
public void play() {
this.cd.play();
}
}
@Autowired
import org.springframework.beans.factory.annotation.Autowired;
@Autowired 注解不仅能够用在构造器上,还能用在类的任何方法上以及属性本身上。如:
@Autowired
private CompactDisc cd;
@Autowired
public void abc(CompactDisc cd) {
this.cd = cd;
}
不论任何形式,Spring 都会尝试满足所声明的依赖。假如有且只有一个 bean 匹配依赖需求的话,那么这个 bean 将会被装配进来。如果没有匹配的 bean,那么在应用上下文创建的时候,Spring 会抛出一个异常。如果有多个bean都能满足依赖关系的话,Spring 也将会抛出一个异常,表明没有明确指定要选择哪个 bean 进行自动装配。
为了避免异常的出现,可以将 @Autowired 的 required 属性设置为 false :
@Autowired(required=false)
如果 required 属性设置为 false 的话,需要谨慎对待,建议代码中进行 null 检查防止出现 NullPointerException 异常。
@Inject
import javax.inject.Inject;
@Inject
注解来源于 Java 依赖注入规范,该规范同时还为我们定义了 @Named
注解。在自动装配中,Spring 同时支持 @Inject
和 @Autowired
。尽管 @Inject
和 @Autowired
之间有着一些细微的差别,但是在大多数场景下,它们都是可以互相替换的。
验证自动装配
package com.y.gui.soundsystem;
import com.y.gui.spring.soundsystem.CDPlayerConfig;
import com.y.gui.spring.soundsystem.cd.MediaPlayer;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
private MediaPlayer mp;
@Test
public void mpTest() {
mp.play();
}
}
运行结果
17:17:24.552 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test method: context [DefaultTestContext@6366ebe0 testClass = CDPlayerTest, testInstance = com.y.gui.soundsystem.CDPlayerTest@166fa74d, testMethod = mpTest@CDPlayerTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@44f75083 testClass = CDPlayerTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@33c7e1bb, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7a765367, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@12cdcf4], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]], attributes = map[[empty]]], class annotated with @DirtiesContext [false] with mode [null], method annotated with @DirtiesContext [false] with mode [null].
17:17:24.555 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Retrieved ApplicationContext [624271064] from cache with key [[MergedContextConfiguration@44f75083 testClass = CDPlayerTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@33c7e1bb, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7a765367, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@12cdcf4], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
17:17:24.555 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@10feca44 size = 1, maxSize = 32, parentContextCount = 0, hitCount = 2, missCount = 1]
17:17:24.556 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Retrieved ApplicationContext [624271064] from cache with key [[MergedContextConfiguration@44f75083 testClass = CDPlayerTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@33c7e1bb, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7a765367, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@12cdcf4], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
17:17:24.556 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@10feca44 size = 1, maxSize = 32, parentContextCount = 0, hitCount = 3, missCount = 1]
17:17:24.874 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Retrieved ApplicationContext [624271064] from cache with key [[MergedContextConfiguration@44f75083 testClass = CDPlayerTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@33c7e1bb, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7a765367, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@12cdcf4], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
17:17:24.874 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@10feca44 size = 1, maxSize = 32, parentContextCount = 0, hitCount = 4, missCount = 1]
SgtPeppers.play
通过 Java 代码装配 bean
在很多场景下通过组件扫描和自动装配实现 Spring 的自动化配置是更为推荐的方式,但有时候自动化配置的方案行不通,因此需要明确配置 Spring。比如说,想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加 @Component
和 @Autowired
注解的,因此就不能使用自动化装配的方案了。 在这种情况下,必须要采用显式装配的方式。
在进行显式配置的时候,有两种可选方案:Java
和XML
。
package com.y.gui.spring.soundsystem;
import com.y.gui.spring.soundsystem.cd.impl.CDPlayer;
import com.y.gui.spring.soundsystem.impl.HardDaysNight;
import com.y.gui.spring.soundsystem.impl.Revolver;
import com.y.gui.spring.soundsystem.impl.SgtPeppers;
import com.y.gui.spring.soundsystem.impl.WhiteAlbum;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDPlayerDisplayConfig {
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(randomCD());
}
/*@Bean
public CDPlayer cdPlayer(CompactDisc cd) {
return new CDPlayer(cd);
}*/
@Bean(name="beanRandomCD")
public CompactDisc randomCD() {
int choice = (int) Math.floor(Math.random() * 4);
if (choice == 0) {
return new SgtPeppers();
} else if (choice == 1) {
return new WhiteAlbum();
} else if (choice == 2) {
return new HardDaysNight();
} else {
return new Revolver();
}
}
}
测试
package com.y.gui.soundsystem;
import com.y.gui.spring.soundsystem.CDPlayerDisplayConfig;
import com.y.gui.spring.soundsystem.cd.MediaPlayer;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerDisplayConfig.class)
public class CDPlayerDisplayTest {
@Autowired
private MediaPlayer mp;
@Test
public void mpTest() {
mp.play();
}
}
运行结果
16:23:49.558 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Retrieved ApplicationContext [928466577] from cache with key [[MergedContextConfiguration@6366ebe0 testClass = CDPlayerDisplayTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerDisplayConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@30a3107a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@52feb982, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@25af5db5], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
16:23:49.558 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@223aa2f7 size = 1, maxSize = 32, parentContextCount = 0, hitCount = 3, missCount = 1]
16:23:49.827 [main] DEBUG org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate - Retrieved ApplicationContext [928466577] from cache with key [[MergedContextConfiguration@6366ebe0 testClass = CDPlayerDisplayTest, locations = '{}', classes = '{class com.y.gui.spring.soundsystem.CDPlayerDisplayConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@30a3107a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@52feb982, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@25af5db5], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
16:23:49.827 [main] DEBUG org.springframework.test.context.cache - Spring test ApplicationContext cache statistics: [DefaultContextCache@223aa2f7 size = 1, maxSize = 32, parentContextCount = 0, hitCount = 4, missCount = 1]
Revolver.play
CDPlayerDisplayConfig 配置类没有添加 @ComponentScan 注解,而是通过 @Bean 显示的装配 Bean。
@Bean
import org.springframework.context.annotation.Bean;
@Bean
注解会告诉 Spring 这个方法将会返回一个对象,该对象要注册为 Spring 应用上下文中的 bean。方法体中包含了最终产生 bean 实例的逻辑。
默认情况下,bean 的 ID 与带有 @Bean
注解的方法名是一样的。CDPlayer 的 bean 名称将为 cdPlayer。同时,也可以使用 @Bean
的 name 属性指定名称。
看起来 cdPlayer()
方法中是通过 randomCD()
方法来获取 CompactDisc
的,但实际并非如此。
因为 randomCD()
方法上添加了 @Bean
注解,Spring 将会拦截所有对它的调用,并确保直接返回该方法所创建的 bean,而不是每次都对其进行实际的调用。
其实,通过将 CompactDisc
作为方法参数由 Spring 传递进来的方式更为妥当 (如上注释的代码),这样 CompactDisc
就将不会被限制装配方式,比如可以通过其它配置类或 XML 或自动扫描装配。
通过 XML 装配 bean
在 Spring 刚刚出现的时候,XML 是描述配置的主要方式。在 Spring 的名义下,我们创建了无数行 XML 代码。在一定程度上,Spring 成为了 XML 配置的同义词。
Spring 现在有了强大的自动化配置和基于 Java 的配置,XML不应该再是第一选择了。
创建 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"
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">
<!-- configuration details to here -->
</beans>
借助 Spring Tool Suite 创建 XML 配置文件 创建和管理 Spring XML 配置文件的一种简便方式是使用 Spring Tool Suite(https://spring.io/tools/sts)。在 Spring Tool Suite 的菜单中,选择 File>New>Spring Bean Configuration File,能够创建 Spring XML 配置文件,并且可以选择可用的配置命名空间。
用来装配 bean 的最基本的 XML 元素包含在 spring-beans 模式之中,在上面这个 XML 文件中,它被定义为根命名空间。<beans> 是该模式中的一个元素,它是所有 Spring 配置文件的根元素。
在 XML中配置 Spring 时,还有一些其他的模式。
声明 bean
<bean id="sgtPeppers" class="com.y.gui.spring.soundsystem.impl.SgtPeppers"/>
如果没有明确给定 ID,那么这个 bean 将会根据 全限定类名 来进行命名。在本例中,bean 的 ID 将会是“ com.y.gui.spring.soundsystem.impl.SgtPeppers#0”。其中,“#0 ”是一个计数的形式,用来区分相同类型的其他 bean。
当 Spring 发现这个 <bean/> 元素时,它将会调用 SgtPeppers 的 默认构造器 来创建 bean。
借助构造器注入初始化 bean
在XML中声明DI时,会有多种可选的配置方案和风格。
具体到构造器注入,有两种基本的配置方案可供选择:
- <constructor-arg> 元素
- 使用Spring 3.0所引入的c-命名空间
两者的区别在很大程度就是是否冗长烦琐。可以看到,<constructor-arg> 元素比使用c-命名空间会更加冗长,从而导致XML更加难以读懂。
另外,有些事情 <constructor-arg> 可以做到,但是使用 c- 命名空间却无法实现。
要使用C-命名空间,必须要在XML的顶部声明其模式:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
...
</beans>
构造器注入 bean 引用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<bean id="sgtPeppers" class="com.y.gui.spring.soundsystem.impl.SgtPeppers"/>
<bean id="cdPlayer" class="com.y.gui.spring.soundsystem.cd.impl.CDPlayer">
<constructor-arg ref="sgtPeppers"/>
</bean>
</beans>
c- 命名空间构造器引用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<bean id="sgtPeppers" class="com.y.gui.spring.soundsystem.impl.SgtPeppers"/>
<bean id="cdPlayer" class="com.y.gui.spring.soundsystem.cd.impl.CDPlayer" c:cd-ref="sgtPeppers" />
</beans>
c
: C命名空间的前缀
cd
:构造器参数名
-ref
:注入 bean 引用
"sgtPeppers"
:要注入的 bean 的 ID
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="sgtPeppers" />
_0
:表示参数在整个参数中的位置信息
因为在XML中不允许数字作为属性的第一个字符,因此必须要添加一个下画线作为前缀。
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_-ref="sgtPeppers" />
_
:如果只有一个构造器参数,那也可以不用去标示参数名或位置
c- 命名空间装配字面量值
package com.y.gui.spring.soundsystem.impl;
import com.y.gui.spring.soundsystem.CompactDisc;
import java.util.List;
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
public void play() {
System.out.println("Playing " + title + " by " + artist);
for (String track : tracks) {
System.out.println("-Track: " + track);
}
}
}
<bean id="blankDisc" class="com.y.gui.spring.soundsystem.impl.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<constructor-arg>
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</list>
</constructor-arg>
</bean>
也可以使用<ref>元素替代<value>实现bean引用列表的装配,如:
public Discography(String artist, List<CompactDisc> cds) { ... }
<bean id="discography" class="com.y.gui.spring.soundsystem.impl.Discography">
<constructor-arg value="The Beatles" />
<constructor-arg>
<!-- 当参数是java.util.Set类型时,<list>标签可以替换为<set> -->
<list>
<ref bean="sgtPeppers" />
<ref bean="whiteAlbum" />
<ref bean="hardDaysNight" />
<ref bean="revolver" />
...
</list>
</constructor-arg>
</bean>
<constructor-arg> 比 c- 命名空间的属性更有优势
使用 c- 命名空间的属性无法实现装配集合的功能
设置属性
package com.y.gui.spring.soundsystem.cd.impl;
import com.y.gui.spring.soundsystem.CompactDisc;
import com.y.gui.spring.soundsystem.cd.MediaPlayer;
public class VideoPlayer implements MediaPlayer {
private CompactDisc compactDisc;
public void setCompactDisc(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
@Override
public void play() {
compactDisc.play();
}
}
<bean id="cdPlayer" class="com.y.gui.spring.soundsystem.cd.impl.VideoPlayer">
<property name="compactDisc" ref="compactDisc" />
</bean>
<property> 元素为属性的Setter方法所提供的功能与 <constructor-arg> 元素为构造器所提供的功能是一样的。
Spring提供了更加简洁的p-命名空间,作为 <property> 元素的替代方案。为了启用 p- 命名空间,必须要在XML文件中与其他的命名空间一起对其进行声明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
... ...
</bean>
使用 p- 命名空间为属性设值:
<bean id="cdPlayer" class="com.y.gui.spring.soundsystem.cd.impl.VideoPlayer" p:compactDisc-ref="compactDisc" />
p
: p命名空间的前缀
compactDisc
:属性名
-ref
:注入 bean 引用
"compactDisc"
:要注入的 bean 的 ID
<bean id="blankDisc" class="com.y.gui.spring.soundsystem.impl.BlankDisc">
<property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
<property name="artist" value="The Beatles" />
<property name="tracks">
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</list>
</property>
</bean>
使用 p- 命名空间的属性来完成该功能:
<bean id="blankDisc" class="com.y.gui.spring.soundsystem.impl.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles">
<property name="tracks">
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</list>
</property>
</bean>
p- 命名空间不能用来装配集合
我们可以使用 Spring util- 命名空间中的一些功能来简化装配,首先要在XML中声明 util- 命名空间及其模式:
<?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:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
... ...
</beans>
<util:list id="trackList">
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!-- ...other tracks omitted for brevity... -->
</util:list>
<bean id="blankDisc" class="com.y.gui.spring.soundsystem.impl.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles"
p:tracks-ref="trackList" />
Spring util- 命名空间中的元素
- 元素
- 描述
- <util:constant>
- 引用某个类型的 public static 域,并将其暴露为 bean
- util:list
- 创建一个 java.util.List 类型的 bean,其中包含值或引用
- util:map
- 创建一个 java.util.Map 类型的 bean,其中包含值或引用
- util:properties
- 创建一个 java.util.Properties 类型的 bean
- util:property-path
- 引用一个 bean 的属性(或内嵌属性),并将其暴露为 bean
- util:set
- 创建一个 java.util.Set 类型的 bean,其中包含值或引用
导入和混合配置
在JavaConfig中引用XML配置
@Import
可以将多个配置组合到一起
package com.y.gui.spring.soundsystem;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({CDPlayerConfig.class, CDPlayerDisplayConfig.class})
public class SystemConfig {
}
@ImportResource
在 Java 中加载 xml 配置
package com.y.gui.spring.soundsystem;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
@Configuration
@Import({CDPlayerConfig.class, CDPlayerDisplayConfig.class})
@ImportResource("classpath:static/spring-soundsystem.xml")
public class SystemConfig {
}
在XML配置中引用 JavaConfig
<import/> 元素
可以引入其它配置文件
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="cd-config.xml" />
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" />
</beans>
<bean/>元素
导入Java配置
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.y.gui.spring.soundsystem.CDPlayerConfig" />
<import resource="cdplayer-config.xml" />
</beans>