在线学习连接:spring in action 4
关键词解释
名词 | 解释 |
---|---|
EJB | Enterprise JavaBean,企业级JavaBean |
POJO | Plain Old Java Object,简单老式Java对象 |
J2EE | Java 2 Enterprise Edition,Java2企业版 |
DI | Dependency Injection,依赖注入,获取对象的过程被反转,获得依赖对象的过程由自身管理变成由IOC容器主动注入 |
IOC | Inversion of Control,控制反转,借助于“第三方” 实现具有依赖关系的对象间解耦 |
AOP | Aspect-Oriented Programming,面向切面编程 |
装配 | wiring 创建应用对象间协助关系的行为 |
JNDI | Java Naming and Directory Interface,Java 命名与目录接口, |
一、Spring的核心
核心特性:DI和AOP
1.1 简化Java开发
1.1.1 激发POJO的潜能
1.1.2 依赖注入
1.1.3 应用切面
1.1.4 使用模板代码
1.2 容纳你的Bean
两种容器:Bean工厂和应用上下文(ApplicationContext,基于BeanFactory构建)
1.2.1 使用应用上下文
- AnnotationConfigApplicationContext:从配置类中加载Spring应用上下文
- AnnotationConfigWebApplicationContext:从配置类中加载SpringWeb上下文
- ClassPathXmlApplicationContext:从类路径下的xml文件加载上下文
- FileSystemXmlApplicationContext:从文件系统下的xml文件加载
- XmlWebApplicationContext:从Web应用下的xml文件加载
// 文件系统
ApplicationContext context = new FileSystemXmlApplicationContext("c:/knight.xml");
// 类路径,包括jar中的xml
ApplicationContext context = new ClassPathXmlApplicationContext("knight.xml");
// 配置类
ApplicationContext context = new AnnotationConfigApplicationContext(com.springinaction.knights.config.KnightConfig.class);
1.2.2 Bean的生命周期
1.2.3 俯瞰Spring风景线
1.2.4 新特性
二、装配Bean
2.1 Spring配置的可选方案
- 组件扫描&自动装配,隐式配置
- Java配置类,显示配置
- XML配置文件,显示配置
2.2 自动化装配Bean
- 组件扫描
- 自动装配
2.2.1 创建可被发现的Bean
@Component:Spring提供
@Named:Java依赖注入规范提供
@ComponectScan:组件扫描默认不启用,默认扫描与配置类相同的包以及所有子包
2.2.2 注入
@Autowired:Spring提供
@inject:来源于Java依赖注入规范
属性注入
构造方法注入
setter方法注入
2.3 Java代码装配Bean
2.3.1 创建配置类
@Configuration
import org.spingframework.context.annotation.Configuration;
@Configuration
public class CDPlayerConfig {
}
@Bean
@Bean(name="sgtPeppers")
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
2.3.2 通过JavaConfig实现注入
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer anotherCDPlayer() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
2.4 通过XML装配Bean
2.4.1 声明简单的
<bean id="compactDisc" class="soundsystem.SgtPeppers" />
2.4.2 构造器注入bean
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc">
</bean>
拓展:c命名空间:
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" />
字面量注入
<bean id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
</bean>
集合注入
和都可以用来装配List、Set甚至数组
<?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 id="compactDisc"
class="soundsystem.BlankDisc"
c:_0="Sgt. Pepper's Lonely Hearts Club Band"
c:_1="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>
</beans>
2.4.3 设置属性
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<property name="compactDisc" ref="compactDisc" />
</bean>
拓展:p命令空间:
<bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="compactDisc" />
字面量注入到属性
<bean id="compactDisc" class="soundsystem.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>
Spring util-命名空间
2.5 导入和混合配置
2.5.1 在JavaConfig中引用配置
@Import(CDPlayerConfig.class)
@ImportResource(“classpath:cd-config.xml”)
2.5.2 在XML中引用JavaConfig
<import resource="cdplayer-config.xml" />
三、高级装配
3.1 环境与profile
3.1.1 配置Profile Bean
@Profile:指定某个bean属于哪一个profile。可作用于类/方法
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 {
// 为dev环境装配的bean
@Bean(destroyMethod = "shutdown")
@Profile("dev")
public DataSource embeddedDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
// 为prod环境装配的bean
@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配置profile
3.1.2 激活profile
1、Spring 在确定哪个 profile 处于激活状态时,需要依赖两个独立的属性:spring.profiles.active 和 spring.profiles.default。
2、@ActiveProfile(“dev”)
3.2 条件化的Bean
@Bean
@Conditioal(MagicExistsCondition.class)
public MagicBean magicBean() {
return new MagicBean();
}
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");
}
}
3.3 处理自动装配的歧义性
3.3.1 标示首选&限定符
- @Primary:与 @Component 组合用在组件扫描的 bean 上,表示首选的Bean
- @Qualifier:使用限定符,在注入时指定Bean,与 @Autowired 和 @Inject 协同使用
@Autowired
@Qualifier("iceCream")
public void setDessert(Dessert dessert) {
this.dessert = dessert;
}
创建自定义限定符
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,
ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold { }
3.4 Bean的作用域
默认下,Spring应用上下文的bean都是单例创建。Spring定义了多种作用域:
- 单例(Singleton):在整个应用中,只创建 bean 的一个实例。
- 原型(Prototype):每次注入或者通过 Spring 应用上下文获取的时候,都会创建一个新的 bean 实例。
- 会话(Session):在 Web 应用中,为每个会话创建一个 bean 实例。
- 请求(Rquest):在 Web 应用中,为每个请求创建一个 bean 实例。
@Component
@Scop(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Notepad { ... }
<bean id="notepad" class="com.myapp.Notepad" scope="prototype" />
3.4.1 使用会话和请求作用域
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES)
public ShoppingCart cart() { ... }
- ScopedProxyMode.INTERFACES:实现ShoppingCart接口,将调用委托给实现bean
- ScopedProxyMode.TARGET_CLASS:以生成目标类扩展的方式创建代理
在xml中使用会话作用域
<bean id="cart" class="com.myapp.ShoppingCart" scope="session">
<aop:scoped-proxy />
</bean>
aop:scoped-proxy 是与 @Scope 注解的 proxyMode 属性功能相同的 Spring XML 配置元素。告诉 Spring 为 bean 创建一个作用域代理。默认情况下,它会使用 CGLib 创建目标类的代理。也可以将 proxy-target-class 属性设置为 false,进而要求它生成基于接口的代理
<bean id="cart" class="com.myapp.ShoppingCart" scope="session">
<aop:scoped-proxy proxy-target-class="false" />
</bean>
3.5 运行时注入
- 属性占位符(Property PlaceHolder)
- Spring表达式语言(SpEL)
3.5.1 注入外部的值
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
// 声明属性源,属性文件会加载到 Spring 的 Environment 中
@PropertySource("classpath:/com/soundsystem/app.properties")
public class ExpressiveConfig {
@Autowired
Environment env;
@Bean
public BlankDisc disc() {
return new BlankDisc(
env.getProperty("disc.title"),
env.getProperty("disc.artist")
);
}
}
Spring的Environment
- String getProperty(String key)
- String getProperty(String key, String defualtValue)
- T getProperty(String key, Class type)
- T getProperty(String key, Class type, T defaultValue)
- env.containsProperty(“disc.title”):检查一下某个属性是否存在
- env.getPropertyAdClass(“disc.class”, CompactDisc.class):将属性解析为类
- String[] getActiveProfiles():返回激活 profile 名称的数组;
- String[] getDefaultProfiles():返回默认 profile 名称的数组;
- boolean acceptsProfiles(String… profiles):如果 environment 支持给定 profile 的话,就返回true
解析属性占位符
在 Spring 装配中,占位符的形式为使用 ${ … } 包装的属性名称。
<bean id="sgtPeppers" class="soundsystem.BlankDisc"
c:_title="${disc.titlte}"
c:_artist="${disc.artist}" />
public BlankDisc(
@Value("${disc.title}") String title,
@Value("${disc.artist}") String artist) {
this.title = title;
this.artist = artist;
}
3.5.2 通过SpEL装配
- 使用 bean 的 ID 来引用 bean;
- 调用方法和访问对象的属性;
- 对值进行算术、关系和逻辑运算;
- 正则表达式匹配;
- 集合操作。
SpEL 表达式要放到 #{ … } 之中
表示字面值
#{3.14159} #{‘hello’} #{false}
引用Bean、属性和方法
- #{sgtPeppers}
- #{sgtPeppers.artist}
- #{artistSelector.selectArtist()}
- #{artistSelector.selectArtist().toUpperCase()}
- #{artistSelector.selectArtist()?.toUpperCase()} 类型安全运算符 ?.
表达式中使用类型
- T(java.lang.Math)
- T(java.lang.Math).PI
SpEL运算符
计算正则表达式
#{admin.email matches ‘[a-zA-Z0-9._%±]+@[a-zA-Z0-9.-]+\.com’}
matches 运算符对 String 类型的文本(作为左边参数)应用正则表达式(作为右边参数)。
计算集合
- #{jukebox.songs[4].title}
- #{jukebox.songs[T(java.lang.Math).random() * jukebox.songs.size()].title}
- #{jukebox.songs.?[artist eq ‘Aerosmith’]} 查询运算符 .?[],它会用来对集合进行过滤,得到集合的一个子集。
- #{jukebox.songs.^[artist eq ‘Aerosmith’]} .^[] 和 .$[],它们分别用来在集合中查询第一个匹配项和最后一个匹配项。
- #{jukebox.songs.![title]} 投影运算符,从集合的每个成员中选择特定的属性放到另外一个集合中。
- #{jukebox.songs.?[artist eq ‘Aerosmth’].![title]} 联合使用,获得 Aerosmith 所有歌曲的名称列表