您的位置:首页 > 编程语言 > Java开发

spring知识概要

2016-09-30 17:33 232 查看

Spring基础

基本上所有的框架都是提取实际开发中大量重复步骤而成

围绕Spring框架,还衍生出了如Spring Web Flow、Spring Security等框架

Spring框架优点

1) 低侵入式,代码污染低

2) 独立于各种应用服务器

3) IOC降低了业务对象替换的复杂性,降低了组件之间的耦合

4) AOP支持通用任务如日志、事务、安全等的集中处理

5) ORM和DAO提供了与第三方持久框架的良好整合,并简化了底层数据库的访问

6) 开发者可自由选择Spring框架的部分或全部,不像有些框架得全部引用

Spring容器(Spring Core Container)是Spring的核心机制,它主要由以下4个包和其子包组成:

a) org.springframework.core

b) org.springframework.beans

c) org.springframework.content

d) org.springframework.expression

spring容器还依赖于common-logging 这个JAR包

Spring容器中的Bean是一个泛化概念,只要是一个Java类就可当成Bean。Spring容器使用xml配置文件来管理这些Bean,所以配置到XML文件中的Bean,Spring容器就可管理它。

一个对象需要调用另一个对象的情形就可称为依赖

Spring容器利用XML配置文件管理Bean的原理

我们将Bean配置在XML文件里后,在创建Spring容器后,Spring容器就开始解析Xml文件。当解析到
<bean…/>
元素里class属性的完整类名时,就会利用反射机制实例化一个对象,当解析到
<property…/>
元素时,就会执行该对象的setter方法,其中name属性决定执行哪个setter方法,value或ref属性决定setter方法的传入参数。最后在完成注入后,将
<bean…/>
元素里的id属性值和创建的对象以键值对的形式存在Spring容器中,这样Spring容器就可管理Bean了。

XML配置文件中
<property…/>
元素什么时候用value属性,什么时候用ref属性?

a) 当传入参数是基本数据类型或String类型时用vlaue

b) 当传入参数是其他Bean时,则用ref(即引用类型用ref)

如何访问Spring容器中的Bean?

常用ApplicationContext接口的实现类来获取,该接口主要有以下两个方法:

a) Object getBean(String name):获取容器中id为name的Bean实例

b) T getBean(String id,
Class<T> type
):根据id名和Bean类型获取该Bean

ApplicationContext接口的主要实现类:

a) ClassPathXmlApplicationContext :从类加载路径下搜索配置文件

b) FileSystemXmlApplicationContext:从文件系统的相对或绝对路径下搜索配置文件

c) AnnotationConfigWebApplicationContext:使用注解替换xml配置文件时使用

示例:

ApplicationContext  app = new ClassPathXmlApplicationContext(“beans.xml”);
User  user = (User) app.getBean(“user”)


10.总结

有了spring后,程序可不再使用new来创建对象了

Spring容器

由前面了解到,Spring容器是利用xml配置文件来生产并管理Bean的,而访问Spring容器中的Bean利用了Application接口,所以我们用该接口来代表Spring容器。实际上,ApplicationContext的父接口BeanFactroy也可代表Spring容器,但我们一般不用它作为Spring容器,除非应用对内存非常关键。

ApplicationContext容器接口 除有BeanFactory全部功能以外,还有以下功能:

a) 在创建容器时就初始化容器中的Bean,可通过
<bean…/>
元素的lazy-init=”true”取消

b) 因继承了MessageSource接口所以支持国际化

c) 支持资源访问,如URL和文件

d) 支持事件机制

e) 可同时加载多个配置文件

f) 能通过声明方式启动并创建Spring容器

ApplicationContext接口的实现类

a) 常用实现类:

ClassPathXmlApplicationContext:从类加载路径下搜索配置文件

FileSystemXmlApplicationContext:从文件系统的相对或绝对路径下搜索配置文件

AnnotationConfigApplicationContext:使用Java配置替换xml配置文件时使用

b) 在web应用中常用的实现类:

XmlWebApplicationContext:

AnnotationConfigWebApplicationContext:使用注解替换xml配置文件时使用

编程式实例化ApplicationContext

ApplicationContext app = new ClassPathXmlApplicationContext(“beans.xml”);

声时式创建并启动Spring容器(ApplicationContext)

1) 当beans.xml文件放在WEB-INF下时,只需在web.xml中配置:

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>


2) 当beans.xml放在src目录(即classpath)下时,则需在web.xml当中配置:

<context-param>
<!-- 加载spring容器:单词不能写错 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath: beans.xml</param-value>
</context-param>
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>


当有多个配置文件时,可在classpath后面使用通配符“*”

Spring创建Bean的3种方式

Spring创建Bean的3种方式

a) 调用构造器

b) 调用静态工厂方法

c) 调用实例工厂方法

使用静态工厂方法

1) 此时
<bean…/>
元素需要指定以下两属性

a) class:指定静态工厂类的类名

b) factory-method:指定创建实例的静态工厂方法

2) 示例

public class Dog implements Animal{ //要求类化的类
private String msg;
public void setMsg(String msg){
this.msg = msg;
}
public void eat(){
System.out.print(msg);
}
}
public class Dog  AnimalFactory{ //静态工厂类代码
public static  Animal  getAnimal(String name){
if(“dog”.equalsIgnoreCase(name)){
return  new Dog();
}else{
return  new  Cat();
}
}
}
//对应配置文件
<bean id="dog" class="com.dfsj.AnimalFactory"  factory-method=”getAnimal”>
<constructor-arg  value="dog"/>
<property name="msg" value="我是狗"/>>
</bean>


需要注意的是,静态工厂方法的参数通过
<constructor-arg…/>
元素配置,而新建对象的属性的值通过
<property…/>
元素设置

3.使用实例工厂方法创建Bean时,
<bean…/>
元素需要指定如下两属性:

a) factory-bean:指定工厂类实例,即工厂类在配置文件中的id

b) factory-method:指定实例工厂创建实例方法

4.静态工厂方法与实例工厂方法的区别:

不同点:

a) 静态工故事有class属性,指定的是静态 工厂类的类名,而实例工厂是用factory-bean属性指定工厂类在配置文件中的id

