Spring2学习笔记(1)

最近看完了<<spring in action(第二版)>>,感觉写得确实经典,本人将在接下来的时间来分享个人的学习笔记,内容可能不是太丰富,只是对一些知识点的总结,如果要详细学习的,建议大家去看这本书

 

1       基本 Bean 装配

1.1    Spring 容器

1、  Bean 工厂

(org.springframework.beans.factory.BeanFactory 接口定义 ) ,提供了基础的依赖注入

 

BeanFactory factory =

        new XmlBeanFactory( new ClassPathResource( "hello.xml" ));

GreetingService greetingService =

        (GreetingService) factory.getBean( "greetingService" );

2、  应用上下文

org.springframework.context.ApplicationContext

 

 

ApplicationContext ctx =

      new ClassPathXmlApplicationContext(

          "com/springinaction/chapter01/knight/knight.xml" );

 

    Knight knight =

        (Knight) ctx.getBean( "knight" );

 

1.2    配置的 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-2.0.xsd http://www.springframework.org/schema/aop             http://www.springframework.org/schema/aop/spring-aop-2.0.xsd " >

 

  < bean id = "greetingService"

      class = "com.springinaction.chapter01.hello.GreetingServiceImpl" >

    < property name = "greeting" value = "Buenos Dias!" />

  </ bean >

</ beans >

1.3    创建 Bean

1.3.1   声明一个简单 Bean

< bean id = "sonnet29" class = "com.springinaction.springidol.Sonnet29" />

< bean id = "saxophone" class = "com.springinaction.springidol.Saxophone" />

1.3.2   通过构造函数注入

  < bean id = "duke"

      class = "com.springinaction.springidol.PoeticJuggler" >

    < constructor-arg value= "15" />     <!— 注入数值 -->

     < constructor-arg ref = "sonnet29 " />   <!— 注入 XML 中声明的对象 -->

  </ bean >

 

Setter 注入

  < bean id = "Saxophonist"

      class = "com.springinaction.springidol.Instrumentalist" >

    < property name = "song" value = "Jingle Bells" />   <!— 注入简单数值 à

    < property name = "instrument" ref = "saxophone" />   <!— 注入对象 à

  </ bean >

 

1.3.3   注入内部 Bean

    特点:没有 id 属性

    缺点:

1、  不能复用

2、  还会影响 Spring 上下文中 XML 的可读性

  < bean id = "Saxophonist"

      class = "com.springinaction.springidol.Instrumentalist" >

    < property name = "song" value = "Jingle Bells" />  

< property name = "instrument" >

        <bean class="com.springinaction.springidol.Saxophone" />

</ property >

  </ bean >

 

  < bean id = "duke"

      class = "com.springinaction.springidol.PoeticJuggler" >

    < constructor-arg value= "15" />     <!— 注入数值 -->

     < constructor-arg >

       <bean class="com.springinaction.springidol.Sonnet29" />

    </ constructor-arg />

  </ bean >

 

1.3.4   装配集合

<list> <set> :可与任意的 java.util.Collection 中的属性交换

<map> <props> props 要求值、键都是 String map 没有要求

  < bean id = "springIdol" class = "com.springinaction.springidol.SpringIdol" >

    < property name = "performers" >

      < list >

        < ref bean = "duke" />

        < ref bean = "kenny"   />

        < ref bean = "hank"   />

      </ list >

    </ property >

  </ bean >

 

  < bean id = "hank" class = "com.springinaction.springidol.OneManBand" >

    < property name = "instruments" >

      <props>

        <prop key="GUITAR">STRUM STRUM STRUM</prop>

        <prop key="CYMBAL">CRASH CRASH CRASH</prop>

        <prop key="HARMONICA">HUM HUM HUM</prop>

      </props>

    </ property >

  </ bean >

 

<map> 中的每个 <entry> 都有一个键和值组成

key(String),key-ref,value(String),value-ref

  < bean id = "hank" class = "com.springinaction.springidol.OneManBand" >

    < property name = "instruments" >

      < map >

        < entry key = "GUITAR" value = "STRUM STRUM STRUM" />

         < entry key-ref = "instrument1" value-ref = "saxophone " />

       </ map >

    </ property >

  </ bean >

 

1.3.5   装配空值

< property name = "someNonNullProperty" > <null/> </ property>

 

1.3.6   自动装配 (autowire)

byName,byType,constructor,autodetect

  < bean id = "duke"

      class = "com.springinaction.springidol.PoeticJuggler"

      autowire = "constructor" >

