Spring In Action 4

在线学习连接:spring in action 4

关键词解释

名词解释
EJBEnterprise JavaBean,企业级JavaBean
POJOPlain Old Java Object,简单老式Java对象
J2EEJava 2 Enterprise Edition,Java2企业版
DIDependency Injection,依赖注入,获取对象的过程被反转,获得依赖对象的过程由自身管理变成由IOC容器主动注入
IOCInversion of Control,控制反转,借助于“第三方” 实现具有依赖关系的对象间解耦
AOPAspect-Oriented Programming,面向切面编程
装配wiring 创建应用对象间协助关系的行为
JNDIJava 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的生命周期

Bean的生命周期

1.2.3 俯瞰Spring风景线

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运算符

SpELl运算符

计算正则表达式

#{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 所有歌曲的名称列表
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值