b) 静态工厂方法创建Bean实例的方法是静态的

相同点

a) 都需要用factory-method指定创建Bean实例的方法

b) 工厂方法里的参数都必须通过
<constructor-arg…/>
元素来配置

c) 给新创建的Bean实例的属性赋值,都是用
<property…/>
元素

Spring容器中Bean的作用域

1. Spring容器的bean的作用域通过sope属性指定

<bean id=”test” class=”com.dfsj.Test”  scope=”prototype”>


常用的两个作用域

a) singleton:在IOC容器中只生成一个实例

b) prototype:每次通过容器的getBean()方法获取该作用域的Bean时,都将产生一个新的实例

只在web项目中有效的几个作用域

a) reqeust:对于一次http请求,该作用域下的Bean只生成一个实例

b) session:对于一次会话,只生成一个实例

c) global session:在全局会话,里生成一个实例

在web.xml中配置使request作用域生效的Listener

<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>


5 注

在springMVC框架中,已有SpringDispatherServlet或DispatherServlet来拦截处理所有和请求有关的状态处理,所以不需要如编号4的Listerner配置。

Spring核心机制:依赖注入

1.注入方式

设值注入

<bean  id=”user”  class=”com.app.User”>
<property  name=”name”  vlaue=”张三”/>
<property  name=”age”  vlaue=”30”/>
</bean>


2.构造注入

<bean id="test" class="com.test.Test">
<property name="name" value="Peter"/>
<constructor-arg ref="person"/>
<constructor-arg value="张三" type="String"/>
</bean>


构造注入的参数序安出现的顺序为准,除非以index属性指定(下标从0开始)


3.在使用spring框架时,眼睛看到xml配置时,心中要想到底层Java代码是如何实现的,用得熟练时,看到任何一段Java代码都能用xml文件配置也来

2 各种注入示例

以参数下标方式配置有参构造,不指定index时,以出现顺序注入

<bean id="test" class="com.test.Test">
< constructor-arg index=”0” value="ddd"/>
<constructor-arg  index=”1” value=”44”/>
</bean>


2.注入基本数据类型

<bean id="test" class="com.test.Test">
< property  name=”name”  value="ddd"/>
< property  name=”age”  value="30"/>
</bean>


3.注入其他Bean

<bean id="dog" class="com.test.Dog">
<bean id="test" class="com.test.Test">
< property  name=”dog”  ref="dog"/>
</bean>


4.注入嵌套Bean

<bean id="test" class="com.test.Test">
< property  name=”cat” >
<bean  class=”com.test.Cat”>
</property>
</bean>


5.注入Map集合

entry元素有4个属性:

key:当key值是基本数据类型或字符串类型时使用

key-ref:当key值是引用类型时使用

value:当value值是基本数据或字符串类型时使用

value-ref:当value值是引用类型时使用

示例:给
private Map<String,Axe>  axes
注入

<bean id="test" class="com.test.Test">
< property  name=”axes” >
<map>
<entry key=”name” value=”张三”/>
</map>
</property>
</bean>


6.注入数组(与注入List集合一样):如给
private String[] cities
;注入

<bean id="test" class="com.test.Test">
< property  name=”cities” >
<list>
< value=”北京”/>
< value=”重庆”/>
</list>
</property>
</bean>


7.注入List集合:如给
private  List<String>  cities;
注入

<bean id="test" class="com.test.Test">
< property  name=”cities” >
<list>
< value=”北京”/>
< value=”重庆”/>
</list>
</property>
</bean>


8.注入Properties集合(Properties类实现了Map接口)

<bean id="test" class="com.test.Test">
< property  name=”health” >
<props>
<prop  key=”血压” >正常</prop>
<prop  key=”身高” >175</prop>
</props>
</property>
</bean>


9.注入Set集合:如给private Set set注(因为泛型,所以可以注入各种类型的)

<bean id="test" class="com.test.Test">
< property  name=”set” >
<set>
< value>普通字符串< value/> //基本数据类型或字符串
<bean class=”com.test.User”> //嵌套Bean
<ref  brean=”stoneAxe”>  //容器中的其他Bean
<list>                   //List集合
< value>20< value/>
<set>
< value>30< value/>
</set>
</list>
</set>
</property>
</bean>


10.当
<list…/>、<set…/>、<map…/>
这些元素在配置注入时,如果这些集合未泛型,则其值可以是基本数据类型、字符串、容器中其他Bean、嵌套Bean、集合等各种数据类型,如上面Set集合注入的示例

Spring的组合属性

1. 所谓组合属性,就是一个类的属性还有自己的属性。因为涉及到调用,所以在使用组合属性时,除最后一个属性外,前面调用者都不能为空。

2. 示例

Java代码:
public class  Test{
private  Person  person = new Person; //这里一定要new
//….getter 、setter方法
}
对应配置代码:
<bean id="person" class="com.test.Person" />
<bean id="test" class="com.test.Test">
< property  name=”person.name”  value=”张三” >
</bean>


3.Spring中的Bean与Java的Bean的区别

1) 写法不同:

传统的JavaBean作为对象,要求每个属性都必须提供getter setter方法,而SpringBean只需要为接受设值注入的属性提供setter方法即可,但是如果要获取该属性值,还是需要写getter方法的

2) 生命周期的不同:

传统的JavaBean不接受容器的管理,而SpringBean是由spring容器管理它的生命周期和行为的

3) Spring中的Bean即使有”有参构造函数,最好也提供无参构造函数

Spring的Java配置管理

Spring的Java配置管理,代替了之前的xml文件配置管理

1. 实现

1)利用@Configuration注解修饰的类(后面就叫配置类)代替xml文件

2)有@Bean注解修饰一个方法,该方法的返回的对象将定义成容器中的Bean

3)用@Value注解修饰一个Field,相当于配置一个变量

2. 示例

@Configuration
public  class  AppConfig{
@Value("张三") String  personName;

@Bean(name="chinese")
public Person getPerson(){
Chinese  c = new  Chinese();
c.setAxe(getStoneAxe ()); // 获取stoneAxe对象并注入
c.setName(personName);
return  c;
}
@Bean(name="stoneAxe")
public  Axe  getStoneAxe(){
return  new StoneAxe();
}
}


