本文共 22803 字,大约阅读时间需要 76 分钟。
Spring学习笔记(
14
)----使用CGLIB实现AOP功能
-----------------------------------------------
接着这上面的例子,在上面的例子中我们的UserManagerImpl类是实现了UserManager接口,如果UserManagerImpl没有实现任何接口要怎么办呢?应为创建代理对象时我们需要指定接口的。
Java代码
1
.Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
2
. targetObject.getClass().getInterfaces(),
3
.
this
);
由于没有时间接口,因此我们是不能这样创建代理接口的,这是我们需要借助第三方包来实现。在spring中提供了cglib-nodep-
2
.1_3.jar包。我们通过cglib创建代理对象。
下面就通过实例演示通过cglib创建代理对象。
首先创建CGlibProxyFactory,实现MethodInterceptor接口,接口中有一个intercept方法,当代理对象的方法被调用时会调用这个方法。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
import
java.lang.reflect.Method;
4
.
import
net.sf.cglib.proxy.Enhancer;
5
.
import
net.sf.cglib.proxy.MethodInterceptor;
6
.
import
net.sf.cglib.proxy.MethodProxy;
7
.
8
.
9
.
public
class
CGlibProxyFactory
implements
MethodInterceptor
10
.{
11
.
private
Object targetObject;
12
.
13
.
public
Object newProxy(Object targetObject)
14
. {
15
.
this
.targetObject=targetObject;
16
. Enhancer enhancer=
new
Enhancer();
17
. enhancer.setSuperclass(
this
.targetObject.getClass());
18
. enhancer.setCallback(
this
);
19
.
//返回代理对象
20
.
return
enhancer.create();
21
. }
22
.
23
.
/**
24. * proxy 带来对象本身
25. * method 被拦截到的方法
26. * args 方法的参数
27. * methodProxy 方法的代理对象
28. */
29
.
public
Object intercept(Object proxy, Method method, Object[] args,
30
. MethodProxy methodProxy)
throws
Throwable
31
. {
32
. checkSecurity();
33
. Object ret=
null
;
34
.
try
35
. {
36
.
//调用目标对象的真实方法
37
. ret=method.invoke(
this
.targetObject, args);
38
.
//ret接受存在的返回值,不存在返回值则为Null
39
. }
catch
(Exception e)
40
. {
41
. e.printStackTrace();
42
. }
43
.
return
ret;
44
. }
45
.
public
void
checkSecurity()
46
. {
47
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
48
. }
49
.}
其实整个代码很前面的很相似,只是创建代理对象的方法不一样。
测试代码:
Java代码
1
.CGlibProxyFactory factory=
new
CGlibProxyFactory();
2
.
//创建代理对象,这是这个代理对象是UserManagerImpl的子类
3
. UserManagerImpl userManager=(UserManagerImpl)factory.newProxy(
new
UserManagerImpl());
4
. userManager.addUser(
"coolszy"
,
"kuka"
);
上面演示的几个事例是不借助与任何框架的情况下实现AOP的方法。
Spring学习笔记(
15
)----使用Spring的注解方式实现AOP
-----------------------------------------------------
下面介绍使用Spring框架进行AOP编程。
首先我们需要导入需要的jar包:
1
.aspectjrt.jar
2
.aspectjweaver.jar
3
.cglib-nodep-
2
.1_3.jar
在spring中有两种方式实现面向切面编程,一种是基于XML配置,另一种是使用注解份额方式,在实际开放中我们可以任选其中的一种即可。
首先介绍下使用注解方式进行AOP开发。
要使用注解方式,我们需要打开注解处理器
Xml代码
1
.<aop:aspectj-autoproxy/>
我们还是使用前面介绍的接口:
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
interface
UserManager
4
.{
5
.
6
.
public
abstract
void
addUser(String username, String password);
7
.
8
.
public
abstract
void
deleteUser(
int
userId);
9
.
10
.
public
abstract
String findUser(
int
userId);
11
.
12
.
public
abstract
void
modifyUser(
int
userId, String username, String password);
13
.
14
.}
实现这个接口:
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
UserManagerImpl
implements
UserManager
4
.{
5
.
6
.
public
void
addUser(String username, String password)
7
. {
8
. System.out.println(
"--------UserManagerImpl.addUser()----------"
);
9
. }
10
.
11
.
public
void
deleteUser(
int
userId)
12
. {
13
. System.out.println(
"--------UserManagerImpl.deleteUser()----------"
);
14
. }
15
.
16
.
public
String findUser(
int
userId)
17
. {
18
. System.out.println(
"--------UserManagerImpl.findUser()----------"
);
19
.
return
null
;
20
. }
21
.
22
.
public
void
modifyUser(
int
userId, String username, String password)
23
. {
24
. System.out.println(
"--------UserManagerImpl.modifyUser()----------"
);
25
. }
26
.}
下面我们定义一个切面类,由于我们使用的是注解方式,因此我们使用
@Aspect
来标识它是切面类。在切面类中我们要定义切入点,切入点是用来定义我们要拦截的方法。在切入点定义中使用了AOP表达式语言,下面通过实例简单解释一下:
表达式解释代码
1
.
@Pointcut
(
"execution (* com.szy.spring..*.*(..))"
)
2
.execution:代表执行
3
.第一个*:代表返回值类型,使用*代表任何类型的返回值
4
.com.szy.spring:代表包名
5
...:代表其底下的子包也进行拦截
6
.第二个*:代表对哪个类进行拦截,*代表所有类
7
.第三个*:代表方法
8
.(..):代表方法的蚕食有无都可以
现在我们要对UserManagerImpl类下的所有方法进行拦截,则切入点如下表示:
Java代码
1
.
@Pointcut
(
"execution (* com.szy.spring.UserManagerImpl.*(..))"
)
2
.
3
.
private
void
anyMethod()
//定义切入点
4
. {
5
. }
其中切入点的名称是下面方法的名称aynMethod(),包括括号。
下面我们定义通知,通知分为前置通知、后置通知、意外通知、等。通知分为前置通知、后置通知、意外通知、最终通知和环绕通知等。
演示前置通知,
Java代码
1
.
@Before
(
"anyMethod()"
)
//括号内为切入点名称
2
.
public
void
doBefore()
3
. {
4
. System.out.println(
"----------------执行前置通知-----------------"
);
5
. }
6
.
7
.
@AfterReturning
(
"anyMethod()"
)
8
.
public
void
doAfterReturning()
9
. {
10
. System.out.println(
"----------------执行后置通知-----------------"
);
11
. }
Java代码
1
.
@After
(
"anyMethod()"
)
2
.
public
void
doAfter()
3
. {
4
. System.out.println(
"----------------执行最终通知-----------------"
);
5
. }
6
.
7
.
@AfterThrowing
(
"anyMethod()"
)
8
.
public
void
doAfterThrowing()
9
. {
10
. System.out.println(
"----------------执行意外通知-----------------"
);
11
. }
12
.
13
.
@Around
(
"anyMethod()"
)
14
.
public
Object doAround(ProceedingJoinPoint pjp)
throws
Throwable
15
. {
16
. System.out.println(
"----------------进入判断方法-----------------"
);
17
. Object result=pjp.proceed();
//该方法必须被执行
18
. System.out.println(
"----------------退出判断方法-----------------"
);
19
.
return
result;
20
. }
我们把切面交给spring管理,要交给spring管理我们可以在配置文件同进行bean配置,或者使用扫描的方式。
Xml代码
1
.<bean id=
"interceptor"
class
=
"com.szy.spring.Interceptor"
/>
下面我们进行测试
Java代码
1
.ApplicationContext context=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. UserManager manager=(UserManager)context.getBean(
"userManager"
);
3
. manager.addUser(
"coolszy"
,
"kuka"
);
按照我们的设计,输入的结果应为
----------------执行前置通知-----------------
----------------进入判断方法-----------------
--------UserManagerImpl.addUser()----------
----------------执行后置通知-----------------
----------------执行最终通知-----------------
----------------退出判断方法-----------------
Spring学习笔记(
16
)----使用Spring配置文件实现AOP
----------------------------------------------
前面介绍了使用注解的方式,下面介绍使用配置文件的方式实现AOP。
使用配置方式,Interceptor类中不包含任何注解。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
import
org.aspectj.lang.ProceedingJoinPoint;
4
.
5
.
public
class
Interceptor
6
.{
7
.
public
void
doBefore()
8
. {
9
. System.out.println(
"----------------执行前置通知-----------------"
);
10
. }
11
.
12
.
public
void
doAfterReturning()
13
. {
14
. System.out.println(
"----------------执行后置通知-----------------"
);
15
. }
16
.
17
.
public
void
doAfter()
18
. {
19
. System.out.println(
"----------------执行最终通知-----------------"
);
20
. }
21
.
22
.
public
void
doAfterThrowing()
23
. {
24
. System.out.println(
"----------------执行意外通知-----------------"
);
25
. }
26
.
27
.
public
Object doAround(ProceedingJoinPoint pjp)
throws
Throwable
28
. {
29
. System.out.println(
"----------------进入判断方法-----------------"
);
30
. Object result=pjp.proceed();
//该方法必须被执行
31
. System.out.println(
"----------------退出判断方法-----------------"
);
32
.
return
result;
33
. }
34
.}
紧着这我们在配置文件中配置切面、切入点、通知等:
Xml代码
1
.<bean id=
"aspetbean"
class
=
"com.szy.spring.Interceptor"
/>
2
. <aop:config>
3
. <aop:aspect id=
"aspet"
ref=
"aspetbean"
>
4
. <aop:pointcut id=
"cut"
expression=
"execution (* com.szy.spring.UserManagerImpl.*(..))"
/>
5
. <aop:before pointcut-ref=
"cut"
method=
"doBefore"
/>
6
. <aop:after-returning pointcut-ref=
"cut"
method=
"doAfterReturning"
/>
7
. <aop:after pointcut-ref=
"cut"
method=
"doAfter"
/>
8
. <aop:after-throwing pointcut-ref=
"cut"
method=
"doAfterThrowing"
/>
9
. <aop:around pointcut-ref=
"cut"
method=
"doAround"
/>
10
. </aop:aspect>
11
. </aop:config>
运行测试代码输入正常结果。
在实际开发中AOP一般用于权限设置等。
Spring学习笔记(
14
)----使用CGLIB实现AOP功能
-----------------------------------------------
接着这上面的例子,在上面的例子中我们的UserManagerImpl类是实现了UserManager接口,如果UserManagerImpl没有实现任何接口要怎么办呢?应为创建代理对象时我们需要指定接口的。
Java代码
1
.Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
2
. targetObject.getClass().getInterfaces(),
3
.
this
);
由于没有时间接口,因此我们是不能这样创建代理接口的,这是我们需要借助第三方包来实现。在spring中提供了cglib-nodep-
2
.1_3.jar包。我们通过cglib创建代理对象。
下面就通过实例演示通过cglib创建代理对象。
首先创建CGlibProxyFactory,实现MethodInterceptor接口,接口中有一个intercept方法,当代理对象的方法被调用时会调用这个方法。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
import
java.lang.reflect.Method;
4
.
import
net.sf.cglib.proxy.Enhancer;
5
.
import
net.sf.cglib.proxy.MethodInterceptor;
6
.
import
net.sf.cglib.proxy.MethodProxy;
7
.
8
.
9
.
public
class
CGlibProxyFactory
implements
MethodInterceptor
10
.{
11
.
private
Object targetObject;
12
.
13
.
public
Object newProxy(Object targetObject)
14
. {
15
.
this
.targetObject=targetObject;
16
. Enhancer enhancer=
new
Enhancer();
17
. enhancer.setSuperclass(
this
.targetObject.getClass());
18
. enhancer.setCallback(
this
);
19
.
//返回代理对象
20
.
return
enhancer.create();
21
. }
22
.
23
.
/**
24. * proxy 带来对象本身
25. * method 被拦截到的方法
26. * args 方法的参数
27. * methodProxy 方法的代理对象
28. */
29
.
public
Object intercept(Object proxy, Method method, Object[] args,
30
. MethodProxy methodProxy)
throws
Throwable
31
. {
32
. checkSecurity();
33
. Object ret=
null
;
34
.
try
35
. {
36
.
//调用目标对象的真实方法
37
. ret=method.invoke(
this
.targetObject, args);
38
.
//ret接受存在的返回值,不存在返回值则为Null
39
. }
catch
(Exception e)
40
. {
41
. e.printStackTrace();
42
. }
43
.
return
ret;
44
. }
45
.
public
void
checkSecurity()
46
. {
47
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
48
. }
49
.}
其实整个代码很前面的很相似,只是创建代理对象的方法不一样。
测试代码:
Java代码
1
.CGlibProxyFactory factory=
new
CGlibProxyFactory();
2
.
//创建代理对象,这是这个代理对象是UserManagerImpl的子类
3
. UserManagerImpl userManager=(UserManagerImpl)factory.newProxy(
new
UserManagerImpl());
4
. userManager.addUser(
"coolszy"
,
"kuka"
);
上面演示的几个事例是不借助与任何框架的情况下实现AOP的方法。
Spring学习笔记(
15
)----使用Spring的注解方式实现AOP
-----------------------------------------------------
下面介绍使用Spring框架进行AOP编程。
首先我们需要导入需要的jar包:
1
.aspectjrt.jar
2
.aspectjweaver.jar
3
.cglib-nodep-
2
.1_3.jar
在spring中有两种方式实现面向切面编程,一种是基于XML配置,另一种是使用注解份额方式,在实际开放中我们可以任选其中的一种即可。
首先介绍下使用注解方式进行AOP开发。
要使用注解方式,我们需要打开注解处理器
Xml代码
1
.<aop:aspectj-autoproxy/>
我们还是使用前面介绍的接口:
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
interface
UserManager
4
.{
5
.
6
.
public
abstract
void
addUser(String username, String password);
7
.
8
.
public
abstract
void
deleteUser(
int
userId);
9
.
10
.
public
abstract
String findUser(
int
userId);
11
.
12
.
public
abstract
void
modifyUser(
int
userId, String username, String password);
13
.
14
.}
实现这个接口:
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
UserManagerImpl
implements
UserManager
4
.{
5
.
6
.
public
void
addUser(String username, String password)
7
. {
8
. System.out.println(
"--------UserManagerImpl.addUser()----------"
);
9
. }
10
.
11
.
public
void
deleteUser(
int
userId)
12
. {
13
. System.out.println(
"--------UserManagerImpl.deleteUser()----------"
);
14
. }
15
.
16
.
public
String findUser(
int
userId)
17
. {
18
. System.out.println(
"--------UserManagerImpl.findUser()----------"
);
19
.
return
null
;
20
. }
21
.
22
.
public
void
modifyUser(
int
userId, String username, String password)
23
. {
24
. System.out.println(
"--------UserManagerImpl.modifyUser()----------"
);
25
. }
26
.}
下面我们定义一个切面类,由于我们使用的是注解方式,因此我们使用
@Aspect
来标识它是切面类。在切面类中我们要定义切入点,切入点是用来定义我们要拦截的方法。在切入点定义中使用了AOP表达式语言,下面通过实例简单解释一下:
表达式解释代码
1
.
@Pointcut
(
"execution (* com.szy.spring..*.*(..))"
)
2
.execution:代表执行
3
.第一个*:代表返回值类型,使用*代表任何类型的返回值
4
.com.szy.spring:代表包名
5
...:代表其底下的子包也进行拦截
6
.第二个*:代表对哪个类进行拦截,*代表所有类
7
.第三个*:代表方法
8
.(..):代表方法的蚕食有无都可以
现在我们要对UserManagerImpl类下的所有方法进行拦截,则切入点如下表示:
Java代码
1
.
@Pointcut
(
"execution (* com.szy.spring.UserManagerImpl.*(..))"
)
2
.
3
.
private
void
anyMethod()
//定义切入点
4
. {
5
. }
其中切入点的名称是下面方法的名称aynMethod(),包括括号。
下面我们定义通知,通知分为前置通知、后置通知、意外通知、等。通知分为前置通知、后置通知、意外通知、最终通知和环绕通知等。
演示前置通知,
Java代码
1
.
@Before
(
"anyMethod()"
)
//括号内为切入点名称
2
.
public
void
doBefore()
3
. {
4
. System.out.println(
"----------------执行前置通知-----------------"
);
5
. }
6
.
7
.
@AfterReturning
(
"anyMethod()"
)
8
.
public
void
doAfterReturning()
9
. {
10
. System.out.println(
"----------------执行后置通知-----------------"
);
11
. }
Java代码
1
.
@After
(
"anyMethod()"
)
2
.
public
void
doAfter()
3
. {
4
. System.out.println(
"----------------执行最终通知-----------------"
);
5
. }
6
.
7
.
@AfterThrowing
(
"anyMethod()"
)
8
.
public
void
doAfterThrowing()
9
. {
10
. System.out.println(
"----------------执行意外通知-----------------"
);
11
. }
12
.
13
.
@Around
(
"anyMethod()"
)
14
.
public
Object doAround(ProceedingJoinPoint pjp)
throws
Throwable
15
. {
16
. System.out.println(
"----------------进入判断方法-----------------"
);
17
. Object result=pjp.proceed();
//该方法必须被执行
18
. System.out.println(
"----------------退出判断方法-----------------"
);
19
.
return
result;
20
. }
我们把切面交给spring管理,要交给spring管理我们可以在配置文件同进行bean配置,或者使用扫描的方式。
Xml代码
1
.<bean id=
"interceptor"
class
=
"com.szy.spring.Interceptor"
/>
下面我们进行测试
Java代码
1
.ApplicationContext context=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. UserManager manager=(UserManager)context.getBean(
"userManager"
);
3
. manager.addUser(
"coolszy"
,
"kuka"
);
按照我们的设计,输入的结果应为
----------------执行前置通知-----------------
----------------进入判断方法-----------------
--------UserManagerImpl.addUser()----------
----------------执行后置通知-----------------
----------------执行最终通知-----------------
----------------退出判断方法-----------------
Spring学习笔记(
16
)----使用Spring配置文件实现AOP
----------------------------------------------
前面介绍了使用注解的方式,下面介绍使用配置文件的方式实现AOP。
使用配置方式,Interceptor类中不包含任何注解。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
import
org.aspectj.lang.ProceedingJoinPoint;
4
.
5
.
public
class
Interceptor
6
.{
7
.
public
void
doBefore()
8
. {
9
. System.out.println(
"----------------执行前置通知-----------------"
);
10
. }
11
.
12
.
public
void
doAfterReturning()
13
. {
14
. System.out.println(
"----------------执行后置通知-----------------"
);
15
. }
16
.
17
.
public
void
doAfter()
18
. {
19
. System.out.println(
"----------------执行最终通知-----------------"
);
20
. }
21
.
22
.
public
void
doAfterThrowing()
23
. {
24
. System.out.println(
"----------------执行意外通知-----------------"
);
25
. }
26
.
27
.
public
Object doAround(ProceedingJoinPoint pjp)
throws
Throwable
28
. {
29
. System.out.println(
"----------------进入判断方法-----------------"
);
30
. Object result=pjp.proceed();
//该方法必须被执行
31
. System.out.println(
"----------------退出判断方法-----------------"
);
32
.
return
result;
33
. }
34
.}
紧着这我们在配置文件中配置切面、切入点、通知等:
Xml代码
1
.<bean id=
"aspetbean"
class
=
"com.szy.spring.Interceptor"
/>
2
. <aop:config>
3
. <aop:aspect id=
"aspet"
ref=
"aspetbean"
>
4
. <aop:pointcut id=
"cut"
expression=
"execution (* com.szy.spring.UserManagerImpl.*(..))"
/>
5
. <aop:before pointcut-ref=
"cut"
method=
"doBefore"
/>
6
. <aop:after-returning pointcut-ref=
"cut"
method=
"doAfterReturning"
/>
7
. <aop:after pointcut-ref=
"cut"
method=
"doAfter"
/>
8
. <aop:after-throwing pointcut-ref=
"cut"
method=
"doAfterThrowing"
/>
9
. <aop:around pointcut-ref=
"cut"
method=
"doAround"
/>
10
. </aop:aspect>
11
. </aop:config>
运行测试代码输入正常结果。
在实际开发中AOP一般用于权限设置等。
Spring学习笔记(
17
)----使用Spring注解方式管理事务
--------------------------------------------------
使用Spring+JDBC集成步骤如下:
*配置数据源,例如:
Xml代码
1
.<bean id=
"dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method=
"close"
>
2
. <property name=
"driverClassName"
value=
"com.mysql.jdbc.Driver"
/>
3
. <property name=
"url"
value=
"jdbc:mysql://localhost:3306/test"
/>
4
. <property name=
"username"
value=
"root"
/>
5
. <property name=
"password"
value=
"123456"
/>
6
. <!-- 连接池启动时的初始值 -->
7
. <property name=
"initialSize"
value=
"1"
/>
8
. <!-- 连接池的最大值 -->
9
. <property name=
"maxActive"
value=
"100"
/>
10
. <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
11
. <property name=
"maxIdle"
value=
"2"
/>
12
. <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
13
. <property name=
"minIdle"
value=
"1"
/>
14
. </bean>
*配置事务,配置事务时,需要在xml配置文件中引入用于声明事务的tx命名空间,事务的配置有两种方式:注解方式和基于XML配置的方式
下面演示下使用Spring注解方式管理事务
首先在配置文件中配置Spring提供的事务管理器
Xml代码
1
.<bean id=
"txManager"
class
=
"org.springframework.jdbc.datasource.DataSourceTransactionManager"
>
2
. <!-- 指定数据源 -->
3
. <property name=
"dataSource"
ref=
"dataSource"
/>
4
. </bean>
由于会使用注解方式,因此我们要打开注解处理器,对注解进行解析
Xml代码
1
.<tx:annotation-driven transaction-manager=
"txManager"
/>
这样我们的配置文件配置完成,下面我们在Mysql中建立一张表,
Sql代码
1
.create table users
2
.(
3
. id
int
(
11
) not
null
auto_increment,
4
. username varchar(
20
) not
null
,
5
. primary key (id)
6
.)
根据数据库,我们创建javabean
Java代码
1
.
package
com.szy.spring.bean;
2
.
/**
3. * @author coolszy
4. * @time Dec 6, 2009 2:13:33 PM
5. */
6
.
public
class
User
7
.{
8
.
private
int
id;
9
.
private
String username;
10
.
public
int
getId()
11
. {
12
.
return
id;
13
. }
14
.
public
void
setId(
int
id)
15
. {
16
.
this
.id = id;
17
. }
18
.
public
String getUsername()
19
. {
20
.
return
username;
21
. }
22
.
public
void
setUsername(String username)
23
. {
24
.
this
.username = username;
25
. }
26
.}
然后创建DAO接口,在DAO中提供几个方法:
Java代码
1
.
package
com.szy.spring.dao;
2
.
3
.
import
java.util.List;
4
.
5
.
import
com.szy.spring.bean.User;
6
.
7
.
public
interface
UserDAO
8
.{
9
.
public
void
save(User user);
10
.
public
void
update(User user);
11
. Public User getUser(
int
id);
12
.
public
void
delete(
int
id);
13
.
public
List<User> getAllUsers();
14
.}
实现这个接口
Java代码
1
.
package
com.szy.spring.dao.impl;
2
.
3
.
import
java.util.List;
4
.
5
.
import
com.szy.spring.bean.User;
6
.
import
com.szy.spring.service.UserService;
7
.
8
.
/**
9. * @author coolszy
10. * @time Dec 6, 2009 2:19:22 PM
11. */
12
.
public
class
UserDAOImpl
implements
UserDAO
13
.{
14
.
15
.
public
void
delete(
int
id)
16
. {
17
.
18
. }
19
.
20
.
public
List<User> getAllUsers()
21
. {
22
.
return
null
;
23
. }
24
.
25
.
public
User getUser(
int
id)
26
. {
27
.
28
. }
29
.
30
.
public
void
save(User user)
31
. {
32
.
33
. }
34
.
35
.
public
void
update(User user)
36
. {
37
.
38
. }
39
.
40
.}
下面把这个类交给Spring管理
Xml代码
1
.<bean id=
"userDAO"
class
=
"com.szy.spring.dao.impl.UserDAOImpl"
/>
由于要通过数据源对表进行操作,因此在DAO中添加数据源。
Java代码
1
.
private
DataSource dataSource;
2
.
3
.
public
void
setDataSource(DataSource dataSource)
4
. {
5
.
this
.dataSource = dataSource;
6
. }
然后在配置文件中进行配置
Xml代码
1
.<bean id=
"userDAO"
class
=
"com.szy.spring.service.impl.UserDAOImpl"
>
2
. <property name=
"dataSource"
ref=
"dataSource"
/>
3
. </bean>
这样我们就把数据源注入到类中。
在UserDAOImpl类中我们提供了dataSource,这样我们就可以对数据库进行操作,但是不推荐直接使用dataSource,建议使用JdbcTemplate
Java代码
1
.
private
JdbcTemplate jdbcTemplate;
2
.
public
void
setDataSource(DataSource dataSource)
3
. {
4
.
//this.dataSource = dataSource;
5
.
this
.jdbcTemplate=
new
JdbcTemplate(dataSource);
6
. }
下面我们使用jdbcTemplate对数据库进行增删改查,详细代码见附件。
Java代码
1
.
package
com.szy.spring.dao.impl;
2
.
3
.
import
java.util.List;
4
.
5
.
import
javax.sql.DataSource;
6
.
7
.
import
org.springframework.jdbc.core.JdbcTemplate;
8
.
9
.
import
com.szy.spring.bean.User;
10
.
import
com.szy.spring.dao.UserDAO;
11
.
12
.
/**
13. * @author coolszy
14. * @time Dec 6, 2009 2:19:22 PM
15. */
16
.
public
class
UserDAOImpl
implements
UserDAO
17
.{
18
.
//private DataSource dataSource;
19
.
private
JdbcTemplate jdbcTemplate;
20
.
public
void
setDataSource(DataSource dataSource)
21
. {
22
.
//this.dataSource = dataSource;
23
.
this
.jdbcTemplate=
new
JdbcTemplate(dataSource);
24
. }
25
.
26
.
public
void
delete(
int
id)
27
. {
28
. jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
29
.
new
int
[]{java.sql.Types.INTEGER});
30
. }
31
.
32
.
public
List<User> getAllUsers()
33
. {
34
.
return
(List<User>)jdbcTemplate.query(
"select * from users"
,
new
UserRowMapper());
35
. }
36
.
37
.
public
User getUser(
int
id)
38
. {
39
.
return
(User)jdbcTemplate.queryForObject(
"select * from users where id=?"
,
new
Object[]{id},
40
.
new
int
[]{java.sql.Types.INTEGER},
new
UserRowMapper());
41
.
42
. }
43
.
44
.
public
void
save(User user)
45
. {
46
. jdbcTemplate.update(
"insert into users(username) values(?)"
,
new
Object[]{user.getUsername()},
47
.
new
int
[]{java.sql.Types.VARCHAR});
48
.
49
. }
50
.
51
.
public
void
update(User user)
52
. {
53
. jdbcTemplate.update(
"update users set username=? where id=?"
,
new
Object[]{user.getUsername(),user.getId()},
54
.
new
int
[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});
55
.
56
. }
57
.
58
.}
编写测试代码,代码运行正常。
在我们实现的每个方法中如delete()方法,如果delete方法是这样
Java代码
1
.
public
void
delete(
int
id)
2
. {
3
. jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
4
.
new
int
[]{java.sql.Types.INTEGER});
5
.jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
6
.
new
int
[]{java.sql.Types.INTEGER});
7
.
8
. }
9
.
这样每条语句都会在各自的事务中执行,并不能保证在同一使用中执行,为了保证在同一事务中执行,我们应使用Spring容器提供的声明事务,我们在UserDAOImpl 类上加入
@Transactional
,表示该类受Spring事务管理。如果该类中每个方法不需要事务管理,如getUser方法,则在该方法前加入
Java代码
1
.
@Transactional
(propagation=Propagation.NOT_SUPPORTED)
PS:在上面的配置文件中我们在配置文件中指明了驱动类等信息,如果我们想写在配置文件中要怎么配置能,首先我们编写配置文件,
Jdbc.properties代码
1
.driverClassName=com.mysql.jdbc.Driver
2
.url=jdbc\:mysql\:
//localhost\:3306/test
3
.username=root
4
.password=
123456
5
.initialSize=
1
6
.maxActive=
100
7
.maxIdle=
2
8
.minIdle=
1
然后Spring的配置文件需进行如下配置:
Xml代码
1
.<context:property-placeholder location=
"classpath:jdbc.properties"
/>
2
. <bean id=
"dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method=
"close"
>
3
. <property name=
"driverClassName"
value=
"${driverClassName}"
/>
4
. <property name=
"url"
value=
"${url}"
/>
5
. <property name=
"username"
value=
"${username}"
/>
6
. <property name=
"password"
value=
"${password}"
/>
7
. <property name=
"initialSize"
value=
"${initialSize}"
/>
8
. <property name=
"maxActive"
value=
"${maxActive}"
/>
9
. <property name=
"maxIdle"
value=
"${maxIdle}"
/>
10
. <property name=
"minIdle"
value=
"${minIdle}"
/>
11
. </bean>
这样就可以从属性文件中读取到配置信息。
Spring学习笔记(
18
)----使用Spring配置文件实现事务管理
-------------------------------------------------------
由于我们要拦截UserDAOImpl中的方法,因此我们需要在配置文件中配置信息,在配置文件中使用了AOP技术来拦截方法。
Xml代码
1
.<aop:config>
2
. <aop:pointcut id=
"transactionPointcut"
expression=
"execution(* com.szy.spring.dao.impl..*.*(..))"
/>
3
. <aop:advisor advice-ref=
"txAdvice"
pointcut-ref=
"transactionPointcut"
/>
4
. </aop:config>
5
. <tx:advice id=
"txAdvice"
transaction-manager=
"txManager"
>
6
. <tx:attributes>
7
. <!-- 如果连接的方法是以get开头的方法,则不使用事务 -->
8
. <tx:method name=
"get*"
read-only=
"true"
propagation=
"NOT_SUPPORTED"
/>
9
. <tx:method name=
"*"
/>
10
. </tx:attributes>
11
. </tx:advice>
这样Spring就能对这个类进行事务管理。
下面我们测试下数据库操作是否在同一事务中执行。
假设我们的delete方法如下:
Java代码
1
.
public
void
delete(
int
id)
2
. {
3
. jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
4
.
new
int
[]{java.sql.Types.INTEGER});
5
. jdbcTemplate.update(
"delete from users1 where id=10"
);
6
. }
在第二条删除语句中,users1表是不存在的,如果两次update语句是在两个事务中执行,则第一条能成功执行,并且数据库中该id的记录已经被删除,而第二条由于不存在该表不能正常删除。如果在同一事务中执行,由于第二条update出错,数据库中不能删除任何记录。
测试代码:
Java代码
1
.
@Test
2
.
public
void
testDelete()
3
. {
4
. userDAO.delete(
5
);
5
. }
程序报错,同时id=
5
的记录没有被删除。如果我们把配置文件中关于事务配置的信息给注释掉,再次测试,程序同样报错,但是id=
5
的记录被成功删除掉,这说明这两条update语句是在两个不同的事务中运行。
PS:在平时开发中,Spring团队建议使用注解的方式进行配置,这样配置文件显得精简,同时也会做到精确控制。
转载地址:http://esfbi.baihongyu.com/