<!--     <constructor-arg ref ="sonnet29" />  -->

  </ bean >

 

默认自动装配

Spring 配置文件的根元素 <beans> 中设置 default autowire ,就可以将所有的 Bean 设置为自动装配如:

< beans default-autowire = "byName" >

……

</ bean >

缺点:不透明,不推荐使用

 

1.4    控制 Bean 创建

1.4.1   Bean 范围化

每次请求时生成唯一的实例,设置 scope 属性

singleton,prototype,request,session,global-session

< bean id = "saxophone"

class = "com.springinaction.springidol.Saxophone"

scope="prototype" />

 

1.4.2   配置单例 Bean

< bean id = "theStage"

class = "com.springinaction.springidol.Stage"

factory-method="getInstance" />

 

1.4.3   初始化和销毁 Bean

Bean 中使用 init-method destroy-method 属性

    init-method=” 初始化方法名 ” destroy-method=” 销毁方法名

默认初始化和销毁方法

<beans> 中使用

default-init-method=” 初始化方法名 ”,

default-destroy-method=” 销毁方法名

 

还可以重写 InitializingBean DisposableBean 接口,分别实现 afterPropertiesSet(),destroy() 方法,实现这些接口的缺点是应用 Bean SpringAPI 相互耦合,建议用 init-method destroy-method

 

 

2       高级 Bean 装配

2.1    声明父 Bean 和子 Bean

2.1.1   抽象基 Bean 类型

  < bean id = "baseSaxophonist"

      class = "com.springinaction.springidol.Instrumentalist"

      abstract="true" >

    < property name = "song" value = "Jingle Bells" />

    < property name = "instrument" ref = "saxophone" />    

  </ bean >

继承

  < bean id = "kenny" parent = "baseSaxophonist" />

  < bean id = "david" parent = "baseSaxophonist" />

覆盖继承的属性

  < bean id = "frank" parent = "baseSaxophonist" >

    < property name = "song" value = "Mary had a little lamb" />

  </ bean >

 

2.1.2   抽象共同属性

定义共同属性 song ,但它没有设置 class 属性

  < bean id = "basePerformer" abstract="true" >

    < property name = "song" value = "Somewhere Over the Rainbow" />

  </ bean >

Bean 利用自己的 class 属性来确定自己的类型

  < bean id = "taylor" class = "com.springinaction.springidol. Vocalist "

    parent = "basePerformer"/ >

 

  < bean id = "stevie" class = "com.springinaction.springidol. Instrumentalist "

       parent = "basePerformer" >

    < property name = "instrument" ref = "guitar" />

  </ bean >

 

2.2    方法注入

方法替换

获取器注入

2.3    注入非 Spring Bean

2.0 可以明确地配置在 Spring 之外实例化的 Bean 。也就是说,这些 Bean 不是由 Spring 创建的,但可以由 Spring 配置

@Configurable("pianist")

public class Instrumentalist implements Performer {

...

}

@Configurable 的作用:

1、   表示 Instrumentalist 实例即使在 Spring 之外创建的,仍然可以由 Spring 进行配置

2、   它把 Instrumentalist 类与 id pianist Bean 关联 起来。当S pring 企图配置 Instrumentalist 实例时,会以 pianist Bean 作为模板

 

还需在 Spring 配置中添加如下内容:

< aop:spring-configured />

 

2.4    注册自定义属性编辑器

2.5    使用 Spring 的特殊 Bean

后处理 Bean

Bean 工厂的后处理

配置属性的外在化

提取文本消息

程序事件的解耦

Bean 了解容器

2.6    脚本化的 Bean

 

3       通知 Bean

3.1    AOP 简介

Aspect Oriented Programming ,面向切面编程,切面有助于实现交叉事务的模块化

3.1.1   术语

通知 (Advice)

       通知定义了切面是什么以及何时使用

切入点 (Pointcut)

       切入点定义了“何地”

切面 (Aspect)

       切面是通知和切入点的结合。通知和切入点共同定义了关于切面的全部内容 它的功能、在何时和何地完成其功能

连接点 (Joinpoint)

引入 (Introduction)

目标 (Target)

代理 (Proxy)

织入 (Weaving)

 

3.1.2   Spring AOP 的支持

经典的基于代理的 AOP( 各版本 Spring)

@AspectJ 注解驱动的切面 ( Spring2.0)

POJO 切面 ( 2.0)

注入式 AspectJ 切面 ( 各版本 )

 

3.2    创建典型的切面

3.2.1   创建通知

5 种形式