3.Java配置管理时创建容器

ApplicationContext  app = new AnnotationConfigApplicationContext(AppConfig.class);


如果是web应用,则用AnnotationConfigWebApplicationContext创建

4.XML配置管理与Java配置管理的混用

1)在xml配置文件中导入Java配置类

<bean  class="com.dfsj.util.AppConfig">


2)在Java配置类里导入xml配置文件

@Configuration
@ImportResource("classpath:/beans.xml")
public class  AppConfig{
//….
}


5.Java配置类的其他注解

1)@Import:修饰Java类,用于导入其他Java配置类

2)@Scope:修饰创建Bean的方法,用于指定生成的Bean的作用域

3)@Lazy:修饰创建Bean的方法,用于指定生成Bean是否延迟初始化

4)@DependsOn:修饰创建Bean的方法,用于指定在初始该方法前要初始化的其他Bean

深入理解Spring容器中的Bean

1. 抽象Bean

1)抽象Bean由
<bean.../>
元素的abstract=”true”属性指定,如:

<bean  id="test"  abstract="true">
<property  name="username"  value="peter"/>
<property  name="age"  value="peter"/>
</bean>


从上面示例中可以看到,并没有用class属性指定类,这是为什么呢?

因为我们知道,抽象Bean是不可被实例化的,即便指了类的完整名也不会用到,还有就是,Spring中的Bean的继承是对象与对象之间的关系,而不是类与类之间的关系,只存在参数之间的传递,所以抽象类须指定参数。抽象类的属性值,在子类当中也能获取到。

2. 继承Bean

1)在Spring中,Bean的继承是由parent属性指定的,如:

<bean  id="son"  class="com.dfsj.Son"  parent="test">
parent指定的值是父类在容器中的id


2)当子类信息与父类信息不一致时,子类的覆盖父类的

3)子类无法从父类继承这些属性:depends-on、autowire、singleton、scope、lazy-init

3 .Spring中Bean的继承与Java中类的继承的区别:

1)前者是对象与对象之间的关系,后者是类与类的关系

2)前者主要表现为参数值的延续,后者主要是方法、属性的延续

3)Spring中的Bean不可作为父Bean使用,而Java中子类可以当成父类实例使用

4.工厂Bean

详情参见P580-P582

1.工厂Bean是实现FactoryBean接口的Bean

2.FactoryBean接口提供了如下几个方法:

(1) T getObject():返回该工厂的自定义内容

(2)
class<?>  getObjectType()
:返回该工厂自定义内容(java实例)的类型(实现类)

(3) boolean isSingleton():返回自定义的java实例是否为单例模式

3.工厂Bean配置在xml文件后,通过Spring容器的getBean()方法获取时,得到的不是该Bean的实例,而是由开发者在getOject()方法里自定义的返回值,可能是一个数字,也可能是一个字符串,也可能是一个对象,所以此时配置工厂Bean时的id属性指定的是getObject方法返回值在容器中的唯一标识。

4.如何返回工厂Bean本身?

当我们在用Spring容器的getBean()方法获取工厂Bean时,在id前面加上”&”符

号即可,如:

ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
app.getBean("&factoryBeanId");


5.强制初始化其他Bean

如果某个类的初始化块中使用了其他Bean,则这种依赖不够直接,当spring初始主调Bean时,可能会由于初始化块中的其他Bean还未被初始化,则会抛出像空指针之类的异常。这时我们可通过depends-on属性在初始化主调Bean前强制先初始化其他Bean,如:

<bean id="person"  class="com.test.Person" />
<bean id="test"  class="com.test.Test"  depends-on="person" />


Spring中Bean的生命周期

1. prototype作用域的Bean的生命周期

当Spring容器创建了prototype作用域的Bean实例之后,Bean实例完全交给客户端代码管理,容器不再跟踪其生命周期,且每次客户端请求该Bean时,都会新建一个实例。

2. singleton作用域的Bean的生命周期

每次客户端请深圳市singleton作用域的Bean时,返回的都是同一个实例,spring容器负责跟踪Bean实例的产生和销毁。

3. Spring如何管理Bean的生命周期

1)依赖注入之后的行为,两种方式:

(1) 通过实现InitializingBean接口,然后利用afterPropertiesSet()方法处理

(2) 通过
<bean.../>
元素的init-method属性指定的方法处理

<bean id="test" class="com.dfsj.Test" init-method="initMethod">
<property  name="username"  value="peter"/>
</bean>
//这里的意思是,在完成Test注入之后,先执行Test里的initMethod()方法
//如果(1)、(2)两种方式都实现了,则在依赖注入之后,先执行(1)的方法


2)Bean销毁之前的行为,两种方式

(1) 通过实现DisposableBean接口,然后利用destroy()方法处理

(2) 通过
<bean.../>
元素的destroy-method属性指定要执行的处理方法

如果(1)、(2)两种方式都实现了,则在依赖注入之后,先执行(1)的方法

协调作用域不同步的Bean:参见P589-P591

Spring的其他依赖配置

如果Spring框架用得熟练,别人给你任何一段Java代码,你都能用spring的配置文件配置出来。前面了解了用
<property.../>
元素配setter方法、用
<constructor-arg.../>
元素配置有参构造等等,下面我们来了解下如何配一个类的setter方法、普通方法、属性、Field

详情参见P592~P599

1. 使用PropertyPathFactoryBean获取其他Bean的属性值

1)PropertyPathFactoryBean属于工厂Bean,所以获得其他Bean的属性值的原理就是利用工厂Bean的getObject自定义返回值实现的,示例如:

<bean  id="test"  class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<!-- person是Person类在容器中的id -->
<property  name="targetBeanName"  value="person"/>
<property  name="propertyPath"  value="name"/>
</bean>


2)解释上面配置:给PropertyPathFactoryBean的targetBeanName属性注入指定Bean的id,给propertyPath属性注入指定需要返回值的属性,通过容器获的getBean(“test”)方法获取的值就是Person类的name属性的值

3)获取指定Bean的具体某个属性值的简单方式:

<bean id="son.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>

//此时容器getBean方法得这样写:getBean("son.age");
//son是Son类在容器中的唯一标识


