Spring2学习笔记(1)

来源:互联网 发布:淘宝美工自我评价 编辑:程序博客网 时间:2024/05/18 06:21

最近看完了<<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.xsdhttp://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要求值、键都是Stringmap没有要求

  <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>

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

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

        <propkey="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 STRUMSTRUM" />

        <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-methoddestroy-method属性

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

默认初始化和销毁方法

<beans>中使用

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

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

 

还可以重写InitializingBeanDisposableBean接口,分别实现afterPropertiesSet(),destroy()方法,实现这些接口的缺点是应用BeanSpringAPI相互耦合,建议用init-methoddestroy-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    注入非SpringBean

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

@Configurable("pianist")

public class Instrumentalist implements Performer {

...

}

@Configurable的作用:

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

2、   它把Instrumentalist类与idpianistBean关联起来。当Spring企图配置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   SpringAOP的支持

经典的基于代理的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 voidafterThrowing(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 thisshow.</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>

 

 

原创粉丝点击