本文共 26756 字,大约阅读时间需要 89 分钟。
Spring框架学习总结
——田超凡
1. 企业级应用开发
企业级应用是指那些为商业组织、大型企业创建和部署的的解决方案及应用。由于大型企业级应用结构复杂、涉及的外部资源众多、事务密集、数据规模庞大、用户数量多。因此有较强的安全性考虑和较高的性能要求。当代的企业级应用绝不可能是一个个独立的系统。在企业中,一般会部署多个进行交互的应用,同时这些应用又都有可能与其他企业的相关应用连接,从而构成一个结构复杂的、跨越Internet的分布式企业应用集群。
作为企业级应用,不仅要有强大的功能,还要能够满足未来业务需求的变化,易于扩展和维护。
2. Spring框架简介
传统Java EE解决企业级应用问题的“重量级”架构体系,使它的开发效率、开发难度和实际的性能都令人失望。正在这时,Spring框架以一个救世主的形象出现。Spring的作者Rod Johnson对传统的JavaEE技术日益臃肿和低效提出了质疑,他觉得应该有更便捷的做法。于是提出了Interface 21,这就是Spring框架的雏形。提出了技术以实用性为准的主张,引发了人们对传统Java EE技术的思考。
Spring框架致力于Java EE企业级应用的各种解决方案,而不是仅仅专注于某一层的解决方案。Spring框架是企业应用开发的“一站式选择”,Spring贯穿整个应用的表现层UI、业务逻辑层BIZ和持久层DAO。Spring框架在应用中是以一个支持者或者说赞美者的身份存在的,他不想取代那些已有的框架,而是以高度的开放性与其他框架无缝整合。
Spring框架确实给人一种格外清新的感觉,犹如春天的到来(也可以理解为微雨后的绿草丛),讨人喜欢,蕴藏勃勃生机。
Spring是一个轻量级、低侵入式(使用者可以不用完全依赖Spring框架自身提供的API类和接口)的框架,简化了Java EE企业级应用的开发,提供了强大、稳定的功能,又没有带来额外的负担。Spring是一个全面的解决方案,但是有一个原则“不重新发明轮子”,对于已经在某个领域有较好的解决方案(如持久层的MyBatis、Hibernate框架,表示层的Struts2、Spring MVC框架),Spring绝对不做重复性的实现,Spring仅是对这些不同领域较好解决方案提供支持,使之更易用,而不是重新做一个实现。
注意:
Spring框架的两个主要目标:
①使现有的Java EE技术更易用
②促进良好的编程习惯(最佳实践)
3. Spring框架组成部分
Spring框架主要组成模块,分别是:
Core Container:最基础最核心的部分,提供了IoC特性(控制反转),该部分主要由三大核心组成:
Beans 组件/Context运行时环境支持/Core核心工具
SpringContext提供了遍历和集成的工具,维护开发环境。
Data Access(Integration):Spring提供的对数据持久化框架的支持,包括事务处理等。
Spring Web:为Spring在Web应用程序的开发提供支持。
Spring AOP:Spring提供的基于Spring Core的面向切面编程的实现。
4. Spring IoC
Spring Io的意思是控制反转,也称为依赖注入(DI),是面向对象编程的一种设计理念,也是面向对象编程发展到一定程度的产物,用来降低程序代码的耦合度。
依赖:一般是指在代码中通过定义局部变量、方法参数、返回值等建立的对于其他对象的调用关系。例如在A类的方法中实例化了B类对象并通过B类对象调用B类方法完成特定功能,我们就说A类依赖于B类。
几乎所有的类都是由两个或更多的类通过彼此合作来实现完整的功能。类与类之间的依赖关系增加了程序的开发复杂程度,我们在开发一个类的时候,还要考虑对正在使用该类的其他类的影响。
注意:
对于一个类依赖某个接口实现类的情况下,如果替换了接口的实现类,将会导致该类代码的改动,不利于程序的扩展和维护。
以上问题的解决方案有两种:
1. 通过工厂方法模式建立一个工厂,该工厂类主要负责根据不同业务需求创建同一个接口不同的实现类。这样在依赖某个接口实现类的类中,直接使用工厂方法获取接口的实现类,如果需求变动需要替换掉原有的接口实现类,只需要修改工厂类中的工厂方法即可。
注意:这种方式也有弊端,比如定义了多个接口,那么就需要定义多个工厂类,大量的工厂类引入到项目中,明显增加开发工作量。
2. 使用Spring IoC控制反转(DI依赖注入)实现,只需要专注业务类和持久类的设计和代码编写。
5. 搭建Spring框架环境(Hello Spring!)
(1).搭建Spring框架环境需要使用以下Jar包,下载后复制到项目的WEB-INF/lib目录下并进行buildPath部署到项目中。
aopalliance.jar ------Spring AOP支持
aspectjweaver-1.6.9.jar ------SpringAOP支持
commons-logging-1.2.jar ------日志支持
log4j-1.2.17.jar ------log4j日志记录
spring-aop-3.2.13.RELEASE.jar -----SpringAOP支持
spring-beans-3.2.13.RELEASE.jar -----Spring Core支持
spring-context-3.2.13.RELEASE.jar ------Spring Core支持
spring-core-3.2.13.RELEASE.jar -------Spring Core支持
spring-expression-3.2.13.RELEASE.jar -------Spring Core支持
(2) .在src目录下创建source folder类型的目录,在该目录下加入log4j.properties(输出级别最好设置成Info)log4j日志配置文件和applicationContext.xml Spring核心配置文件
(3) .创建实体类,定义属性和方法进行封装。
(4) .在Spring配置文件applicationContext.xml中加入以上文件头(完整的文件头,后续有些功能需要引入相应的命名空间,这里已经汇总好了,直接使用就可以)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
//Spring配置文件配置项
</beans>
(5) .使用bean元素和property子元素创建实例。
bean元素:声明需要Spring创建的实例
属性:
id:为该bean元素指定一个名称,全局唯一。
注意:如果需要为bean指定更多别名,可以通过name属性指定,名称之间使用逗号、分号或空格进行分隔。
class:指定该实例所属类型的完全限定名。
property元素:使用设值注入的方式给实例注入属性值。
注意:设值注入是通过调用属性的setter方法为属性赋值的,而不是直接对属性赋值。因此在实体类中要为需要注入的属性提供setter方法,否则无法完成设值注入。并且要注意setter方法名和属性名的对应关系,遵循JavaBean命名规范。
属性:
name要注入值得属性名
value要注入的属性值
例如:
<bean id="zhangGa" class="pojo.Person">
<property name="name" value="张嘎"></property>
<property name="content" value="三天不打小鬼子,手都痒痒!"></property>
</bean>
(4) .编写测试方法测试功能
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
Person zhangGa=(Person)context.getBean("zhang");
Person rold=(Person)context.getBean("r");
zhangGa.print();
rold.print();
使用到的类和接口说明:
ApplicationContext接口:负责读取Spring配置文件,管理对象的加载、生成,维护bean对象之间的依赖关系。负责bean的生命周期等。ApplicationContext接口继承BeanFactory接口(BeanFactory接口Spring IoC容器的核心)。
ClassPathXmlApplicationContext类:ApplicationContext接口的实现类,用于从classpath路径中读取Spring配置文件。
注意:
(1) .除了ClassPathXmlApplicationContext类外,ApplicationContext接口还有其他的实现类。例如
FileSystemXmlApplicationContext也可用于加载Spring配置文件,但是是在文件路径中读取Spring配置文件的。
(2) .除了ApplicationContext及其实现类,还可以通过BeanFactory接口及其实现类对Bean组件实施管理。事实上,ApplicationContext接口就是建立在BeanFactory接口的基础上
注意:BeanFactory接口才是SpringIoC容器的核心,负责管理组件和他们之间的依赖关系,应用程序通过BeanFactory接口与SpringIoC容器进行交互。ApplicationContext接口是BeanFactory接口的子接口,可以对企业级开发提供更全面的支持。
IoC控制反转(DI依赖注入)小结:
①我们发现通过使用SpringIoC容器生成组件,为组件注入属性值并管理组件之间的依赖关系。实例的属性不再由程序代码来主动创建和管理,改为被动接受SpringIoC容器的注入,组件之间以Spring配置文件的方式组合在一起,而不再是由传统硬编码的方式耦合在一起。
②相对于控制反转,依赖注入的说法也许更容易理解一些。依赖注入就是将组件依赖的对象通过Spring配置文件注入给该组件,从而避免组件之间以硬编码的方式耦合在一起。
③通过Spring框架强大的组装能力,我们在开发每个程序组件的时候,只要明确关联组件的接口定义,不需要关心接口的具体实现,接口的具体实现交由SpringIoC容器统一创建、注入和管理,类似可插拔式的插槽,灵活高效,这其实也就是所谓的“面向接口”编程。
6. Spring AOP面向切面编程
AOP指的是面向切面编程,AOP面向切面编程是软件编程思想发展到一定阶段的产物,是对面向对象编程OOP的有益补充。
AOP一般适用于具有横切逻辑的场合,如访问控制、事务管理、日志记录、性能监测等。
日志、异常处理、事务控制都是一个健壮的业务系统所必需的。但是为了保证系健壮可用,就在要众多的业务方法中反复编写类似的代码,使得原本就很复杂的业务逻辑变得更加复杂。业务功能的开发者还要关注这些“额外”的代码是否处理正确,是否有遗漏的地方,如保存数据设置手动提交事务时需要正确处理提交或回滚,如果没有显式使用commit提交事务,数据不会保存到数据库中,带来数据安全隐患,耽误业务处理的进展。如果需要修改日志信息格式或者安全验证的规则,或者增加新的辅助功能,将会导致业务代码频繁大量的改动。
横切逻辑指的是业务系统中散落、渗透到系统各处却不得不处理的事情,这些穿插在既定义务中的操作就是所谓的“横切逻辑”。也成为切面Aspect。
面向切面编程AOP,简单地说就是在不改变原程序代码的基础上,在程序运行时为代码段动态增加新的功能,对代码段进行增强处理。它的设计思想来源自代理设计模式。
在代理设计模式中可以为需要执行的对象创建一个代理对象,代理对象为要执行的目标对象的目标方法创建一个代理方法,这样当通过代理对象调用代理的方法时,就可以在执行目标方法的前后增加一些新的功能,也就是所谓的增强处理。增强的功能既可以插到原对象的目标方法执行前,也可以插到原对象的目标方法执行后。在这种模式下,带来的感觉就是在原有代码乃至原业务逻辑都不修改的情况下,直接在业务流程中切入新代码,增加新功能。这就是所谓的面向切面编程。
注意:
①面向切面编程AOP的基本概念如下:
切面(Aspect):一个模块化的横切逻辑(或称横切关注点),可能会横切多个对象。
连接点(JoinPoint):程序执行中的某个具体的执行点,如需要执行的目标方法就是一个连接点。
增强处理(Advice):切面在某个特定连接点上执行的代码逻辑。
切入点(Pointcut):对连接点的特征进行描述,可以使用正则表达式。增强处理方法一般和一个切入点表达式相关联,并在与这个切入点匹配的连接点上执行增强处理。
目标对象(Target Object):做一个或多个切面增强的对象。
AOP代理(AOP Proxy):由AOP框架创建的对象,实现执行增强处理方法等功能。
织入(Weaving):将增强处理连接到应用程序中的类型或对象上的过程。
常用AOP增强处理类型:
前置增强before/后置增强after-returning/异常抛出增强after-throwing/环绕增强around/最终增强after
②切面可以理解为由增强处理和切入点组成,既包含了横切逻辑的定义,也包含了连接点的定义。
③AOP面向切面编程关心的两个问题:在什么位置,执行什么功能。
Spring AOP是负责实施切面的框架,由Spring AOP完成织入工作。
7. Spring AOP实现日志输出
(1).导入并部署Spring AOP依赖的jar文件:
aopalliance.jar
aspectjweaver-1.6.9.jar
spring-aop-3.2.13.RELEASE.jar
(3) 编写日至切面类,定义前置增强和后置增强方法
//前置增强
public void before(JoinPoint joinPoint)
{
logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature().getName()+"方法执行,方法入参:"+Arrays.toString(joinPoint.getArgs()));
}
//后置增强
public void afterReturning(JoinPoint joinPoint,Object result)
{
logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature().getName()+"方法执行,方法返回值:"+result);
}
参数说明:
JoinPoint:连接点,指代需要执行的目标方法,Spring会自动注入该实例。
常用方法:
getTarget()获取目标对象
getSignature().getName()获取目标方法名
getArgs()获取目标方法参数数组,返回Object[]类型
注意:对于后置增强方法,还可以添加一个Object类型的参数,表示目标方法执行的返回值。
(4) .在Spring配置文件applicationContext.xml中配置切面组件,并定义切入点和织入增强处理。
<!-- 配置用户aop切面bean -->
<bean id="userLogger" class="logger.UserLogger"></bean>
<!-- 配置SpringAOP切面,织入增强 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution(* service.UserServiceImpl.addUserInfo(pojo.User))" id="pointcut"></aop:pointcut>
<aop:aspect ref="userLogger">
<!-- 前置增强 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<!-- 后置增强 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
</aop:aspect>
</aop:config>
配置元素说明:
aop:config元素:配置AOP切入点和切面的根节点,所有关于Spring AOP的配置项均可放在此元素中。
aop:pointcut元素:定义切入点表达式。
属性:
id全局唯一,表示切入点的名称
expression定义切入点表达式
execution切入点指示符,它的括号中是一个切入点表达式。可以配置需要切入增强处理的方法的特征。
注意:切入点表达式支持模糊匹配。可以使用通配符
Public * addNewUser(entity.User) *表示所有类型的返回值
Public void *(entity.User) *表示匹配所有的方法名
Public void addNewUser(..) ..表示匹配所有参数和类型
* com.service.*.*(..) 匹配com.service包下的所有类的所有方法
* com.service..*.*(..) 匹配com.service包及其子包下的所有类的所有方法
可以根据需要来设置切入点表达式的匹配规则。
aop:aspect定义切面,织入增强处理
属性ref:引用定义好的切面bean
子元素:
aop:before 前置增强
aop:after-returning后置增强
属性:
method指定进行增强处理的方法名
Pointcut-ref引用定义好的切入点表达式bean,将增强处理和切入点关联。
注意:后置增强aop:after-returning有一个特有属性returning,用来指定执行目标方法的返回值注入给增强处理方法的哪个参数。
(5) .编写测试类,实现日志输出。
8. 多种方式实现依赖注入DI
①设值注入:通过setter()方法注入属性值给某个属性。
②构造柱入:通过构造函数给属性赋值,并通过注入属性值给构造函数的参数实现构造柱入。
实现方式:
(1)定义一个实体类,定义属性和构造函数。
例如:
/**
* 人物pojo类
* @author Hasee
*
*/
public class Person {
private String name;
private String content;
//构造注入
public Person(String name,String content)
{
this.name=name;
this.content=content;
}
public Person()
{
}
//getter/setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
//自我介绍
public void print()
{
System.out.println(this.name+" 说:“"+this.content+"”");
}
}
(2)在Spring配置文件中完成bean的配置,实现构造柱入
<!-- 构造柱入说话人和说话内容 -->
<bean id="zhang" class="pojo.Person">
<constructor-arg index="0">
<value>张嘎</value>
</constructor-arg>
<constructor-arg index="1">
<value>三天不打小鬼子,手都痒痒!</value>
</constructor-arg>
</bean>
<bean id="r" class="pojo.Person">
<constructor-arg index="0">
<value>Rod</value>
</constructor-arg>
<constructor-arg index="1">
<value>世界上有10种人,认识二进制的和不认识二进制的。</value>
</constructor-arg>
</bean>
配置项说明:
constructor-arg元素:
用来指定构造函数的一个参数,默认使用时不区分顺序。当构造函数的参数有多个出现混淆,无法区分时,可以通过属性index指定该参数的索引位置,从0开始。还可以通过属性type指定参数的类型,避免字符串和基本数据类型混淆。
③p命名空间注入:使用bean元素的属性而不是子元素的形式注入bean元素的属性值。
语法:
①注入直接量(基本数据类型、字符串):
P:属性名=”属性值”
②引用其他bean
P:属性名-ref=”bean的id”
注意:
(1)一般建议在定义带参构造函数完成构造柱入的同时,定义一个无参构造函数,这样做的原因是提高灵活性,防止后期若改为设值注入或p命名空间注入时,如果定义了带参构造,并且没有提供默认无参构造,系统不再会为其分配默认无参构造,便会产生异常。
(2)构造柱入的时效性好,在对象实例化时就得到所依赖的对象,便于在对象初始化方法中使用以来对象,但受限于方法重载的形式,使用灵活性不足。设值注入使用灵活,但时效性不足,并且大量的setter方法增加了类的复杂性。Spring并不倾向于某种注入方式,可以根据实际需求选用合适的依赖注入方式。
9. 注入不同类型数据类型的属性
Spring提供了各种不同的标签实现各种不同类型的参数注入,这些标签对于设值注入和构造柱入都适用。
①注入直接量(基本数据类型/字符串)
<bean id=”” class=””>
<property name=””>
<value>属性值</value>
</property>
</bean>
或者直接通过property元素的value属性注入属性值。
②引用其他bean组件
<bean id=”” class=””>
<property name=””>
<ref bean=”bean的id”></ref>
//或者
<ref local=”bean的id”></ref>
</property>
</bean>
或者直接通过property元素的ref属性引用其他bean组件
注意:local属性只能在同一个Spring配置文件中检索bean,而使用bean属性可以在其他Spring配置文件中检索bean
③使用内部bean
<bean id=”” class=””>
<property name=””>
<bean class=””>
<property name=”” value=””></property>
....
</bean>
</property>
</bean>
不需要指定内部bean的id属性,因为内部bean仅作用于这一处,在其他bean中不能访问。
④注入集合类型的属性
(1) 数组或List集合
<bean id=”” class=””>
<property name=””>
<list>
<value>元素值</value>
......
</list>
</property>
</bean>
注意:
<list>标签中可以使用<ref>标签引用其他bean作为一个集合元素
(2) set集合
<bean id=”” class=””>
<property name=””>
<set>
<value>元素值</value>
......
</set>
</property>
</bean>
(3) Map集合
<bean id=”” class=””>
<property name=””>
<map>
<entry>
<key><value>Map元素的键</value></key>
<value>Map元素的值</value>
</entry>
......
</map>
</property>
</bean>
注意:一个entry元素表示一个map集合元素
(4) Properties类型的属性
<bean id=”” class=””>
<property name=””>
<props>
<prop key=”键”>值</prop>
......
</props>
</property>
</bean>
⑤注入null值和空字符串
注入null值<null/>
注入空字符串<value></value>
10. Spring AOP增强类型小结:
Spring AOP常用增强处理类型:
前置增强before:目标方法执行前执行
配置元素:<aop:before>
后置增强after-returning:目标方法执行后执行
配置元素:<aop:after-returning>
注:前置增强和后置增强配置方式见上文。
异常抛出增强after-throwing:目标方法抛出异常时执行
配置元素:<aop:after-throwing>
public void afterThrowing(JoinPoint joinPoint,RuntimeException e)
{
logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature().getName()+"方法执行抛出异常,异常抛出增强,抛出异常:"+e);
}
注意:参数e表示抛出的异常,Spring会自动注入目标方法抛出的异常实例给这个参数。(需要配置throwing属性)
环绕增强around:功能最强大的增强处理,Spring把对目标方法的控制权完全交给了环绕增强。可以获取或修改目标方法的参数、返回值,可以对目标方法进行异常处理,甚至可以觉得目标方法是否被执行(拦截目标方法)
配置元素:<aop:around>
public Object around(ProceedingJoinPoint joinPoint)
{
Object result=null;
try
{
//执行代理的目标方法
result=joinPoint.proceed();
logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature().getName()+"方法执行,环绕增强,返回值:"+result);
}
catch(Throwable e)
{
e.printStackTrace();
logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature().getName()+"方法执行抛出异常,环绕增强,异常信息:"+e);
}
finally
{
logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature().getName()+"方法执行完毕,环绕增强,方法返回值:"+result);
}
return result;
}
注意:ProceedingJoinPoint接口是JoinPoint接口的子接口,不但封装了目标方法及其入参数组,还封装了被代理的目标对象,通过proceed()方法执行真正的目标方法,从而达到对连接点(目标方法)的完全控制。
最终增强after:无论方法抛出异常还是正常退出,都要执行最终增强
配置元素:<aop:after>
public void after(JoinPoint joinPoint)
{
logger.info("调用"+joinPoint.getTarget()+"的"+joinPoint.getSignature().getName()+"方法执行,最终增强");
}
注意:
Spring AOP配置信息完整实例:
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut id="pointcut" expression="execution(* service.UserServiceImpl.addUserInfo(pojo.User))"></aop:pointcut>
<aop:aspect ref="addUserLogger">
<!-- 前置增强 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<!-- 后置增强 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
<!-- 异常抛出增强 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
<!-- 环绕增强 -->
<aop:around method="around" pointcut-ref="pointcut"/>
<!-- 最终增强 -->
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
<!--切面bean-->
<bean id="addUserLogger" class="logger.AddUserLogger"></bean>
11. 使用注解实现IoC
@Component声明一个bean组件名,参数为组件的id
@Repository声明DAO接口实现类
@Service声明Service接口实现类
@Controller声明控制器类
Bean组件自动装配(注入)注解:
@Autowired 按类型匹配
@Qualifier 如果有一个以上的bean类型相匹配,则使用@Qualifier注解指定所需的bean的名称,一般结合@Autowired注解使用,适用于有多个和需要注入的属性类型相匹配的bean,如果不使用@Qualifier会抛出异常,因为无法按类型自动装配多个类型匹配的bean
Java标准注解实现自动装配(注入):
@Resource按bean名称匹配,如果没有找到匹配的bean名称,再继续按类型匹配
注意:使用注解标注后,在Spring配置文件中一定要启用Spring IoC注解,否则会抛出找不到组件异常。
<context:component-scan base-package=”dao,service”/>
12. 使用注解实现AOP
Aspect J简介:AspectJ是一个面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译时提供代码的织入,所以她有一个专门的编译器来生成遵守字节编码规范的class文件
@AspectJ是AspectJ新增的功能,使用JDK5.0注解和正规的AspectJ切点表达式描述切面。
注意:在使用@AspectJ注解实现AOP时,要确保所使用的JDK是1.5以上版本,否则无法使用注解实现AOP,则需要通过Spring配置文件配置实现切入点的定义和增强处理的织入。
@Aspect标注切面类
@PointCut声明切入点
@Before前置增强
@AfterReturning后置增强
@AfterThrowing异常抛出增强
@Around环绕增强
@After最终增强
注意:
1.注解的属性和在Spring配置文件中对应增强处理标签的属性一致。
2.在使用AspectJ注解实现AOP时,一定要在Spring配置文件中配置以下配置项:
①定义切面bean,否则增强处理无法顺利完成织入。
<bean id="addUserLogger" class="logger.AddUserLogger"></bean>
②启用Spring AOP注解,否则AspectJ注解无效
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
13. Spring与MyBatis整合环境搭建
(1) .导入Spring框架、MyBatis框架依赖的Jar包、MySQL驱动Jar包、Log4j Jar包,并导入MyBatis-Spring整合依赖的Jar包,包括:
aopalliance.jar
aspectjweaver-1.6.9.jar
commons-dbcp-1.4.jar
commons-logging-1.2.jar
commons-pool-1.6.jar
log4j-1.2.17.jar
mybatis-3.2.2.jar
mybatis-spring-1.2.0.jar
mysql-connector-java-5.1.0-bin.jar
spring-aop-3.2.13.RELEASE.jar
spring-beans-3.2.13.RELEASE.jar
spring-context-3.2.13.RELEASE.jar
spring-core-3.2.13.RELEASE.jar
spring-expression-3.2.13.RELEASE.jar
spring-jdbc-3.2.13.RELEASE.jar
spring-tx-3.2.13.RELEASE.jar
(2) .创建项目基本目录
DAO映射器接口、SQL映射文件*mapper.xml、DAO接口实现类(可以省略)
Service业务接口、Service业务接口实现类
pojo持久化类
test测试类,控制台输出
resources目录:
Log4j.properties 日志配置文件
Mybatis-config.xml MyBatis核心配置文件
applicationContext.xml Spring核心配置文件
(3) .编写mybatis-config.xml MyBatis核心配置文件
<configuration>
<!-- Spring和MyBatis整合,数据源、SQL映射文件载入均交由Spring统一配置和管理 -->
<!-- 持久化类指定别名 -->
<typeAliases>
<package name="pojo"></package>
</typeAliases>
</configuration>
(4) 编写POJO持久化类,定义属性并进行getter/setter封装
例如:
public class User {
private Integer id;
private String userCode;
private String userName;
private String userPassword;
private Integer gender;
private Date birthday;
private String phone;
private String address;
private Integer userRole;
private Integer createdBy;
private Date creationDate;
private Integer modifyBy;
private Date modifyDate;
//省略getter/setter方法
}
(5)编写dao映射器接口需要执行的持久化操作方法并编写响应的SQL映射文件和SQL语句,建立持久化类和数据库表之间的ORM映射关系(详见MyBatis学习总结)。
例如:
UserMapper接口:
public interface UserMapper {
//修改用户信息
public abstract int updateUserInfo(User user);
//删除用户信息
public abstract int deleteUserInfo(@Param("id")Integer id);
//修改用户密码
public abstract int updatePassword(@Param("id")Integer id,@Param("userPassword")String userPassword);
}
UserMapper.xml映射文件:
<mapper namespace="dao.UserMapper">
<!-- 修改用户信息 -->
<update id="updateUserInfo" parameterType="Role">
UPDATE `smbms_user`
<set>
<if test="userCode!=null and userCode!=''">`userCode`=#{userCode},</if>
<if test="userName!=null and userName!=''">`userName`=#{userName},</if>
<if test="userPassword!=null and userPassword!=''">`userPassword`=#{userPassword},</if>
<if test="gender!=null and gender!=0">`gender`=#{gender},</if>
<if test="birthday!=null and birthday!=''">`birthday`=#{birthday},</if>
<if test="phone!=null and phone!=''">`phone`=#{phone},</if>
<if test="address!=null and address!=''">`address`=#{address},</if>
<if test="userRole!=null and userRole!=0">`userRole`=#{userRole},</if>
<if test="modifyBy!=null and modifyBy!=0">`modifyBy`=#{modifyBy},</if>
<if test="modifyDate!=null and modifyDate!=''">`modifyDate`=#{modifyDate},</if>
</set>
WHERE `id`=#{id}
</update>
<!-- 删除用户信息 -->
<delete id="deleteUserInfo" parameterType="java.lang.Integer">
DELETE FROM `smbms_user`
WHERE `id`=#{id}
</delete>
<!-- 修改用户密码 -->
<update id="updatePassword">
UPDATE `smbms_user`
<set>
<if test="userPassword!=null and userPassword!=''">`userPassword`=#{userPassword},</if>
</set>
WHERE `id`=#{id}
</update>
</mapper>
(6)编写Spring配置文件applicationContext.xml
①配置dbcp数据源(其他方式配置数据源见下文)
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/smbms"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
②配置MyBatis核心对象SqlSessionFactoryBean
<!-- 配置MyBatis核心对象SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 加载数据源配置 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 加载MyBatis核心配置文件配置项 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 加载SQL映射文件 -->
<property name="mapperLocations">
<list>
<value>classpath:dao/**/*.xml</value>
</list>
</property>
</bean>
③
(1).基于dao接口实现类则需要在dao接口实现类中定义SqlSessionTemplate类型的属性并定义getter/setter方法封装属性。
注意:
①SqlSessionTemplate类实现了SqlSession接口,可以替换掉MyBatis原有的SqlSession实现类提供数据库访问操作,使用SqlSessionTemplate类可以更好地与Spring服务融合并简化部分流程化的工作,可以保证和当前Spring事务相关联,自动管理会话的声明周期,包括必要的关闭、提交和回滚操作。
②使用SqlSessionTemplate,需要在Spring配置文件中定义SqlSessionTemplate组件,构造柱入SqlSessionFactory,然后将创建好的SqlSessionTemplate组件注入到dao实现类组件中。
<!-- 配置SqlSessionTemplate,构造柱入SqlSessionFactory -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg>
<ref bean="sqlSessionFactory"></ref>
</constructor-arg>
</bean>
③DAO接口实现类还可以通过继承SqlSessionDaoSupport类,调用getSqlSession()方法获取SqlSessionTemplate实例。SqlSessionDaoSupport类提供了注入sqlSessionFactory的setSqlSessionFactory()方法,在注入SqlSessionFactory的同时创建SqlSessionTemplate实例,并且SqlSessionDaoSupport类提供了getSqlSession()方法返回创建好的SqlSessionTemplate实例,因此DAO接口实现类在继承SqlSessionDaoSupport类后,无需定义SqlSesionTemplate属性即其getter/setter方法。直接通过getSqlSession()方法就可以直接获取到创建好的SqlSessionTemplate实例。这样在Spring配置文件中配置DAO接口实现类时,可以直接注入SqlSessionFactoryBean(自动调用父类SqlSessionDaoSupport类的setSqlSessionFactory()方法完成设值注入)。
(2) .基于Mapper映射器接口实现(不再需要Mapper映射器接口实现类)
①MapperFactoryBean类:继承SqlSessionDaoSupport类,使用MapperFactoryBean可以一次创建一个映射器接口实现,需要同时注入两个属性:mapperInterface指定需要创建实例的映射器接口名、引用sqlSessionFactoryBean
配置如下:
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="dao.UserMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
然后就可以将该映射器接口实现直接注入到业务层组件的映射器接口属性中。如:
<bean id="userService" class="service.UserServiceImpl">
<property name="userMapper" ref="userMapper"></property>
</bean>
②MapperScannerConfigurer类:一次扫描并注册基准包及其子包下的所有映射器接口实现为MapperFactoryBean,自动注入SqlSessionFactory。
配置如下:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="dao"></property>
</bean>
然后可以通过配置文件或Spring IoC注解的方式自动装配映射器接口实现到业务层组件中定义的映射器接口上。
@Service("userService")
public class UserServiceImpl implements UserService{
//dao层引用
@Resource(name="userMapper")
private UserMapper userMapper;
}
注意:使用MapperScannerConfigurer自动创建的映射器接口实现MapperFactoryBean的名称(bean的id)默认为映射器接口名(首字母小写,驼峰命名法)
@Resource(name="userMapper")
(6) 编写测试类和测试方法调用业务bean进行测试,如:
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-mybatis.xml");
UserService userService=(UserService)context.getBean("userService");
15.Spring声明式事务处理
业务层的只能不仅仅是调用dao这么简单,事务处理是任何企业级开发中不能回避的一个重要问题。以往通过硬编码的方式进行事务控制,事务控制代码分散在业务方法中难以重用,需要调整时工作量比较大,复杂事务的编码难度较高,增加了开发难度等。
Spring提供了声明式事务处理机制,基于Spring AOP实现,无需编写任何事务管理代码,所有的工作全在配置文件中完成。这意味着事务控制代码和业务代码彻底分离,配置即可用,降低了开发和维护的难度。
Spring配置文件中配置项:
①配置事务管理器DataSourceTransactionManager
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
②配置事务增强
<!-- 配置事务增强 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="query*" propagation="SUPPORTS"></tx:method>
<tx:method name="find*" propagation="SUPPORTS"></tx:method>
<tx:method name="get*" propagation="SUPPORTS"></tx:method>
<tx:method name="add*" propagation="REQUIRED"></tx:method>
<tx:method name="update*" propagation="REQUIRED"></tx:method>
<tx:method name="delete*" propagation="REQUIRED"></tx:method>
<!-- 默认 -->
<tx:method name="*" propagation="REQUIRED"></tx:method>
</tx:attributes>
</tx:advice>
配置参数说明:
Transaction-manager属性:引用配置好的事务管理器
Tx:attributes子元素:定制事务属性。
Tx:method:为不同方法设置不同的事务属性。
属性:
name属性:必须,用于指定匹配的方法,对方法名进行约定,可以使用通配符(*)
常用可选属性:
Propagation:事务传播机制
属性值:
REQUIRED 存在事务则提供支持,不存在则创建一个新的事务并开启事务处理
SUPPORTS 存在一个事务,则支持当前事务,否则按非事务方式处理
REQUIRES-NEW 总是开启一个新的事务,如果事务已存在,则挂起当前事务,开启新事务执行该方法。
MANDATORY 存在事务则支持当前事务,如果没有一个活动的事务则抛出异常。
NESTED 存在事务则创建一个事务作为当前事务的嵌套事务运行,如果不存在事务则作用等同于REQUIRED
NOT_SUPPORTED 总是以非事务方式运行,如果存在事务,则挂起当前事务,然后执行该方法。
NEVER 总是以非事务方式运行,如果存在一个活动的事务,则抛出异常。
ISOLATION属性:事务隔离等级
DEFAULT:同数据库事务隔离等级一致
READ_UNCOMMITED 未提交读
READ_COMMITED 提交读
REPEATABLE_READ 可重复读
SERIALIZABLE 串行读
timeout属性:事务超时
Read-only属性:是否是只读事务
Rollback-for属性:能够触发回滚的异常类型
No-rollback-for属性:不触发回滚的异常类型
③配置事务切面,织入事务增强
<!-- 配置事务切面,织入事务增强 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut id="pointcut" expression="execution(* service.*.*(..))"></aop:pointcut>
<!-- 织入事务增强,将事务增强和切入点相结合 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
16. 注解实现Spring声明式事务处理
@Transactional注解:
默认值:
事务传播设置:PROPAGATION_REQUIRED
事务隔离等级:ISOLATION_DEFAULT
事务是可读写
事务超时默认依赖于事务系统的,或者事务超时没有被支持
任何RuntimeException都将触发事务回滚,但是任何CheckedException都不会触发事务回滚。
注解属性值同配置事务增强的属性基本一致。
注意:使用Spring声明式事务注解,必须在Spring配置文件中配置事务管理器DataSourceTransactionManager并启用Spring声明式事务注解:
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启用Spring声明式事务注解 -->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
17. Spring配置数据源的方式小结
①使用dbcp数据源,直接在bean元素的property子节点中编写数据源信息
例如:
<!-- 配置dbcp数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/smbms"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
②引用外部数据源属性配置文件(database.properties)中的配置信息
使用PropertyPlaceHolderConfigurer类引入数据源配置文件,再通过${ 键}获取相应数据源配置信息
<!-- 使用PropertyPalceHolderConfigurer引入数据源配置文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"></property>
</bean>
<!-- 配置dbcp数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
③使用JNDI获取数据源:
配置JndiObjectFactoryBean组件并将web服务器(如Tomcat)中配置的JNDI名称注入到jndiName属性,注意要加上前缀(java:comp/env/)
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/smbms/test"></property>
</bean>
18. Spring配置文件Bean的作用域
在Spring中定义Bean,除了可以创建Bean实例并对Bean的属性进行注入外,还可以为定义的Bean指定一个作用域。这个作用域的取值决定了Spring创建该Bean组件实例的策略,进而影响程序的运行效率和数据安全。
在Spring2.0及以后的版本中,Bean的作用域被划分为5种:
Singleton 默认值。以单例模式创建Bean实例,即容器中该Bean实例只有一个。
Prototype 每次从容器中获取Bean实例时,都会创建一个新的Bean实例。
request用于Web应用环境,针对每次HTTP请求都会创建一个Bean实例
Session 用于Web应用环境,同一个会话共享同一个Bean实例,不同会话使用不同的Bean实例。
Global session 仅在Portlet的Web应用中使用,同一个全局会话共享同一个Bean实例,对于非Portlet环境,作用等同于session
注意:
1.对于不存在线程安全性问题的组件,采用这种方式可以大大减少创建对象的开销,提高运行效率。但是对于存在线程安全问题的组件,则不能使用singleton模式,可以使用prototype作用域。
2.可以通过bean元素的scope属性指定bean的作用域
19. Spring的自动装配
在没有显示指定所依赖的bean组件的id的情况下,通过自动装配可以将与属性类型相符的(对于@Resource注解还会尝试id和属性名相同的)Bean自动注入给该属性,从而简化配置。
使用注解实现依赖注入DI时可以使用自动装配,基于XML的配置也可以使用自动装配。
bean元素的autowire属性指定自动装配,代替了通过<property>子元素(ref属性或ref子元素)显式指定bean之间的依赖关系,这就是Spring自动装配的神奇之处。由BeanFactory自动检查XML配置文件的内容,为Bean自动注入依赖关系,大大简化了维护Bean注入的配置。
注意:
①bean元素autowire属性常用取值:
No 不使用自动装配,默认值
byName 根据属性名自动装配
byType 根据属性类型自动装配,如果有多个这样的bean,将抛出致命异常!!!
Constructor 与byType类似,不同之处在于constructor应用于构造器参数,如果在容器中没有找到与构造器参数类型一致的Bean,将抛出致命异常!!!
②可以通过在Spring配置文件中配置顶级元素(beans元素)的default-autowire属性设置全局自动装配策略,在bean元素的autowire属性仍可指定某个Bean组件的自动装配策略,取值见上文。
优先级:bean元素的autowire属性(局部自动装配策略) 优先于 beans元素的default-autowire属性(全局自动装配策略),即局部优先。
20. 拆分Spring配置文件
对于使用XML方式进行配置的Spring项目,建议将一个大的Spring配置文件拆分成多个小的Spring配置文件,每个配置文件仅仅配置功能近似的Bean组件
拆分策略:
1. 如果是按模块分工,则拆分策略为:
公用配置(数据源、事务、扫描注解等)一个配置文件+
每个功能模块(包括每个模块的dap/service/web控制器等)一个配置文件
2. 如果是按分层分工,则拆分策略为:
公用配置(数据源、事务、扫描注解等)一个配置文件+
DAO层一个配置文件+
Service层一个配置文件+
Web控制器层一个配置文件
注意:
拆分Spring配置文件按,不仅可以分散配置文件,降低修改配置文件的难度和冲突的风险,而且更符合“分而治之”的软件工程原理。
拆分方法:
加载多个Spring配置文件的方式:
①直接传入多个字符串格式的配置文件名到ClassPathXmlApplicationContext类的构造函数中
②定义一个字符串数组,存放多个配置文件名,将字符串数组传入到ClassPathXmlApplicationContext类的构造函数中
③在调用ClassPathXmlApplicationConext类的构造函数时,参数可以使用通配符,加载多个具有一定命名规则的配置文件
④在Spring主配置文件中通过import元素和import元素的resource属性引入其他Spring配置文件,在调用ClassPathXmlApplicationContext类的构造函数时,直接传入Spring主配置文件名即可同时加载在该Spring主配置文件中通过import元素引入的其他Spring配置文件。
例如:
<!-- 加载拆分的Spring配置文件 -->
<import resource="applicationContext-Bill.xml"></import>
<import resource="applicationContext-User.xml"></import>
<import resource="applicationContext-Role.xml"></import>
注意:转载请注明原作者。
编写日期:2018年5月22日
转载地址:https://supertian.blog.csdn.net/article/details/80412984 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!