2. 使用FieldRetrivingFactoryBean获取其他Bean的Field值

首先要明确的是,这里所说的Field都是以public修饰的

1)获取静态的Field的值,用targetClass属性

<bean  id="test" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property  name="targetClass"  value="com.dfsj.Test"/>
<property  name="targetField"  value="NAME"/>
</bean>

//或者:
<bean  id="test" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property  name="targetClass"  value="com.dfsj.Test"/>
<property  name="staticField"  value="com.dfsj.Test.NAME"/>
</bean>


2)获取实例Field,targetObject属性

<bean  id="test" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property  name="targetObject"  ref="test"/>
<property  name="targetField"  value="age"/>
</bean>


虽然2) 也能获取静态Field值,但不推荐这么用

3. 使用MethodInvokingFactoryBean获取其他Bean的方法的返回值

1)获取静态方法返回值

<bean  id="jt" class="org.springframework.beans.factory.config. MethodInvokingFactoryBean">
<property  name="targetClass"  value="com.dfsj.Test"/>
<property  name="targetMethod"  value="staticMethodName"/>
<property  name="arguments"  >
<list>
<value>"firstArgument"</value>
<value>"secondArgument"</value>
</list>
</property>
</bean>


2)获取普通方法返回值

<bean id="pu" class="org.springframework.beans.factory.config. MethodInvokingFactoryBean">
<property  name="targetObject"   ref="test"/>
<property  name="targetMethod" value="staticMethodName"/>
<property  name="arguments" value="传一个参数" />
</bean>


Spring基于xml Schema的简化配置

1. p:命名空间

p:命名空间用于代替
<property.../>
元素进行设值注入

1.语法

1)基本数据类型属性:p:属性名=”值”

2)引用类型属性:p:属性名-ref=”引用Bean的id”

2.导入p:命名空间

http://www.springframework.org/schema/p


3.示例

<bean  id="test" class="com.dfsj.Test"  p:name="peter"  p:person-ref="person"/>
//等价于:
<bean  id="test"  class=" com.dfsj.Test ">
<property  name="name"  value="peter"/ >
<property  name="person"  ref="person"/ >
</bean>


注意

如果Bean的属性名以”-ref” 结尾,那么采用p:命名空间就会发生冲突

2. c:命名空间

c:命名空间用于代替
<constructorg-arg.../>
元素

1. 导入c:命名空间

http://www.springframework.org/schema/c

2. 语法

index是参数下标,从0开始

1)基本数据类型:c:构造参数名=”值” 或c:_index=”值”

2)引用类型:c: 构造参数名-ref=”引用Bean的id” 或 c:_index-ref=”其他Bean的id”

3.示例

<bean  id="test" class="com.dfsj.Test"  c:name="jhon"  c:axe-ref="stoneAxe"/>
//等价于:
<bean  id="test"  class=" com.dfsj.Test ">
< constructorg-arg  value="jhon"/ >
< constructorg-arg  ref=" stoneAxe "/ >
</bean>


3. util命名空间

1.constant

用于获取指定类的静态Field值,它是FieldRetrievingFactoryBean的简化配置,如:

<util:constant  id="person.age"  static-field="AGE" />


2.property-path

用于获取指定对象的getter方法的返回值,它是PropertyPathFactoryBean的简化,如:

<util:property-path  id="testId"  path ="person.name" />


list

用于定义一个List集合,支持
<value.../>、<ref.../>、<bean.../>
等子元素,如:

< util:list  id="schools"  list-class="java.util.LinkedList ">
< value>小学</value>
< value>中学</value>
< value>大学</value>
</ util:list >


4.set

用于定义一个Set集合,支持
<value.../>、<ref.../>、<bean.../>
等元素,如:

< util:set  id="axes"  set-class="java.util.HashSet ">
< value>字符串值</value>
<bean  class=" com.test.SteelAxe "/>
< ref  bean="stoneAxe"/>
</ util:set >


5.map

用于定义一个Set集合,支持
<entry.../>
元素定义key-value对,如:

< util:map  id="sores"  map-class="java.util.TreeMap ">
< entry  key="数学"  value="88"/>
< entry  key="美术"  value="80"/>
</ util:map >


6.properties

用于加载一份资源文件,并创建一个Properties实例

< util:properties  id="test"  location ="classpath:myProperties.properties "/>


4.Spring的其他简化配置的schema

spring-aop-4.0.xsd :用于简化springAOP配置

spring-jee-4.0.xsd :用于简化JavaEE配置

spring-jms-4.0.xsd :用于简化JMS配置

spring-lang-4.0.xsd :用于简化spring动态语言 配置

.spring-tx-4.0.xsd :用于简化spring事务 配置

spring的两种后处理器

Bean后处理器:对容器中的Bean进行后处理,进行额外的加强

容器后处理器:对IOC容器进行后处理,用于增强容器的功能

后处理器英文Post Processor

1. Bean后处理器

定义

实现BeanPostProcessor接口的Bean就是Bean后处理器,它可对容器中的某一批Bean进行增强处理

BeanPostProcessor接口有如下两个方法:

下同的bean是要处理的Bean实例,name是该Bean配置的id

1)Object postProcessBeforeInitialization(Object bean, String name) throws Exception

在注入依赖之后初始化Bean之前调用

2) Object postProcessAfterInitialization(Object bean, String name) throws Exception

如果指定了init-method属性,则在它指定的方法之后执行

两个常见的Bean后处理器

1)BeanNameAutoProxyCreator:根据实例Bean的name属性创建Bean实例的代理

2)DefaultAdvisorAutoProxyCreator:根据提供的Advisor对容器中的所有Bean他建代理

Bean后处理器会对容器中的所有Bean进行后处理(在方法里可过滤掉某些不需要处理的Bean),所以在配置Bean后处理器可以不用指定id。如果用BeanFactroy作为Spring容器,则程序必须先获取Bean后处理器实例,然后手动注册,详情参见P617

Bean后处理器与其他初始化方法的执行顺序

注入完成

Bean后处理器的postProcessBeforeInitialization方法

InitializingBean接口的afterPropertiesSet方法

init-method属性指定的方法

Bean后处理器的postProcessAfterInitialization方法

