在Spring中的bean都是单例的
在XML中进行显式配置,在Java中进行显式配置:声明bean或者自动扫描,隐式的bean发现和自动化装配
CompactDisc.java
package soundSystem;
public interface compactDisc{
void display();
}
SgtPeppers.java
package soundsystem;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
//@Component("sgtPEeppers")//为bean命名
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
private List<String> tracks;
public SgtPeppers(String title, String artist){
this.title = title;
this.artist = artist;
}
public SgtPeppers(String title, String artist, List<String> tracks){
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
public void setTitle(String title){
this.title = title;
}
public void setArtist(String artist) {
this.artist = artist;
}
public void setTracks(List<String> tracks) {
this.tracks = tracks;
}
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
MediaPlayer.java
package soundsystem;
public interface MediaPlayer {
void play();
}
CDPlayer.java
package soundsystem;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
// 在XML中,可单独使用构造器注入构造bean
public CDPlayer(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
//在XML中,若存在现实构造函数,不可单独使用属性注入构造bean,必须构造器注入+属性注入
public void setCompactDisc(CompactDisc compactDisc){
this.compactDisc = compactDisc;
}
public void play() {
compactDisc.play();
}
}
CDPlayerConfig.java
package soundSystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
@Configuration //可不加(不知道为什么可不加)
@ComponentScan //在XML中配置得到相同的效果
@ComponentScan(value = "soundsystem",
excludeFilters = {
@Filter(type = FilterType.ANNOTATION, value = {Controller.class}),
@Filter(type = FilterType.ANNOTATION, value = {Component.class})
},
includeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = {Controller.class},
@Filter(type = FilterType.CUSTOM, classes = {CustomTypeFilter.class})
},
useDefaultFilters = false)
@ComponentScans(value =
{@ComponentScan(value = "soundsystem"),
@ComponentScan(value = "soundsystem")})
public class CDPlayerConfig{
@Bean //在不做自动扫描componentScan时,声明bean
public CompactDisc compactDisc() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
SoundSystemConfig.java
package soundsystem;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
@Configuration
//导入多个多种方式配置
@Import(CDPlayerConfig.class)
@ImportResource("classpath:appliction.xml")
public class SoundSystemConfig {
}
CustomTypeFilter.java
package soundsystem;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
public class CustomTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前扫描到的类的注解元数据
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前扫描到的类的元数据
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前扫描到的类的资源信息
Resource resource = metadataReader.getResource();
if (classMetadata.getClassName().contains("Co")) {
return true;
}
return false;
}
}
CDPlayerTest.java
package soundsystem;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/applicationContext.xml"})
//@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
// @Rule
// public final StandardOutputStreamLog log = new StandardOutputStreamLog();
@Autowired //各类方法的参数变量
private CompactDisc cd;
@Test
public void cdShouldNotBeNull() {
assertNotNull(cd);
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
System.out.println("beanName: " + beanName);
}
// assertEquals(
// "Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles\n",
// log.getLog());
}
}
applicationContext.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" />
<!--构造器注入 value-->
<bean id="compactDisc1" class="soundsystem.SgtPeppers">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<!--设置List-->
<!--<constructor-arg><null/></constructor-arg>-->
<constructor-arg>
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<!--...other tracks omitted for brevity-->
</list>
</constructor-arg>
<!--<constructor-arg>-->
<!--<set>-->
<!--<value>Sgt. Pepper's Lonely Hearts Club Band</value>-->
<!--<value>With a Little Help from My Friends</value>-->
<!--<!–...other tracks omitted for brevity–>-->
<!--</set>-->
<!--</constructor-arg>-->
</bean>
<!--构造器注入 ref-->
<bean id="cdPlayer1" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc1" />
</bean>
<bean id="cdPlayer2" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc1" />
<!--属性注入-->
<property name="compactDisc" ref="compactDisc1" />
</bean>
<bean id="compactDisc2" class="soundsystem.SgtPeppers">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<!--设置List-->
<!--<constructor-arg><null/></constructor-arg>-->
<!--<constructor-arg>-->
<!--<list>-->
<!--<value>Sgt. Pepper's Lonely Hearts Club Band</value>-->
<!--<value>With a Little Help from My Friends</value>-->
<!--<!–...other tracks omitted for brevity–>-->
<!--</list>-->
<!--</constructor-arg>-->
<!--<constructor-arg>-->
<!--<set>-->
<!--<value>Sgt. Pepper's Lonely Hearts Club Band</value>-->
<!--<value>With a Little Help from My Friends</value>-->
<!--<!–...other tracks omitted for brevity–>-->
<!--</set>-->
<!--</constructor-arg>-->
<!--属性注入-->
<property name="title" value=""/>
<property name="artist" value=""/>
<property name="tracks">
<list>
<value>Sgt. Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<!--...other tracks omitted for brevity-->
</list>
</property>
</bean>
</beans>
import-config.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">
<bean class="soundsystem.CDPlayerConfig" />
<import resource="applicationContext.xml" />
</beans>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sound-system</groupId>
<artifactId>sound-system</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
</project>
同一个bean适应不同的环境(开发、测试、生产)
多种方式设置哪个profile处于激活状态,通过spring.profiles.active和spring.profiles.default设置
- 作为DispatcherServlet的初始化参数
- 作为web应用的上下文参数
- 作为JNDI条目
- 作为环境变量
- 作为JVM的系统属性
- 在集成测试类上,使用@ActiveProfiles注释设置
Java Config配置
package com.myapp;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jndi.JndiObjectFactoryBean;
@Configuration
public class DataSourceConfig {
@Bean(destroyMethod = "shutdown")
@Profile("dev")
public DataSource embeddedDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
@Bean
@Profile("prod")
public DataSource jndiDataSource() {
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
}
}
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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans profile="dev">
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:schema.sql" />
<jdbc:script location="classpath:test-data.sql" />
</jdbc:embedded-database>
</beans>
<beans profile="prod">
<jee:jndi-lookup id="dataSource"
lazy-init="true"
jndi-name="jdbc/myDatabase"
resource-ref="true"
proxy-interface="javax.sql.DataSource" />
</beans>
</beans>
schema.sql
create table Things (
id identity,
name varchar(100)
);
test-data.sql
insert into Things (name) values ('A')
条件化装配bean
MagicBean.java
package com.habuma.restfun;
public class MagicBean {
}
MagicExistsCondition.java
package com.habuma.restfun;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MagicExistsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("magic");
}
}
MagicConfig.java
package com.habuma.restfun;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MagicConfig {
@Bean
@Conditional(MagicExistsCondition.class)
public MagicBean magicBean() {
return new MagicBean();
}
}
MagicExistsTest.java
package com.habuma.restfun;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=MagicConfig.class)
public class MagicExistsTest {
@Autowired
private ApplicationContext context;
/*
* This test will fail until you set a "magic" property.
* You can set this property as an environment variable, a JVM system property, by adding a @BeforeClass
* method and calling System.setProperty() or one of several other options.
*/
@Test
public void shouldNotBeNull() {
assertTrue(context.containsBean("magicBean"));
}
}
处理自动装配bean的歧义
标识bean为首选-@Primary
@Component
@Primary
public class IceCream implements Dessert{...}
@Bean
@Primary
public Dessert iceCream(){
return new IceCream();
}
<bean id="iceCream" class="com.desserteater.IceCream" primary="true">
装配bean的限定符-@Qualifier
//在bean生成时限制bean id
@Component
@Qualifier("cold")
public class IceCream implements Dessert{...}
@Bean
@Qualifier("cold")
public Dessert iceCream(){
return new IceCream();
}
//在注入bean时限定注入的bean id
@Autowired
@Qualifier("cold")
public void setDesert(Dessert dessert){
this.dessert = dessert;
}
自定义注解解决-Java不允许在同一个条目上重复出现相同类型的多个注解
//自定义注解
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold{}
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Creamy{}
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Fruity{}
//生成bean时用多个注解做限定,会有相同的注解
@Component
@Cold
@Creamy
public class IceCream implements Dessert{...}
@Component
@Cold
@Fruity
public class Popsicle implements Dessert{...}
//注入bean时用多个注解做限定
@Autowired
@Cold
@Creamy
public void setDessert(Dessert dessert){
this.dessert = dessert;
}
bean的作用域-基于作用域创建bean
单例(Singleton)(默认)-整个应用只有一个
原型(Prototype)-每次注入或者通过spring上下文获取的时候会创建新的
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//@Scope("prototype")
public class Notepad{...}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//@Scope("prototype")
public Notepad notepad(){
return new Notepad();
}
<bean id="notepad" class="com.myapp.Notepad" scope="prototype">
会话(Session)-web应用每个会话一个bean
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public ShoppingCart cart(){...}
<bean id="card" class="com.myapp.ShoppingCart" scope="session">
<aop:scope-proxy proxy-target-class="false" />
</bean>
//是一个单例,加载的时候要创建,但是shoppingCart还未创建,且在以后创建时会存在多个,所以proxyMode设置作为代理,在实际会话中注入真正的shoppingCart
@Component
public class StoreService{
@Autowired
public void setShoppingCart(ShoppingCard shoppingCart){
this.shoppingCart = shoppingCart;
}
}
请求(Request)-web应用每个请求一个bean
运行时属性值的注入
BlankDisc.java
package com.soundsystem;
public class BlankDisc {
private final String title;
private final String artist;
public BlankDisc(String title, String artist) {
this.title = title;
this.artist = artist;
}
public String getTitle() {
return title;
}
public String getArtist() {
return artist;
}
}
EnvironmentConfig.java
package com.soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
@Configuration
@PropertySource("classpath:/com/soundsystem/app.properties")
public class EnvironmentConfig {
@Autowired
Environment env;
@Bean
public BlankDisc blankDisc() {
return new BlankDisc(
env.getProperty("disc.title"),
env.getProperty("disc.artist"));
}
}
EnvironmentConfigWithDefaults.java
package com.soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
public class EnvironmentConfigWithDefaults {
@Autowired
Environment env;
@Bean
public BlankDisc blankDisc() {
return new BlankDisc(
env.getProperty("disc.title", "Rattle and Hum"),
env.getProperty("disc.artist", "U2"));
}
}
EnvironmentConfigWithRequiredProperties.java
package com.soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
public class EnvironmentConfigWithRequiredProperties {
@Autowired
Environment env;
@Bean
public BlankDisc blankDisc() {
return new BlankDisc(
env.getRequiredProperty("disc.title"),
env.getRequiredProperty("disc.artist"));
}
}
app.properties
disc.title=Sgt. Peppers Lonely Hearts Club Band
disc.artist=The Beatles
placeholder-config.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:c="http://www.springframework.org/schema/c"
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-4.0.xsd">
<context:property-placeholder location="classpath:/com/soundsystem/app.properties" />
<bean class="com.soundsystem.BlankDisc">
<constructor-arg value="${disc.title}" />
<constructor-arg value="${disc.artist}" />
</bean>
</beans>
EnvironmentInjectionTest.java
package com.soundsystem;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class EnvironmentInjectionTest {
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=EnvironmentConfig.class)
public static class InjectFromProperties {
@Autowired
private BlankDisc blankDisc;
@Test
public void assertBlankDiscProperties() {
Assert.assertEquals("The Beatles", blankDisc.getArtist());
Assert.assertEquals("Sgt. Peppers Lonely Hearts Club Band", blankDisc.getTitle());
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=EnvironmentConfigWithDefaults.class)
public static class InjectFromPropertiesWithDefaultValues {
@Autowired
private BlankDisc blankDisc;
@Test
public void assertBlankDiscProperties() {
Assert.assertEquals("U2", blankDisc.getArtist());
Assert.assertEquals("Rattle and Hum", blankDisc.getTitle());
}
}
public static class InjectFromPropertiesWithRequiredProperties {
@Test(expected=BeanCreationException.class)
public void assertBlankDiscProperties() {
new AnnotationConfigApplicationContext(EnvironmentConfigWithRequiredProperties.class);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/soundsystem/placeholder-config.xml")
public static class InjectFromProperties_XMLConfig {
@Autowired
private BlankDisc blankDisc;
@Test
public void assertBlankDiscProperties() {
Assert.assertEquals("The Beatles", blankDisc.getArtist());
Assert.assertEquals("Sgt. Peppers Lonely Hearts Club Band", blankDisc.getTitle());
}
}
}
Spring表达式语言-SpEL
未研究待续。。。