Before( ) After-returning( 返回后 ) After-throwing( 抛出后 ) Around( 周围 ) Introduction( 引入 )

public class AudienceAdvice implements MethodBeforeAdvice,

    AfterReturningAdvice, ThrowsAdvice {

 

  public AudienceAdvice() {}

   

  public void before (Method method, Object[] args, Object target)

      throws Throwable {

    audience .takeSeats();

    audience .turnOffCellPhones();

  }

  // 前通知,第一个参数是个 java.lang.reflect.Method 对象,它代表要使用这个通知的方法。第二个参数是一个 Objects 数组,是方法被调用时要传递的参数。最后一个参数是方法调用的目标。

  public void afterReturning (Object rtn, Method method,

      Object[] args, Object target) throws Throwable {

    audience .applaud();

  }

  //rtn 表示从被调用方法返回的值

    public void afterThrowing(Method method, Object[] args, Object target,

      Throwable throwable) {

    audience .demandRefund();

  }

  // 最后一个参数必须,其他可选

  // injected

  private Audience audience ;

  public void setAudience(Audience audience) {

    this . audience = audience;

  }

}

 

定义 Bean

  < bean id = "audience" class = "spring.simple.springidol.Audience" />

  < bean id = "audienceAdvice"

      class = "spring.simple.springidol.AudienceAdvice" >

    < property name = "audience" ref = "audience" />

  </ bean >

 

 

3.2.2   周围通知

MethodInterceptor 接口来定义

public class AudienceAroundAdvice implements MethodInterceptor {

  public Object invoke(MethodInvocation invocation) throws Throwable {

 

    try {

      audience .takeSeats();

      audience .turnOffCellPhones();     // 调用前

 

      Object returnValue = invocation.proceed();   // 调用目标方法

   

      audience .applaud();            // 成功返回之后

   

      return returnValue;

    } catch (PerformanceException throwable) {

      audience .demandRefund();       // 在出现异常之后执行

     

      throw throwable ;

    }

  }

 

  // injected

  private Audience audience ;

  public void setAudience(Audience audience) {

    this . audience = audience;

  }

}

好处:一是能以简洁的方式在一个方法里定义前通知和后通知。如果需要在执行方法之前和之后都使用通知,使用周围通知会比分别单独实现两种通知更方便。利用周围通知还可以检查和修改被通知方法的返回值

必须要调用 proceed() 方法

 

3.3    定义切点和通知者

3.3.1   正则表达式切点

  < bean id = "audiencePointcut"

      class = "org.springframework.aop.support.JdkRegexpMethodPointcut" >

    < property name = "pattern" value = ".*perform" />

  </ bean >

Pattern 属性用于指定方法匹配所使用的切点模板,本例中被设置为一个正则表达式,匹配任何类里名为 perform() 的方法

定义通知:

  < bean id = "audienceAdvisor"

      class = "org.springframework.aop.support.DefaultPointcutAdvisor" >

    < property name = "advice" ref = "audienceAdvice" />

    < property name = "pointcut" ref = "audiencePointcut" />

  </ bean >

 

联合切点与通知者

RegexpMethodPointcutAdvisor 是个特殊的通知者类,可以在一个 Bean 里定义切点和通知者

< bean id = "audienceAdvisor"

    class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" >

    < property name = "advice" ref = "audienceAdvice" />

    < property name = "pattern" value = ".*perform" />

  </ bean >

 

3.3.2   AspectJ 表达式切点

  < bean id = "audiencePointcut"

      class = "org.springframework.aop.aspectj.AspectJExpressionPointcut" >

    < property name = "expression" value = "execution(* *.perform(..))" />

  </ bean >

 

execution(* *.perform(..)):

执行方法时 ( 使用任意返回类型 任意类 .perform() 方法 ( 任意参数 ))

 

要使用的通知类是 AspectJExpressionPointcutAdvisor

< bean id = "audienceAdvisor"

      class = "org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor" >

    < property name = "advice" ref = "audienceAdvice" />

    < property name = "expression" value = "execution(* *.perform(..))" />

  </ bean >

 

通知者把通知与切点关联起来,从而完整地定义一个切面,但切面在 Spring 里是以代理的方式实现的。

 

3.4    使用 ProxyFactoryBean

  < bean id = "bo"

      class = "org.springframework.aop.framework.ProxyFactoryBean" >

    < property name = "target" ref = "boTarget" />  // 被通知的 Bean

    < property name = "proxyInterfaces"

        value = "com.springinaction.springidol.Performer" />    // 应该实现的哪个接口

    < property name = "interceptorNames" value = "audienceAdvisor" />// 通知者

  </ bean >

 