2. 容器后处理器

定义

实现BeanFactoryPostProcessor接口的类就是容器后处理器,它负处理容器本身

BeanFactoryPostProcessor接口的方法

void postProcessBeanFactory(ConfigurableListableBeanFactory bean) throws BeansException;

常用的几个容器后处理器

1)PropertyPlaceholderConfigurer:属性占位符配置器

2)PropertyOverrideConfigurer:重写占位符配置器

3)CustomAutowireConfigurer:自定义自动装配的配置器

4)CustomScopeConfigurer:自定义作用域的配置器

和Bean后处理器一样,容器后处理器配置在Spring容器中时,如果以ApplicationContext作为Spring容器,则容器会自动检测到容器后处理器,所以不需要配置id,但如果使用BeanFactory作为Spring容器,则必须手动注册

如果配置了多个容器后处理器,则可要求容器后处理器必须实现Ordered接口,然后指定order属性

3.容器后处理器之属性占位符配置器

PropertyPlaceholderConfigurer这个属性占位符配置器可读取Properties文件里的键值对,先加载properties文件,再用EL表达式取值,如:

Properties文件代码:

username=”Peter”

password=”123456”

beans.xml文件配置代码:

<bean  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property  name="locations"  >
<list>
<!-- 如果有多个配置文件,可依次罗列出来 -->
<value>myPropertyFile.properties</value>
</list>
</property>
</bean>
<bean id="user"  class="com.dfsj.User">
<property  name="name" > ${username} </property>
<property  name="password" > ${password} </property>
</bean>


4.基于XML Schema的简化配置

<context:property-placeholder  location="classpath:myPropertyFile.properties"/>


4.容器后处理器之重写占位符配置器

PropertyOverrideConfigurer这个重写占位符配置器,较属性占位符配置器多了一个功能,那就是Properties文件里的键值对的值可覆盖spring的xml配置文件里的值,前提需要Properties文件里的键值对满足以下格式:

容器中配置的Bean的id.该Bean的属性 = 值

示例

//1.Properties文件代码:
user.username="peter"
user.password="123456"

//2.对应beans.xml代码:
<bean  class=" org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property  name="locations"  >
<list>
<!-- 如果有多个配置文件,可依次罗列出来 -->
<value>myPropertyFile.properties</value>
</list>
</property>
</bean>
<!-- 下面Bean里的属性注入的值会被覆盖 -->
<bean id="user"  class="com.dfsj.User">
<property  name="name" > 张三 </property>
<property  name="password" > 654321 </property>
</bean>


3.基于XML Schema的简化配置

<context:property-override  location="classpath:myPropertyFile.properties"/>


Spring 注解之零配置

1.指定SpringBean的注解

当不用xml配置文件将Java类配置成Spring容器的Spring Bean时,我们就需要以下几个注解来指定:

@Component :标注Java类为普通Spring Bean

@Controller :标注Java类为控制器组件

@Service :标注Java类为业务逻辑组件

@Repository :标注Java类为DAO组件

为指定的Spring Bean定义名字(相当于之前配置文件里的id值)

默认spring bean的名字是对应Java类的类名小写首字母

自定义名字,如: @Component(“myName”)

2.搜索Spring Bean

当不用xml配置时,指定成Spring Bean的Java类还需要扫描搜索才能找到,这就需要在xml配置文件中指定扫描的包路径,此时需要导入context:命名空间:

xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0-xsd"
<!-- 扫描下面包路径,找到所有springBean-->
<context:component-scan base-package="包路径" />


这样在创建Spring容器时,spring容器会扫描搜索上面路径下的所有被标注成Springbean的Java类,然后创建对应的实例放在Spring容器中。


2. 通过为
< component-scan.../>
元素添加
<include-filter.../>或<exclude-filter.../>
元素来指定Spring Bean类,即使该Java类没有使用Annotation

满足
<include-filter.../>
规则的Java类会被当成Spring Bean

满足
< exclude-filter.../>
规则的Java类不会被当成Spring Bean

上面两元素都要求指定如下两属性:

type:指定过滤器类型,有4种类型:

annotation:此时表达式需要指定一个Annotation类完整名

assignable:此时表达式需要指定一个Java类

regex:此时表达式需要指定.一个正则表达式

aspectj:此时表达式需要指定一个AspectJ过滤器,如:org.example..*Service+

expression:指定过滤器需要的表达式

示例

<!-- 启动包扫描功能,使带有@Controller、@Service、@Repository、@Component等注解的类成为Spring容器的Bean -->
<context:component-scan base-package="com.User" >
<context:include-filter type="regex" expression=".*Dao"/>
<context:include-filter type="regex" expression=".*Service"/>
</context:component-scan>


3.配置依赖的@Resource注解

@Resource注解直接来源于JavaEE规范,其作用类似
<property.../>
元素的ref

@Resource注解既能修饰setter方法,也能修饰Field。若不指定name值,则默认以变量名为name值

如果@Resource修饰的是接口Field,在没有指定name时按byType方式注入,如果该接口有多个实现类时,则spring容器会因为不知具体去找哪个类而报错。所以,如果只有其中一个实现类被指定为Spring Bean时不指定名字则不会报错。

4.指定Bean作用域的@Scope注解

Spring Bean的默认作用域是singleton

定义Spring Bean作用域,如:

@Scope("prototype")
@Component("user")
public  class  User { ...}


自定义作用域解析器(不再基于Annotation的方法来指定作用域)

自定义解析器类必须实现ScopeMetadataResolver接口,还要配置在
< component-scan.../>
元素中,如:

<context:component-scan base-package="包路径"  scope-resolver="自定义解析器类"/>


5 定制SpringBean生命周期行为的注解

@PostConstruct、@PreDestroy都直接来源于JavaEE规范,都用于修饰方法

@PostConstruct修饰的方法在完成注入之后回调,如果被它修饰的类实现了InitializingBean接口,则@PostConstruct修饰的方法在afterPropertiesSet方法之前执行

@PreDestroy 修饰的方法在Bean销毁前回调执行

6 自动装配和精装配的注解

@AutoWired注解用于自动装配,可修饰setter方法、普通方法、Field、构造器等

@AutoWired注解是通过byType方式装配注入的

