一、Spring介绍 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
轻量级:
控制反转:对象的控制权反转为Spring容器控制;
面向切面:
容器框架:Spring就是一个容器,一个管理bean的工厂,org.springframework.context.ApplicationContext
接口用于完成容器的配置,初始化,管理bean。一个Spring容器就是某个实现了ApplicationContext接口的类的实例。也就是说,从代码层面,Spring容器其实就是一个ApplicationContext。
二、Spring简单入门 1. 导入Spring的核心jar包
核心jar包
spring-core-3.2.2.RELEASE.jar 包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心。
spring-beans-3.2.2.RELEASE.jar 所有应用都要用到的,它包含访问配置文件、创建和管理bean,以及进行Inversion of Control(IoC) / DependencyInjection(DI)操作相关的所有类
spring-context-3.2.2.RELEASE.jar Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等。
spring-expression-3.2.2.RELEASE.jar Spring表达式语言
com.springsource.org.apache.commons.logging-1.1.1.jar 第三方的主要用于处理日志
2. 在使用spring之前 创建xxxService
,并由xxxService
调用相应的业务方法完成工作,而且每次创建一个XXXService
都是一个新的对象 。
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void test01 () { UserService userService1 = new UserServiceImpl(); userService1.save(); UserServiceImpl userService2 = new UserServiceImpl(); userService2.save(); System.out.println(userService1.hashCode()); System.out.println(userService2.hashCode()); }
3. Spring配置文件beans.xml
在src
目录下创建配置未见beans.xml
,配置文件的约束在Spring文档的文件内找到:
beans.xml
1 2 3 4 5 6 7 8 9 <?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.xsd" > <bean id ="userService" class ="cn.zhuobo.spring.service.serviceImpl.UserServiceImpl" /> </beans >
4. 获取对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void test02 () { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserService userService1 = (UserService) context.getBean("userService" ); userService1.save(); UserService userService2 = (UserService) context.getBean("userService" ); userService2.save(); System.out.println(userService1.hashCode()); System.out.println(userService2.hashCode()); }
三、控制反转和依赖注入 1. IoC(Inversion of Control) 控制反转不是一种技术,而是一种设计思想,意味着对象的控制权被交给IoC容器,而不是传统的直接在对象内部控制。传统上在对象内部直接new另一个对象,并由程序主动地创建依赖对象,维护对象间的依赖关系(比如Customer对象有一个依赖对象Order,有应用程序类创建这两个对象,并主动将Order注入(set)到Customer)。在IoC中,所有的对象由IoC容器控制,在系统运行到适当的时候,将对象交给需要的另一个对象。所有的对象都由IoC容器控制,不再是应用程序,IoC容器控制着对象的创建、销毁,对象不再管理那些被引用的对象的生命周期。应用程序(或者一个对象)不再主动创建对象,而是被动地接受依赖对象。
传统:
控制反转:
2. DI(Dependency Injection) DI即依赖注入,组件之间的依赖关系有IoC容器在运行之间决定,也就是应用程序需要的资源不再自己创建,而是有IoC容器创建并注入要需要依赖注入的组件(对象),由IoC容器为某个需要依赖注入的对象注入外部资源。“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象” 。
所谓控制反转,那么控制的什么反转了呢?其实就是:获得依赖对象的方式反转了!
依赖注入例子:
在前面的UserService.java中添加一个属性username,并提供属性的setter、getter方法;
在beans.xml配置依赖注入数据:
1 2 3 4 5 6 7 8 9 <bean id ="userService" class ="cn.zhuobo.spring.service.serviceImpl.UserServiceImpl" > <property name ="username" value ="tanzhuobo" /> </bean >
在这个例子里就是spring自己创建了一个字符串对象username,并主动注入到需要username这个对象的UserService对象中。
四、加载Spring容器的方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void test01 () { ApplicationContext context1 = new ClassPathXmlApplicationContext("beans.xml" ); UserService userService1 = (UserService) context1.getBean("userService" ); userService1.save(); ApplicationContext context2 = new FileSystemXmlApplicationContext("D:\\javaProject\\spring\\src\\beans.xml" ); UserService userService2 = (UserService) context2.getBean("userService" ); userService2.save(); }
五、装配bean的三种方式 1. 所谓的装配bean,就是在beans.xml中配置一个bean标签
使用构造方法创建bean
1 2 3 <bean id ="userService" class ="cn.zhuobo.spring.service.serviceImpl.UserServiceImpl" > <property name ="username" value ="tanzhuobo" /> </bean >
使用静态工厂 创建bean
写一个静态工厂,StaticUserServiceFactory.java
,用来创建bean
1 2 3 4 5 6 public class StaticUserServiceFactory { public static UserService getUserService () { return new UserServiceImpl(); } }
在beans.xml装配一个bean
1 2 3 <bean id ="userService2" class ="cn.zhuobo.spring.service.StaticUserServiceFactory" factory-method ="getUserService" />
使用实例工厂
也就是创建一个工厂,但是工厂提供的创建bean的方式不是静态的,InstanceUserServiceFactory.java
1 2 3 4 5 6 public class InstanceUserServiceFactory { public UserService getUserService () { return new UserServiceImpl(); } }
在beans.xml中装配一个bean
1 2 3 4 5 6 7 8 <bean id ="factory" class ="cn.zhuobo.spring.service.InstanceUserServiceFactory" /> <bean id ="userService3" factory-bean ="factory" factory-method ="getUserService" > <property name ="username" value ="tan3" /> </bean >
2. bean的作用域 在bean标签内可以配置scope属性,表示该bean在容器内是单例还是多例的。
值
说明
singleton
在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype
每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean()
六、bean的生命周期
七、依赖注入 依赖注入,为bean(被注入对象)创建依赖对象,配置依赖对象(可以狭义的解释为为bean的属性赋值)。
1. 手动装配,使用xml 1. 构造方法注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <bean id ="student1" class ="cn.zhuobo.spring.domain.Student" > <constructor-arg name ="name" value ="zhuobo1" /> <constructor-arg name ="age" value ="18" /> </bean > <bean id ="student2" class ="cn.zhuobo.spring.domain.Student" > <constructor-arg name ="name" value ="zhuobo2" /> <constructor-arg name ="password" value ="password2" /> </bean > <bean id ="student3" class ="cn.zhuobo.spring.domain.Student" > <constructor-arg index ="0" type ="java.lang.String" value ="zhuobo3" /> <constructor-arg index ="1" type ="java.lang.Integer" value ="19" /> </bean >
2. setter方法注入 1 2 3 4 5 <bean id ="student4" class ="cn.zhuobo.spring.domain.Student" > <property name ="name" value ="zhuobo4" /> <property name ="password" value ="password4" /> <property name ="age" value ="18" /> </bean >
3. p命名空间注入
2. Spring表达式 1 2 3 4 5 #{123}、#{'jack'} : 数字、字符串 #{beanId} :另一个bean引用 #{beanId.propName} :操作数据 #{beanId.toString()} :执行方法 #{T(类).字段|方法} :静态方法或字段
3. 集合注入 集合的注入都是在property
添加子标签:
数组:array
Set:<set>
List:<list>
Map:<map>
,使用子标签 <entry>
描述
Properties:<props>
,使用子标签 <prop key='key'>value</prop>
描述
数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // 类 public class Student { private String name; private String[] courses; } // 配置一个bean,并为集合属性注入数据 <bean id ="student" class ="cn.zhuobo.spring.domain.Student" > <property name ="name" value ="zhuobo" /> <property name ="courses" > <array > <value > Math</value > <value > English</value > <value > Computer Science</value > </array > </property > </bean >
List
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // class public class Student { private String name; private List<String > courses; } // 配置一个bean,并为集合属性注入数据 <bean id ="student" class ="cn.zhuobo.spring.domain.Student" > <property name ="name" value ="zhuobo" /> <property name ="courses" > <list > <value > Math</value > <value > English</value > <value > Computer Science</value > </list > </property > </bean >
Set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // class public class Student { private String name; private List<String > courses; private Set<String > cars; } <bean id ="student" class ="cn.zhuobo.spring.domain.Student" > <property name ="cars" > <set > <value > BMW</value > <value > Audi</value > <value > Ferrari</value > <value > Porsche</value > </set > </property > </bean >
Map
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Student { private String name; private Map<String, String > info; } // 为map属性注入数据 <bean id ="student" class ="cn.zhuobo.spring.domain.Student" > <property name ="info" > <map > <entry key ="name" value ="zhuobo" /> <entry key ="id" value ="14332017" /> </map > </property > </bean >
Properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Student { private String name; private Properties mySqlInfos; } // 为map属性注入数据 <bean id ="student" class ="cn.zhuobo.spring.domain.Student" > <property name ="mySqlInfos" > <props > <prop key ="username" > zhuobo</prop > <prop key ="password" > password</prop > <prop key ="url" > mysql:jdbc://localhost:3306/database</prop > </props > </property > </bean >
4. 注解注入 使用注解来取代xml配置,在类上添加注解就相当于在xml写了一个手动装配了一个bean标签,Spring的注解注入默认是不开启的,开启注解注入如下:
@Component:没有配置id,需要根据类型获取;
1 2 3 UserService userService = (UserService) context.getBean(UserService.class);
@Component(“id”):配置了id,可以使用getBean,根据参数id获取bean;
web开发@Component的衍生注解:
@Repository(“名称”):dao层
@Service(“名称”):service层
@Controller(“名称”):web层
@AutoWired:根据数据类型 自动注入,如果是接口,spring根据类型从容器中找到合适的bean注入
@Qualifier(“名称”):指定自动注入的id名称,与@AutoWired结合使用
@Resource(“名称”):相当于上面两个注解结合使用的简写
@ PostConstruct:自定义初始化
@ PreDestroy:自定义销毁
@scope(prototype):多例,默认是单例
八、AOP(面向切面) Aspect Oriented Programming(面向切面编程),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP实现的目的是对业务处理过程的切面进行提取,提取处理工程的某个步骤或者阶段,以获得逻辑过程各个部分之间低耦合性的隔离效果。
1)AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
2)利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
3)AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
4) 经典应用:事务管理、性能监视、安全检查、缓存、日志等
5) Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
1. AOP实现原理 a.aop底层将采用代理机制进行实现。
b.接口 + 实现类 :spring采用 jdk 的动态代理 Proxy。
c. 实现类:spring 采用 cglib 字节码增强。
2. AOP术语 1.target :目标类,需要被代理的类。例如:UserService 2.Joinpoint (连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法 3.PointCut 切入点:已经被增强的连接点。例如:addUser() 4.advice 通知/增强,增强代码。例如:after、before 5.Weaving (织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程. 6.proxy 代理类 7.Aspect (切面): 是切入点pointcut和通知advice的结合 一个线是一个特殊的面。 一个切入点和一个通知,组成成一个特殊的面。
3. 手动代理 1. JDK动态代理 这种方法需要目标类有接口以及实现类
目标类:
切面类:
工厂类: 创建一个工厂类,工厂类的静态方法返回一个UserService
接口,通过创建代理对象的方法,返回一个代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class MyBeanFactory { public static UserService createUserService() { // 1. 创建目标对象 final UserService userService = new UserServiceImpl(); // 2. 生命切面类对象 final MyAspect myAspect = new MyAspect(); // 3. 把切面的两个方法应用到目标对象 // 3.1 创建jdk代理 UserService userServiceProxy = (UserService) Proxy.newProxyInstance( MyBeanFactory.class.getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 执行增强代码 myAspect.before(); // 执行目标对象的方法,并传递参数 Object object = method.invoke(userService, args); // 执行增强方法 myAspect.after(); return object; } }); // 返回的是代理对象 return userServiceProxy; } }
测试:
2. cglib增强字节码
目标对象只有类,没有接口(目标对象没有实现接口),或者有接口由实现类都可以使用cglib字节码增强框架增强对象;
使用cglib字节码增强框架,在运行时创建目标类的子类,从而对目标类进行增强。
导入jar包: spring-core.jar
整合了cglib字节码增强框架;
工厂类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public static UserService createUserService1 () { final UserService userService = new UserServiceImpl(); final MyAspect myAspect = new MyAspect(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(userService.getClass()); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { myAspect.before(); Object obj = methodProxy.invokeSuper(o, objects); myAspect.after(); return obj; } }); UserService userServiceProxy = (UserService) enhancer.create(); return userServiceProxy; }
4. AOP的5中通知类型 AOP联盟为通知Advice定义了org.aopalliance.aop.Advice
Spring按照通知Advice在目标类方法的连接点位置,可以分为5类
•前置通知 org.springframework.aop.MethodBeforeAdvice
•在目标方法执行前实施增强
•后置通知 org.springframework.aop.AfterReturningAdvice
•在目标方法执行后实施增强
•环绕通知 org.aopalliance.intercept.MethodInterceptor
•在目标方法执行前后实施增强
•异常抛出通知 org.springframework.aop.ThrowsAdvice
•在方法抛出异常后实施增强
•引介通知 org.springframework.aop.IntroductionInterceptor
在目标类中添加一些新的方法和属性
5. Spring编写半自动代理 1. 导入jar包 除了Spring的5个核心jar包之外,还需要导入2个jar包,分别是aop联盟、aop实现:
2. 目标类
3. 切面类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class MyAspect implements MethodInterceptor { @Override public Object invoke (MethodInvocation methodInvocation) throws Throwable { System.out.println("--start transaction--" ); Object object = methodInvocation.proceed(); System.out.println("--commit transaction--" ); return object; } }
4. spring配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <bean id ="userService" class ="cn.zhuobo.spring.service.serviceImpl.UserServiceImpl" /> <bean id ="myAspect" class ="cn.zhuobo.spring.service.MyAspect" /> <bean id ="userServiceProxy" class ="org.springframework.aop.framework.ProxyFactoryBean" > <property name ="interfaces" value ="cn.zhuobo.spring.service.UserService" /> <property name ="target" ref ="userService" /> <property name ="interceptorNames" value ="myAspect" /> <property name ="optimize" value ="true" /> </bean >
5. 测试 1 2 3 4 5 6 7 @Test public void test07 () { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserService userServiceProxy = (UserService) context.getBean("userServiceProxy" ); userServiceProxy.deleteUser(); }
6. Spring全自动AOP 1. 导入jar包 1 spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE.jar
2. 配置xml
3. 测试 注意到,这种配置方法是不会出现代理对象的,虽然说实际上还是代理对象在工作,根据 proxy-target-class
配置使用什么代理对象。
1 2 3 4 5 6 7 8 @Test public void test07 () { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserService userServiceProxy = (UserService) context.getBean("userService" ); userServiceProxy.deleteUser(); }
九、AspectJ 1. 介绍
AspectJ是一个基于Java语言的AOP框架
Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
新版本Spring框架,建议使用AspectJ方式来开发AOP
主要用途:自定义开发
2. 切入点表达式 切入点表达式用于描述作为切入点的方法
Execution() 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 修饰符,一般省略 public 公共方法 * 任意 返回值,不能省略 void 返回没有值 String 返回值字符串 * 任意 包,[省略] com.gyf.crm 固定包 com.gyf.crm.*.service crm包下面子包任意 (例如:com.gyf.crm.staff.service) com.gyf.crm.. crm包下面的所有子包(含自己) com.gyf.crm.*.service.. crm包下面任意子包,固定目录service,service目录任意包 类,[省略] UserServiceImpl 指定类 *Impl 以Impl结尾 User* 以User开头 * 任意 方法名,不能省略 addUser 固定方法 add* 以add开头 *Do 以Do结尾 * 任意 (参数) () 无参 (int) 一个整型 (int ,int) 两个 (..) 参数任意 throws ,可省略,一般不写。
within():匹配包或者子包内的方法
语法:within(com.zhuobo.service..*)
this():匹配实现接口的代理对象中的方法
语法:this(com.zhuobo.aop.user.UserDao)
target():匹配实现接口的目标对象中的方法
语法:this(com.zhuobo.aop.user.UserDao)
args():匹配参数格式符合指定格式的方法
语法:args(int, int )
bean():指定的bean中的所有方法
语法:bean(‘bean id’)
3. AspectJ通知类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 aop联盟定义通知类型,具有特性接口,必须实现,从而确定方法名称。 aspectj 通知类型,只定义类型名称,以及方法格式。 个数:6种,知道5种,掌握1中。 before:前置通知(应用:各种校验) 在方法执行前执行,如果通知抛出异常,阻止方法运行 afterReturning:后置通知(应用:常规数据处理) 方法正常返回后执行,如果方法中抛出异常,通知无法执行 必须在方法执行后才执行,所以可以获得方法的返回值。 around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行 必须手动执行目标方法 afterThrowing:抛出异常通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行 after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
4. 基于xml的AspectJ的使用 1. 导入包
2. 编写业务类和切面类 业务类:
切面类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class MyAspect { public void myBefore (JoinPoint joinPoint) { System.out.println(joinPoint.getSignature().getName()); System.out.println("--BEFORE ADVICE--" ); } public void myAfter (JoinPoint joinPoint) { System.out.println(joinPoint.getSignature().getName()); System.out.println("--AFTER ADVICE--" ); } public Object myAround (ProceedingJoinPoint joinPoint) throws Throwable { System.out.println(joinPoint.getSignature().getName()); System.out.println("--before around ADVICE--" ); Object object = joinPoint.proceed(); System.out.println("--after around ADVICE--" ); return object; } public void myAfterReturning (JoinPoint joinPoint) { System.out.println(joinPoint.getSignature().getName()); System.out.println("--myAfterReturning ADVICE--" ); } }
3. Spring的xml配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <bean id ="userService" class ="cn.zhuobo.spring.service.serviceImpl.UserServiceImpl" /> <bean id ="myAspect" class ="cn.zhuobo.spring.service.MyAspect" /> <aop:config proxy-target-class ="true" > <aop:aspect ref ="myAspect" > <aop:pointcut id ="myPointcut" expression ="execution(* cn.zhuobo.spring.service.serviceImpl.UserServiceImpl.*(..))" /> <aop:before method ="myBefore" pointcut-ref ="myPointcut" /> <aop:after-returning returning ="returning" method ="myAfterReturning" pointcut-ref ="myPointcut" /> <aop:around method ="myAround" pointcut-ref ="myPointcut" /> <aop:after-throwing method ="myAfterThrowing" pointcut-ref ="myPointcut" throwing ="throwable" /> <aop:after method ="myAfter" pointcut-ref ="myPointcut" /> </aop:aspect > </aop:config >
4. 测试 1 2 3 4 5 6 7 8 @Test public void test01 () { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserService userService = (UserService) context.getBean("userService" ); userService.deleteUser(); }
5. 给予注解的AspectJ的使用 1. 声明使用注解 1 2 3 4 <context:component-scan base-package ="cn.zhuobo.spring" /> <aop:aspectj-autoproxy />
2. 使用注解配置业务类和切面类 原来的xml配置方式:
1 2 3 4 <bean id ="userService" class ="cn.zhuobo.spring.service.serviceImpl.UserServiceImpl" /> <bean id ="myAspect" class ="cn.zhuobo.spring.service.MyAspect" />
使用注解:
1 2 3 4 5 6 @Service ("userService" )public class UserServiceImpl implements UserService @Component @Aspect // 使用@Aspect 注解声明这是一个切面类 public class MyAspect {
3. 声明一个公共的切入点 @PointCut ,修饰方法 private void xxx(){} 之后通过“方法名”获得切入点引用
原来的xml配置方式:
1 <aop:pointcut id ="myPointcut" expression ="execution(* cn.zhuobo.spring.service.serviceImpl.UserServiceImpl.*(..))" />
使用注解: 在切面类里面创建一个方法,这个方法什么都不做,就只是添加一个注解,声明是公共的切入点
十、JDBC Template JDBC Template是用于操作JDBC(Java DataBase Connectivity)的工具类,需要使用数据库连接池技术,其中两种比较常用的数据库连接池就是微软公司提供的dbcp
、以及开源的c3p0。(c3p0有自动回收空闲连接的功能,而DBCP没有自动回收空闲连接的功能。控线连接指的是指定时间内,也就是长时间不使用的连接。DBCP的回收机制是如果连接数大于最大连接数,便回收连接。)
1. 在Spring中配置c3p0连接池,使用JDBC Template 1. 导入相关jar包
2. 在spring中配置 1 2 3 4 5 6 7 8 9 10 11 12 <bean id ="datasource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name ="driverClass" value ="com.mysql.jdbc.Driver" /> <property name ="password" value ="root" /> <property name ="user" value ="root" /> <property name ="jdbcUrl" value ="jdbc:mysql://localhost:3306/spring" /> </bean > <bean id ="template" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="datasource" /> </bean >
3. 测试 1 2 3 4 5 6 7 8 9 @Test public void test04 () { ApplicationContext context = new ClassPathXmlApplicationContext("beans02.xml" ); JdbcTemplate template = (JdbcTemplate) context.getBean("template" ); int rows = template.update("insert into t_user values (null, ?, ?)" , "zhuobo2" , "password2" ); System.out.println("Affect rows :" +rows); }
4. 将配置连接池的信息独立为一个文件
在类路径src
目录下创建一个文件database.properties
,文件内写数据库连接信息
1 2 3 4 driverClass=com.mysql.jdbc.Driver jdbcUrl=jdbc:mysql://localhost:3306/spring password=root user=root
在spring配置文件中配置
1 2 3 4 5 6 7 8 9 10 11 <context:property-placeholder location ="classpath:database.properties" /> <bean id ="datasource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name ="driverClass" value ="${driverClass}" /> <property name ="password" value ="${password}" /> <property name ="user" value ="${user}" /> <property name ="jdbcUrl" value ="${jdbcUrl}" /> </bean >
十一、事务管理 1. 事务回顾 简单事务 :ABCD要么全部成功,要么全部失败;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ABCD 一个事务 Connection conn = null ; try { conn = ...; conn.setAutoCommit(false ); A B C D conn.commit(); } catche(){ conn.rollback(); }
有保存点的事务: AB(必须),CD(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Connection conn = null ; Savepoint savepoint = null ; try { conn = ...; conn.setAutoCommit(false ); A B savepoint = conn.setSavepoint(); C D conn.commit(); } catche(){ if (savepoint != null ){ conn.rollback(savepoint); conn.commit(); } else { conn.rollback(); } }
2. 事务的传播行为
事务
描述
PROPAGATION_REQUIRED required , 必须 【默认值】
支持当前事务,A如果有事务,B将使用该事务。 如果A没有事务,B将创建一个新的事务。
PROPAGATION_SUPPORTS supports ,支持
支持当前事务,A如果有事务,B将使用该事务。 如果A没有事务,B将以非事务执行。
PROPAGATION_MANDATORY mandatory ,强制
支持当前事务,A如果有事务,B将使用该事务。 如果A没有事务,B将抛异常。
PROPAGATION_REQUIRES_NEW requires_new ,必须新的
如果A有事务,将A的事务挂起,B创建一个新的事务 如果A没有事务,B创建一个新的事务
PROPAGATION_NOT_SUPPORTED not_supported ,不支持
如果A有事务,将A的事务挂起,B将以非事务执行 如果A没有事务,B将以非事务执行
PROPAGATION_NEVER never,从不
如果A有事务,B将抛异常 如果A没有事务,B将以非事务执行
PROPAGATION_NESTED nested ,嵌套
A和B底层采用保存点机制,形成嵌套事务。
3. 手动管理事务 Spring底层使用TransactionTemplate
对事务进行管理,还是比较麻烦的,可以直接使用TransactionTemplate
,或者使用TransactionProxyFactoryBean 生成代理管理事务,具体操作过程:
Service提供一个TransactionTemplate属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class AccountServiceImpl implements AccountService { private AcountDao accountDao; private TransactionTemplate transactionTemplate; public void setTransactionTemplate (TransactionTemplate transactionTemplate) { this .transactionTemplate = transactionTemplate; } public void setAccountDao (AcountDao accountDao) { this .accountDao = accountDao; } @Override public void transfer (final String outer, final String inner, final Integer money) { this .transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult (TransactionStatus transactionStatus) { accountDao.out(outer, money); int num = 1 /0 ; accountDao.in(inner, money); } }); } }
配置xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <context:property-placeholder location ="classpath:database.properties" /> <bean id ="datasource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name ="driverClass" value ="${driverClass}" /> <property name ="password" value ="${password}" /> <property name ="user" value ="${user}" /> <property name ="jdbcUrl" value ="${jdbcUrl}" /> </bean > <bean id ="accountDao" class ="cn.zhuobo.spring.dao.daoImpl.AcountDaoImpl" > <property name ="dataSource" ref ="datasource" /> </bean > <bean id ="txManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="datasource" /> </bean > <bean id ="transactionTemplate" class ="org.springframework.transaction.support.TransactionTemplate" > <property name ="transactionManager" ref ="txManager" /> </bean > <bean id ="accountService" class ="cn.zhuobo.spring.service.serviceImpl.AccountServiceImpl" > <property name ="accountDao" ref ="accountDao" /> <property name ="transactionTemplate" ref ="transactionTemplate" /> </bean >
4. 基于AOP的事务管理 1. 基于xml的配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <context:property-placeholder location ="classpath:database.properties" /> <bean id ="datasource" class ="com.mchange.v2.c3p0.ComboPooledDataSource" > <property name ="driverClass" value ="${driverClass}" /> <property name ="password" value ="${password}" /> <property name ="user" value ="${user}" /> <property name ="jdbcUrl" value ="${jdbcUrl}" /> </bean > <bean id ="accountDao" class ="cn.zhuobo.spring.dao.daoImpl.AcountDaoImpl" > <property name ="dataSource" ref ="datasource" /> </bean > <bean id ="accountService" class ="cn.zhuobo.spring.service.serviceImpl.AccountServiceImpl" > <property name ="accountDao" ref ="accountDao" /> </bean > <bean id ="txManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="datasource" /> </bean > <tx:advice id ="txAdvice" transaction-manager ="txManager" > <tx:attributes > <tx:method name ="transfer" propagation ="REQUIRED" isolation ="DEFAULT" /> </tx:attributes > </tx:advice > <aop:config > <aop:pointcut id ="myPointcut" expression ="execution(* cn.zhuobo.spring.service.serviceImpl.*.*(..))" /> <aop:advisor advice-ref ="txAdvice" pointcut-ref ="myPointcut" /> </aop:config >
AccountService :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class AccountServiceImpl implements AccountService { private AcountDao accountDao; public void setAccountDao (AcountDao accountDao) { this .accountDao = accountDao; } @Override public void transfer (String outer, String inner, Integer money) { accountDao.out(outer, money); int num = 1 / 0 ; accountDao.in(inner, money); } }
2. 注解配置事务
首先要先开启使用注解配置事务
在业务类上或者具体的业务类方法上使用注解