3.4.1   抽象 ProxyFactoryBean

< bean id = "audienceProxyBase"

      class = "org.springframework.aop.framework.ProxyFactoryBean"

abstract=”true” >

    < property name = "proxyInterfaces"

        value = "com.springinaction.springidol.Performer" />        < property name = "interceptorNames" value = "audienceAdvisor" />

  </ bean >

 

利用 audienceProxyBase 进行扩展

< bean id = "stevie" parent="audienceProxyBase" >

    < property name = "target" ref = "stevieTarget" />

</ bean >

< bean id = "duke" parent="audienceProxyBase" >

    < property name = "target" ref = "dukeTarget" />

</ bean >

 

3.5    自动代理

3.5.1   Spring 切面创建自动代理

Spring 上下文里声明如下的 <bean>

< bean class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

对于简单的通知或运行于 java5 之前的环境时,以上自动代理是不错的

 

3.5.2   自动代理 @AspectJ 切面

@Aspect        // 声明切面

public class Audience {

  public Audience() {}

  @Pointcut("execution(* *.perform(..)) ")      // 定义演出切点

  Public void performance(){}

 

  @Before("performance()")                  // 定义之前执行

  public void takeSeats() {

    System. out .println( "The audience is taking their seats." );

  }

  @Before("performance()")                  // 定义之前执行

  public void turnOffCellPhones() {

    System. out .println( "The audience is turning off their cellphones" );

  }

  @AfterReturning("performance()")                 // 定义之后执行

  public void applaud() {

    System. out .println( "CLAP CLAP CLAP CLAP CLAP" );

  }

  @AfterThrowing("performance()")                  // 定义出错执行

  public void demandRefund() {

    System. out .println( "Boo! We want our money back!" );

  }

}

把以上 Audience 应用为一个切面还须在 Spring 上下文里声明一个自动代理 Bean ,它知道如何把 @AspectJ 注解的 Bean 转化为代理通知

自动代理创建器类: AnnotationAwareAspectJAutoProxyCreator ,也可以用 aop 命名空间 <aop:aspectj-autoproxy>

 

      注解周围通知

  @Around("performance()")

  public void watchPerformance(ProceedingJoinPoint jp) {

    System. out .println( "The audience is taking their seats." );

    System. out .println( "The audience is turning off their cellphones" );

    try {

      jp.proceed();

      System. out .println( "CLAP CLAP CLAP CLAP CLAP" );

    } catch (Throwable throwable) {

      System. out .println( "Boo! We want our money back!" );     

    }

  }

 

3.6    利用 AOP 定义切面

  < aop:config >

    < aop:pointcut

        id = "performance"

        expression = "execution(* *.perform(..))" /> <!-- 定义切点 -->

    < aop:aspect ref = "audience" >

      < aop:before

          method = "takeSeats"

          pointcut-ref = "performance" />

 

      < aop:before

          method = "turnOffCellPhones"

          pointcut-ref = "performance" />

         

      < aop:after-returning

          method = "applaud"

          pointcut-ref = "performance" />

         

      < aop:after-throwing

          method = "demandRefund"

          pointcut-ref = "performance" />

 

    <aop:around

          method="aroundAdvice"

          pointcut-ref="performance" />

    </ aop:aspect >

  </ aop:config >

 

3.7    注入 AspectJ 切面

( 这部分在学习的时候也未搞清楚 , 示例代码是 .aj 的文件 ,还望高人指点)

 

package com .springinaction .springidol ;

 

public aspect JudgeAspect {

  public JudgeAspect() {}

 

  pointcut performance() : execution(* perform(..));

 

  after() returning() : performance() {

    System.out.println (criticismEngine.getCriticism());

  }

 

  // injected

  private CriticismEngine criticismEngine;

 

  public void setCriticismEngine(CriticismEngine criticismEngine) {

    this.criticismEngine = criticismEngine;

  }

}

 

  < bean id = "criticismEngine"

      class = "com.springinaction.springidol.CriticismEngineImpl" >

    < property name = "criticismPool" >

      < list >

        < value > I'm not being rude, but that was appalling. </ value >

        < value > You may be the least talented person in this show. </ value >

        < value > Do everyone a favor and keep your day job. </ value >

      </ list >

    </ property >

  </ bean >

 

  < bean class = "com.springinaction.springidol.JudgeAspect"

      factory-method="aspectOf" >

    < property name = "criticismEngine" ref = "criticismEngine" />

  </ bean >

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值