如果@AutoWired要装配的是数组或集合类型对象时,spring会搜索容器中所有该类型的实例注入到其中,且集合类型时必须指明泛型。

如果@AutoWired要装配的是接口,且该接口在spring容器中有多个实例,则此时根据@AutoWired 的byType方式装配就会抛异常了,因为spring不知道具体要装配哪个,这时我们可以通过@Qualifier注解来精确装配,如:

@Autowired
@Qualifier("test")
private  TestInter  test;


7 Spring的其他注解

@DependsOn :修饰Bean类或方法,用于在初始化其修饰的Bean前强制初始化其他Bean

@DependsOn({“chinese”,”japanese”}) //在初化Person类前初化chinese、japanese

@ DependsOn(“chinese”) //只强制初始化一个Bean

@Lazy :是否要在创建Spring容器时预初始化该Bean,默认false

@Lazy(true) :表示要延迟初始化该Bean,即不预初始化。

Spring的AOP

为什么需要AOP?

面向对象编程(OOP)里,如果有共用的代码我们一般的做法是提取出一个公共方法供大家调用,这种方式并没有完全解耦,比如说有一个方法之前调用过公共代码,现需求变成该方法不需要调用公共代码了,此时我们还得去该方法里删除公共代码块。

而面向切面编程(AOP)不止能提取出公共代码,而且还能控制哪些方法调用该公共代码,其他方法根本不知道发生了什么变化,这就实现了完全的解耦。所有AOP很有用。

比如事务管理、安全检查、缓存、对象池管理等等都是很好的AOP思想。

spring的AOP也需要jar包:aspectjweaver.jar和aspectjtr.jar

在Spring的AOP中,连接点(切入点)总是方法的调用

1 基于注解管理的AOP

1.1 使用步骤

1. 启动@AspectJ支持

在spring配置文件中加入下面配置:

<aop:aspectj-autoproxy />
//也可用以下方式启动:
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
//AnnotationAwareAspectJAutoProxyCreator是一个Bean后处理器,为spring容器中的bean生成AOP代理


2.定义切面Bean

定义切面Bean用@Aspect注解,如:

@Aspect
public class LogAspect{....}


定义好的切面Bean也需要扫描成Spring Bean,有如下两种方式:

1):在切面Bean里加入@Component注解

2):用include-filter元素:

<context:component-scan base-package="com.*" >
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>


3.定义一个要被增强处理的类

@Component
public class User {
public void say(){
System.out.println("被增强处理的方法");
}
}


4.指定切入点和增强处理方法

@Aspect
@Component
public class BeforeAop {
//访问修饰符public 可省略
@Before("execution(public void com.User.User.say())")
public void before(){
System.out.println("在之前切入点之前的增强处理");
}
}


execution方法是用来指定切入点的,这和AspectJ的语法一样。

由于通常的增强处理是对一批方法的处理,所以需要通匹配符*,如下:

@Before("execution(* *.*(..))")


根据Before Aop里的示例可知,第一个
*
表示返回值为任意类型,第二个
*
表示所有类,第三个
*
表示所有方法,括号里的..表示任意参数

如果是某个包及其子包的所有类的所有方法都要匹配,则应如下:

@Before("execution(* com.aops..*.*(..))")


..代表零个或多个

1.2 简单示例

//1.配置文件代码:
<?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" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <!-- Aspectj支持 -->
<aop:aspectj-autoproxy />
<!-- 启动包扫描功能-->
<context:component-scan base-package="com.*" >
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect" />
</context:component-scan>
</beans>
//2. 定义增强处理的切面类和切入点
@Aspect
@Component
public class BeforeAop {
@Before("execution(public void com.User.User.say())")
public void before(){
System.out.println("在切入点之前的增强处理");
}
}
//3. 定义一个要被增强处理的类
@Component public class User { public void say(){ System.out.println("被增强处理的方法"); } }
//4.测试:
public class Test {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
User t = (User) app.getBean("user");
t.say();
}

}


执行结果:

在切入点之前的增强处理

被增强处理的方法

1.3 定义After增强处理

1. 示例

@After("execution(* *.*(..))")
public void after(){
System.out.println("在切入点之后处理");
}


2.After增强处理与AfterReturning 增强处理的区别:

After增强处理不论目标方法是否正常结束,都会调用处理

AfterReturning 只在目标方法成功完成后才处理调用

1.4 定义AfterReturning 增强处理

1. AfterReturning增强处理是在目标方法返回值后进行增强处理,比After晚招牌处理。它用@AfterReturning注解标注,该注解有两常用属性:

pointcut/value:这两属性作用一样,用于指定切入点的表达式

returning:指定一个返回值形参名,该增强处理定义的方法可通过该形参名来访问目标方法的返回值

还有一属性argNames:参数列表参数名

2. 示例:

@AfterReturning(pointcut="execution(* *.*(..))",returning="objss")
public void returnMethod(Object objss){
System.out.println(objss);
}


1.5 定义AfterThrowing增强处理

类似于AfterReturning增强处理,例:

@AfterThrowing(throwing="ex", pointcut="execution(* *.*(..))")
public void doRecoverActions(Throwable ex) {
System.out.println("目标方法中抛出的异常:" + ex);
System.out.println("模拟抛出异常后的增强处理...");
}


1.6 定义Around增强处理

Around 增强处理近似等于 Before 增强处理和 AfterReturning 增强处理的总和。它既可在执行目标方法之前织入增强操作,也可以之后织入。它既可改变执行目标方法的参数值,也可改变目标方法之后的返回值。甚至能控制目标方法什么时候执行。如:

@Around("execution(* com.aops.User.getHeight(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("---around开始-------");
Object[] arg = joinPoint.getArgs();//获得要传给目标方法的所有参数
argArray[0] = "改变第一个参数的值";//改变传入目标方法的参数
Object o = joinPoint.proceed(arg);//调用目标方法,并得到返回值
System.out.println(obj);//打印返回值
System.out.println(argArray.toString());//打印参数
System.out.println("---around结束-------");
return o+"调用目标方法得到的结果";//改变调用目标方法的返回值
}


ProceedingJoinPoint是JointPoint的子类,其他增强处理的方法里如要想获得传入参数就得通过JointPoint的getArgs方法。

注:只有Around增强处理能改变目标方法参数。

1.7 相同增强处理执行顺序

1、如果是同一个切面类里有两个相同的增强处理在同一个连接点被织入时,Spring Aop将随机织入这两个增强处理。

2、 如果是两个切面类里有相同的增强处理在同一个连接点被织入时,具有高优先级的增强处理将先被织入。

3、指定优先级的两个方法:

1)让切面类实现org.springframework.core.Ordered接口,然后实现int getOrder()方法,该方法的返回值越小,优先级越高

2)用@Order注解修饰切面类,此时可指定一个int型的value,值越小优先级越高

1.8定义切入点

AspectdJ和Spring都允许定义切入点,即为一个切入点表达式起一个名字,从而允许在多个增强处理中能重复调用。

1、定义:用@Pointcut注解修饰一个返回类型为void的空方法,方法名即为切入点名字。

@Pointcut("execution(* *.*(..))")
public void myPointcut(){
}


如果希望该切入点只能在本切面类使用,则需将public改为private

2、引用:

1) 在同一个切面类里可直接引用,如:

@After(value="myPointcut()")
public void after(){ System.out.println("after......"); }


2) 如果是引用不同切面类里的切入点,则需要加上其他切面类的类名,如:

@After(value="OtherAdvice.myPointcut()")
public void after(){
System.out.println("after......");
}


1.9 切入点指示符

1. execution:匹配执行方法的连接点,格式如下:

execution(访问修饰符 目标方法返回值类型 目标所属类.目标方法名(形参列表)目标抛出异常)

execution(public * * (..)) //匹配任意public方法

execution(* set*(..)) //匹配任何方法名以set开始的方法

execution(* com.aop.User.*(..)) //匹配User类的所有方法

execution(* com..(..)) //匹配一个包中任意类的任意方法

2. within:限定匹配特定类型的连接点

within(com.aop.*) //匹配aop包中的任意方法

within(com.aop..*) //匹配aop包及其子包的任意方法

3. this:匹配AOP代理

this(com.aop.UserInter) //匹配AOP实现UserInter接口,注意是AOP,不太理解

4.target:匹配目标对象必须是指定类型

target(com.aop.User)

5. args:对连接点(目标方法)的参数类型进行限制

args(java.lang.String) //只匹配传入参数是String类型,且只传一个参数的所有目标方法

这与execution(* *(java.lang.String))不同,execution里表示只匹配只包含一个String类型形参的方法

6.bean:只匹配指定Bean实例的目标方法

bean(*Service) // 匹配名字以Service结尾的bean实例

其中名字是Bean的id或name

1.10 切入点组合表达

&&:同时匹配

||:只需要满足一个切入点表达式即可

!:匹配不是该切入点表达式的其他连接点

示例:

@Aspect
@Component
public class BeforeAop {
@Before("execution(!public void com.User.User.*())")
public void before(){
System.out.println("在切入点之前的增强处理");
}
}


只要不是User类的目标方法都能被匹配

2基于xml配置的AOP

不推荐使用XML配置方式,推荐使用@Aspect

2.1 注意

1、基于注解的AOP配置能被Spring AOP和AspectJ同时支持

2、使用
<aop:config…/>
元素可能与Spring的自动代理方式冲突,因此,要么全部使用
<aop:config…/>
配置方式,要么全部使用自动代理方式,不能二者混用

3、XML配置方式仅支持”singleton”的切面Bean,不能在xml中组合多个命名连接点的声明

4、XML配置方式时,所有关于AOP的信息都必须配在
<aop:config…/>
元素中

5、如果
<aop:config…/>
元素里同时有
<aop:pointcut…/>、<aop:advisor…/>、<aop:aspect…/>
元素时,必须是pointcut、advisor、aspect这样的出现顺序。

6、如果是要增强处理一个有返回值的目标方法,则对应切面类的增强方法也必须写上返回值,否则系统一直处于等待状态中。

7、XML方式的组合运算符:and(相当于&&)、or(相当于||)、not(相当于!)

8、遗留问题:
<aop:advisor…/>
是什么?跟spring自动代理有什么关系?什么是自动代理?

2.2 示例与说明

1、切面类:

public class AspectAdvice {
public void after(){
System.out.println("调用目标方法结束后回调用,无论成与否");
}
public void before(){
System.out.println("before......");
}
public Object afterReturning(Object obj){
System.out.println("成功返回后回调"+obj);
return obj;
}
public Object around(ProceedingJoinPoint jp) throws Throwable{
System.out.println("调用目标方法前执行增强处理...");
Object[] arg =jp.getArgs(); //得到目标方法的形参列表
Object obj = jp.proceed(arg); // 调用目标方法
System.out.println("调用目标方法这后执行的增强处理...");
return obj;
}
}

2、配置文件:
<!-- 注入切面类 -->
<bean id="advice" class="com.aops.AspectAdvice" />
<aop:config>
<!-- 配置切入点,该配置一定要出现在aop:aspect前面 -->
<aop:pointcut id="myPointcut" expression="execution(* com.aops.User.getHeight(..))"/>
<!-- order属性指定优先级,值越小,优先级越高 -->
<aop:aspect id="aspect" ref="advice" order="1">
<!-- method属性指定调用切面类的哪个增强方法 -->
<aop:after method="after"  pointcut="execution(* com.aops.User.*(..))"/>
<!-- pointcut属性指定切入表达式 -->
<aop:before method="before" pointcut="execution(* com.aops.User.*(..))"/>
<!-- returning指定接收返回参数的参数名 -->
<aop:after-returning  returning="obj" pointcut-ref="myPointcut" method="afterReturning"/>
<!-- pointcut-ref属性指定配置的切入表达式id -->
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>


注:当
<aop:pointcut…/>
元素是
<aop:aspect >
的子元素时,说明该切入点只能被当前切面类使用

Spring的事务

对于不同的持久层访问技术,编程式事务提供了一致的事务编程风格,通过模板化操作一致地管理事务。

声明式事务是基于AOP实现的

传统的事务编程与具体的事务操作代码耦合,如果切换事务策略时,必须手动更改代码,而使用Spring管理策略时则就会

Spring的事务机制是一种典型的策略模式,它本身没有任何事务支持,只是负责包装底层的事务

1. Spring支持的事务策略

spring各种全局事务、局部事务示例配置,参见P683-P685

1.1 全局事务

全局事务由应用的服务器管理,需要底层服务器支持JTA(Java Transaction API)

全局事务可以跨多个事务性资源(典型的例子是关系数据库和消息对列)

不论采用哪种持久层访问技术,只要使用JTA全局事务,Spring事务管理的配置就完全一样,都采用全局事务管理策略。

1.2 局部事务

局部事务与底层采用的持久化技术有关,当采用了JDBC持久化时,需要用Connection对象来操作事务,当采用了Hibernate持久化时,需要用Session对象来操作事务。

由于局部事务事务不需要应用服务器参与事务管理,所以不能保证跨多个事务资源的事务的正确性,但实际情况是,大部分应用都是使用单一的事务性资源

1.3 PlatformTransactionManager

Spring事务策略是通过PlatformTransactionManager接口实现的,它是核心。当底层采用不同的持久化持术时,系统只需要使用该接口的不同实现类即可。

PlatformTransactionManager接口包含一个getTransaction(TransactionDefinition define)方法,该方法返回一个TransactionStatus对象,该对象就表示一个事务,它可简单的控制和查询事务。该事务可能是一个新的事务,也可能是已经存在的事务,如果当前执行线程已经处理事务管理下,则返回当前线程的事务,否则新建一个事务对象返回。它有如下方法:

isNewTransaction():判断是否是一个新事务

setRollbackOnly():设置回滚

isRollbackOnly():判断是否有回滚标志

TransactionDefinition 接口用于定义事务规则,如隔离级别、超时、只读状态等等….

2 Spring的两种事务管理方式

2.1 编程式配置事务

1. 编程式通过写代码的方式得到PlatformTransactionManager实例,然后设置开始事务、提交事务和回滚事务。

2.2 声明式配置事务

1. 声明式配置不写任何Java代码,只需在XML文件中通过事务代理(AOP代理的一种)来配置。具体实现原理是,在目标方法执行前织入开始事务,在目标方法执行之后织入结束事务。推荐使用声明式配置事务

2. spring用tx:命名空间的
<tx:advice…/>
元素来配置事务的增强处理,然后用
<aop:advisor…/>
元素启用自动代理

3.注意:

spring支持接口代理,也支持对具体的类生成代理。

如果一个具体的实现类如UserDaoImpl没有实现接口,按如下配置没有问题;但是,如果UserDaoImpl类实现了接口,则下面的配置将会报错,要解决这个问题,需要在配置文件中设置proxy-target-class属性的值为true,如下:

<aop:aspectj-autoproxy proxy-target-class="true"/>


这是因为,Spring默认采用JDK动态代理,而CGLIB代理是面向接口代理的,二者区别需查阅相关资料。

2.3 示例:

对应配置文件:

<?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:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/context       http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"> <!-- 扫描springbean -->
<context:component-scan base-package="com.transaction" />

<!-- 定义数据源Bean,使用C3P0数据源,并配置相关信息 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" p:driverClass="com.mysql.jdbc.Driver"
p:jdbcUrl="jdbc:mysql://localhost:3306/db1"
p:user="root"
p:password="root"
p:maxPoolSize="40"
p:minPoolSize="2"
p:initialPoolSize="2"
p:maxIdleTime="30"/>

<!-- 配置JDBC数据源的局部事务管理器:使用DataSourceTransactionManager类
该类实现了PlatformTransactionManager接口,是针对采用数据源连接的特定实现
所以,也需要注入DataSource的引用  -->
<bean id="transactionManagerId"    class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/>

<!-- 配置事务增强处理,指定事务管理器,transaction-manager属性的默认值是:transactionManager -->
<tx:advice id="txAdvice" transaction-manager="transactionManagerId">
<!-- 配置详细的事务 -->
<tx:attributes>
<!-- 所有以get开头的方法只能读 -->
<tx:method name="get*" read-only="true" />
<!-- 其他方法设置默认隔离级别,超时为5秒 -->
<tx:method name="*" isolation="READ_COMMITTED"
propagation="REQUIRED" timeout="5" />
<!-- propagation属性用于指定事务传行为,它的值是枚举值,具体每个值对应的行为是什么,请参考P687或百度 。
isolation指定事务隔离级别
rollback-for指定触发事务回滚的异常类(须是全限定类名),多个异常类时用逗号隔开
no-rollback-for 指定不触发事务回滚的异常类-->
</tx:attributes>
</tx:advice>

<!-- 如果UserDaoImpl实现了接口,则必须加入以下代码强制实现CGLIB动态代理,
cglib可以在运行期扩展Java类与实现Java接口。
cglib封装了asm,可以在运行期动态生成新的class
(默认是JDK动态代理),详情可百度AOP的两种代理方式 -->
<!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->

<!-- 配置AOP元素 -->
<aop:config>
<!-- 配置切入点:即AOP适用的范围 -->
<aop:pointcut id="point" expression="execution(* com.transaction.UserDaoImpl.*(..))"/>
<!-- 在切入点 应用txAdvice增强处理-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
</aop:config>

</beans>


对应Java逻辑代码:

@Repository("userDao")
public class UserDaoImpl{
@Resource(name="dataSource")
private DataSource dataSource;

//插入操作
public void insertData(){
JdbcTemplate jt = new JdbcTemplate(dataSource);
jt.update("insert into workers_info values(id,workername) values(1,你好)");
}
//读取操作
public void getData(){
JdbcTemplate jt = new JdbcTemplate(dataSource);
jt.execute("select * from workers_info");
//该方法在事务配置里设置为 只读,执行下面的非读操作会报错
//jt.update("insert into workers_info values(id,workername) values(1,你好)");
}
}


spring还可以为不同的方法指定不同的事务策略,具体参见P691

spring还允许将事务放在Java类中定义(@Transaction注解),具体参见P692

POJO:简单的Java对象即JavaBean

EJB:服务器端组件模型

本人将知识都生成了图片,地址:http://img.blog.csdn.net/20160930173240547
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring