第一篇:Java回顾之I/O

  第二篇:Java回顾之网络通信

  第三篇:Java回顾之多线程

  第四篇:Java回顾之多线程同步

  第五篇:Java回顾之集合

  第六篇:Java回顾之序列化

  第七篇:Java回顾之反射

  第八篇:Java回顾之一些基础概念

  第九篇:Java回顾之JDBC

  第十篇:Java回顾之ORM框架

  我计划分两到三篇文章来描述Spring,这一篇主要讲Spring一些基础的内容。

  概述

  我印象4、5年前,我还做java开发的时候,Spring是一个非常火的框架,尤其是在Web开发领域,和Struts以及Hibernate构成了SSH三剑客。当时Web开发的另一个组合是LAMP,即Linux+Apache+MySQL+PHP。我在前端方面基本没有实战经验,对js等技术也还是停留在概念和语法方面,所以扬长避短,我对Spring以及Hibernate特别感兴趣。

  当年Spring是作为EJB的“替代者”横空出世的,其创始人Rod Johnson还写了一本《J2EE development without EJB》来推行这个框架,这也是一本关于Spring很经典的书,不过最好是在接触Spring一段时间后再去阅读,效果会好一点。

  Spring最主要的特点有两个:IoC和AOP,这也是J2EE开发企业软件时经常碰到的问题:1)对象太多如何管理;2)共同逻辑和业务逻辑纠缠在一起,错综复杂,如何解耦。

  这篇文章主要关注3个方面:IoC、AOP和数据库访问。这里我们假设所有需要的jar都已经准备就绪。

  IoC

  IoC的全称是Inversion of Control,中文称为控制反转, Martin Flower由根据它创造了一个新词:Dependency Injection,中文称为依赖注入。这两个词讲的是一回事儿。

  IoC的实质是如何管理对象,传统意义上我们使用new方式来创建对象,但在企业应用开发的过程中,大量的对象创建都在程序中维护很容易造成资源浪费,并且不利于程序的扩展。

  实现IoC通常有三种方式:

  1)利用接口或者继承,一般以接口较多。这种实现方式和我们平时提到的lazy load有异曲同工之妙。

  2)构造函数注入。

  3)属性注入。

   IoC是Spring框架的核心,接下来我们来探索一下Spring中IoC的风采。

  IoC简单示例

  我们先来定义一个简单的接口和实现:

 1 public interface UserDao {
2 void save();
3 }
4
5 public class UserDaoImpl implements UserDao
6 {
7
8 public void save() {
9 System.out.println("save() is called.");
10 }
11
12 }

  然后是在classpath下创建一个beans.xml文件(这个文件名不是必须这样的):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="userDaoImpl" class = "sample.spring.ioc.UserDaoImpl"/>
</beans>

  接下来是测试代码:

1 private static void test1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/beans.xml");
4 UserDao userDao = (UserDao)ctx.getBean("userDaoImpl");
5 userDao.save();
6 }

  输出结果如下:

save() is called.

  我们还可以通过工厂方式来创建对象。

  通过静态工厂创建Bean

  添加一个类,如下:

1 public class UserDaoFactory {
2
3 public static UserDao getUserDao()
4 {
5 return new UserDaoImpl();
6 }
7 }

  在beans.xml中,添加如下内容:

1 <bean id="userDaoImpl2" class = "sample.spring.ioc.UserDaoFactory" factory-method = "getUserDao"/>

  测试代码和执行结果和上面类似,不再赘述。

  通过实例工厂创建Bean

  添加如下类:

1 public class UserDaoFactory2
2 {
3 public UserDao getUserDao()
4 {
5 return new UserDaoImpl();
6 }
7 }

  这个类和UserDaoFactory唯一的区别是这里的getUserDao是实例方法,而不是静态方法。

  在beans.xml中追加如下内容:

1 <bean id="factory" class="sample.spring.ioc.UserDaoFactory2"/>
2 <bean id="userDaoImpl3" factory-bean="factory" factory-method="getUserDao"/>

  测试方法和结果同上。

  对象的生命周期

  我们可以通过设置bean节点的scope属性来控制对象的声明周期,它包含两个可选值:

  1)singleton,表明系统中对于同一个对象,只保留一个实例。

  2)prototype,表明系统中每次获取bean时,都新建一个对象。

  我们修改beans.xml文件:

1 <bean id="userDaoImpl" class = "sample.spring.ioc.UserDaoImpl" scope="singleton"/>
2 <bean id="userDaoImpl2" class = "sample.spring.ioc.UserDaoImpl" scope="prototype"/>

  这两个bean指向同一个类型,但是scope的设置不同。

  下面是测试方法:

 1 private static void scopeTest()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/scope.xml");
4 System.out.println("=====Singleton test=====");
5 UserDao userDao1A = (UserDao)ctx.getBean("userDaoImpl");
6 UserDao userDao1B = (UserDao)ctx.getBean("userDaoImpl");
7 System.out.println("userDao1A == userDao1B:" + (userDao1A==userDao1B));
8 System.out.println("=====Prototype test=====");
9 UserDao userDao2A = (UserDao)ctx.getBean("userDaoImpl2");
10 UserDao userDao2B = (UserDao)ctx.getBean("userDaoImpl2");
11 System.out.println("userDao2A == userDao2B:" + (userDao2A==userDao2B));
12 }

  执行结果如下:

=====Singleton test=====
userDao1A == userDao1B:true
=====Prototype test=====
userDao2A == userDao2B:false

  如何设置对象属性

  上面的示例中,我们的对象中没有包含属性,对于业务对象来说,这一般是不现实。实际中的对象或多或少都会有一些属性。

  Spring支持两种方式对属性赋值:set方式和构造函数。

  下面我们会分别描述两种方式,但首先我们需要展示业务对象:

 1 public class UserServiceBean
2 {
3 private int userID;
4 private String userName;
5 private UserDao userDao;
6 private List<String> hobbies;
7 private Map<String, Integer> scores;
8
9 public UserServiceBean(int userID, String userName, UserDao userDao, List hobbies,Map scores)
10 {
11 this.userID = userID;
12 this.userName = userName;
13 this.userDao = userDao;
14 this.hobbies = hobbies;
15 this.scores = scores;
16 }
17
18 public UserServiceBean(){}
19
20 public void setUserID(int userID) {
21 this.userID = userID;
22 }
23 public int getUserID() {
24 return userID;
25 }
26 public void setUserName(String userName) {
27 this.userName = userName;
28 }
29 public String getUserName() {
30 return userName;
31 }
32 public void setUserDao(UserDao userDao) {
33 this.userDao = userDao;
34 }
35 public UserDao getUserDao() {
36 return userDao;
37 }
38 public void setHobbies(List<String> hobbies) {
39 this.hobbies = hobbies;
40 }
41 public List<String> getHobbies() {
42 return hobbies;
43 }
44 public void setScores(Map<String, Integer> scores) {
45 this.scores = scores;
46 }
47 public Map<String, Integer> getScores() {
48 return scores;
49 }
50 }

  这是一个典型的学生信息,包括学号、姓名、爱好和成绩。

  通过Set方式为对象属性赋值

  我们在beans.xml中追加如内容:

 1 <bean id="userService" class="sample.spring.ioc.UserServiceBean">
2 <property name="userID" value="1"/>
3 <property name="userName" value="张三"/>
4 <property name="userDao" ref="userDaoImpl"/>
5 <property name="hobbies">
6 <list>
7 <value>羽毛球</value>
8 <value>看电影</value>
9 <value>弹吉他</value>
10 </list>
11 </property>
12 <property name="scores">
13 <map>
14 <entry key="数据结构" value="90"/>
15 <entry key="编译原理" value="85"/>
16 <entry key="离散数学" value="82"/>
17 </map>
18 </property>
19 </bean>

  上面是典型的为属性赋值的示例,其中属性不仅包括简单属性(整数、字符串),也包含了复杂属性(List、Map),还有其他的bean。

  下面是测试代码:

 1 private static void propertyTest1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/beans.xml");
4 UserServiceBean userService = (UserServiceBean)ctx.getBean("userService");
5 printUserService(userService);
6 }
7
8 private static void printUserService(UserServiceBean userService)
9 {
10 System.out.println("编号:" + userService.getUserID());
11 System.out.println("姓名:" + userService.getUserName());
12 System.out.println("爱好:");
13 for(String hobby:userService.getHobbies())
14 {
15 System.out.println(hobby);
16 }
17 System.out.println("学习成绩:");
18 for(Entry<String,Integer> entry:userService.getScores().entrySet())
19 {
20 System.out.println(entry.getKey() + "\t" + entry.getValue());
21 }
22 userService.getUserDao().save();
23 }

  输出结果如下:

编号:1
姓名:张三
爱好:
羽毛球
看电影
弹吉他
学习成绩:
数据结构 90
编译原理 85
离散数学 82
save() is called.

  通过构造函数为对象属性赋值

  我们也可以通过构造函数来为对象赋值,在上面定义UserServiceBean时,我们已经添加了一个构造函数。下面来看beans.xml中的配置:

 1 <bean id="userService2" class="sample.spring.ioc.UserServiceBean">
2 <constructor-arg index="0" value="1"/>
3 <constructor-arg index="1" value="张三"/>
4 <constructor-arg index="2" ref="userDaoImpl"/>
5 <constructor-arg index="3">
6 <list>
7 <value>羽毛球</value>
8 <value>看电影</value>
9 <value>弹吉他</value>
10 </list>
11 </constructor-arg>
12 <constructor-arg index="4">
13 <map>
14 <entry key="数据结构" value="90"/>
15 <entry key="编译原理" value="85"/>
16 <entry key="离散数学" value="82"/>
17 </map>
18 </constructor-arg>
19 </bean>

  测试代码和输出结果同上。

  需要注意:我们定义的业务对象应该保留默认的构造函数。

  使用Annotation来定位Bean

  在Spring中,除了在xml配置文件中定义对象,我们还可以使用Annotation来定位,这位我们提供了很大的方便。

  这里我们使用的Annotation主要包括:@Resource/@Autowried/@Qualifier。

  来看下面的示例:

 1 public class UserServiceBean2
2 {
3 private String userID;
4 private String userName;
5 @Resource(name="userDaoImpl")
6 private UserDao userDao1;
7 private UserDao userDao2;
8
9 @Autowired(required=false)
10 @Qualifier("userDaoImpl")
11 private UserDao userDao3;
12
13 @Autowired(required=false)
14 @Qualifier("userDaoImpl3")
15 private UserDao userDao4;
16
17 public void setUserID(String userID) {
18 this.userID = userID;
19 }
20 public String getUserID() {
21 return userID;
22 }
23 public void setUserName(String userName) {
24 this.userName = userName;
25 }
26 public String getUserName() {
27 return userName;
28 }
29 @Resource
30 public void setUserDao2(UserDao userDao2) {
31 this.userDao2 = userDao2;
32 }
33 public UserDao getUserDao2() {
34 return userDao2;
35 }
36
37 public void test()
38 {
39 userDao1.save();
40 userDao2.save();
41 System.out.println(userDao3.getClass().getName());
42 userDao3.save();
43 }
44 }

  测试方法:

1 private static void annotationTest()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/ioc/annotation.xml");
4 UserServiceBean2 userService = (UserServiceBean2)ctx.getBean("userService");
5
6 userService.test();
7 }

  输出结果如下:

save() is called.
save() is called.
sample.spring.ioc.UserDaoImpl
save() is called.

  我们来对上面示例中出现的Annotation来进行说明。

1 @Resource(name="userDaoImpl")
2 private UserDao userDao1;

  这是定义在字段上的Annotation,是指userDao1使用xml配置文件中定义的名为“userDaoImpl”的bean进行填充。

1 @Autowired(required=false)
2 @Qualifier("userDaoImpl")
3 private UserDao userDao3;

  这是第二种类型的Annotation,它把Autowired和Qualifier组合在一起使用,Qualifier来设置bean的名称,Autowired来设置bean找不到时的行为,required为true时会抛出异常,required为false时会返回null。

1 @Resource
2 public void setUserDao2(UserDao userDao2) {
3 this.userDao2 = userDao2;
4 }

  这是作用在setter上的Annotation,@Resource 可以不写明name参数,这时Spring会首先按照名字然后按照数据类型的方式去定位bean。

  自动加载对象定义

  对于大型系统来说,我们可能会创建大量的类,如果这些类的声明都需要写在xml文件里的话,会产生额外大量的工作。

  Spring提供了一种简单的机制让我们的对象可以自动注册。

  我们可以在beans.xml中添加如下内容:

1 <context:component-scan base-package="sample.spring.ioc"/>

  然后我们可以在sample.spring.ioc包下的对象,添加@Component/@Service/@Controller/@repository,这样Spring会自动将带有这些Annotation的类进行注册。

  下面是一个示例:

 1 @Service("userService")
2 public class UserServiceBean3
3 {
4 private String userID;
5 private String userName;
6 @Resource(name="userDaoImpl")
7 private UserDao userDao1;
8
9 @Autowired(required=true)
10 @Qualifier("userDaoImpl")
11 private UserDao userDao3;
12
13 public void setUserID(String userID) {
14 this.userID = userID;
15 }
16 public String getUserID() {
17 return userID;
18 }
19 public void setUserName(String userName) {
20 this.userName = userName;
21 }
22 public String getUserName() {
23 return userName;
24 }
25 // @Resource
26 // public void setUserDao2(UserDao userDao2) {
27 // this.userDao2 = userDao2;
28 // }
29 // public UserDao getUserDao2() {
30 // return userDao2;
31 // }
32
33 public void test()
34 {
35 userDao1.save();
36 // userDao2.save();
37 System.out.println(userDao3.getClass().getName());
38 userDao3.save();
39 }
40 }

  这个类和上面定义的UserServiceBean2非常相似,需要注意在类前面添加的Annotation信息。

  我们不需要在xml文件中手动定义这个bean,Spring会进行自动注册,注册的bean名称是userService。

  AOP

  我们在Java回顾之反射中已经设计了一个简单的AOP框架,通常情况下,对于AOP,我们有两种方式来实现。

  使用DynamicProxy实现AOP

  下面是一个简单的示例,首先定义业务对象:

 1 public interface UserDao {
2
3 void save();
4 }
5
6 public class UserDaoImpl implements UserDao
7 {
8 private String name;
9
10 public void save() {
11 System.out.println("save() is called for " + name);
12 }
13
14 public void setName(String name) {
15 this.name = name;
16 }
17
18 public String getName() {
19 return name;
20 }
21 }

  下面是一个实现了InvocationHandler的类:

 1 public class ProxyFactory implements InvocationHandler
2 {
3 private Object target;
4
5 public Object createUserDao(Object target)
6 {
7 this.target = target;
8 return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
9 this.target.getClass().getInterfaces(), this);
10 }
11
12 public Object invoke(Object proxy, Method method, Object[] args)
13 throws Throwable {
14
15 UserDaoImpl userDao = (UserDaoImpl)target;
16 Object result = null;
17 if(userDao.getName() != null)
18 {
19 result = method.invoke(target, args);
20 }
21 else
22 {
23 System.out.println("The name is null.");
24 }
25 return result;
26 }
27 }

  接下来是测试代码:

1 private static void test1()
2 {
3 ProxyFactory pf = new ProxyFactory();
4 UserDao userDao = (UserDao)pf.createUserDao(new UserDaoImpl());
5 userDao.save();
6 }

  执行结果如下:

The name is null.

  这是因为userDao的类型是UserDao,它是一个接口,并没有定义name字段,因此name=null。

  使用Cglib实现AOP

  同样是上面的需求,我们假设并没有继承的接口,这我们可以使用cglib来实现。

  首先我们重新定义一个UserDaoImpl2,它不会实现任何接口:

 1 public class UserDaoImpl2
2 {
3 private String name;
4
5 public void save() throws InterruptedException {
6 Thread.sleep(3000);
7 System.out.println("save() is called for " + name);
8 }
9
10 public void setName(String name) {
11 this.name = name;
12 }
13
14 public String getName() {
15 return name;
16 }
17
18 public void raiseException()
19 {
20 throw new RuntimeException("This is test.");
21 }
22 }

  然后是创建CglibFactory:

 1 public class CglibFactory implements MethodInterceptor
2 {
3 private Object target;
4 public Object createUserDao(Object target)
5 {
6 this.target = target;
7 Enhancer enhancer = new Enhancer();
8 enhancer.setSuperclass(target.getClass());
9 enhancer.setCallback(this);
10 return enhancer.create();
11 }
12
13 public Object intercept(Object proxy, Method method, Object[] args,
14 MethodProxy methodProxy) throws Throwable {
15 UserDaoImpl2 userDao = (UserDaoImpl2)target;
16 if (userDao.getName() != null)
17 {
18 return method.invoke(target, args);
19 }
20 else
21 {
22 System.out.println("The name is null.");
23 }
24 return null;
25 }
26 }

  它实现了MethodInterceptor接口,其中包括intercept方法,这个方法就会通过反射的方式来触发目标方法,同时还可以添加一些其他处理。

  下面是测试方法:

 1 private static void test2() throws InterruptedException
2 {
3 CglibFactory cf = new CglibFactory();
4 UserDaoImpl2 temp = new UserDaoImpl2();
5 UserDaoImpl2 userDao = (UserDaoImpl2)cf.createUserDao(temp);
6 userDao.save();
7 temp.setName("Zhang San");
8 userDao = (UserDaoImpl2)cf.createUserDao(temp);
9 userDao.save();
10 }

  输出结果如下:

The name is null.
save() is called for Zhang San

  使用Spring实现AOP

  Spring框架集合了ProxyFactory和Cglib两种方式来实现AOP。

  我们来看一个示例,还是使用上面定义的UserDaoImpl以及UserDaoImpl2。

  首先需要定义一个interceptor:

 1 @Aspect
2 public class MyInterceptor {
3
4 @Pointcut("execution (* sample.spring.aop.*.*(..))")
5 public void anyMethod(){}
6
7 @Before("anyMethod()")
8 public void before()
9 {
10 System.out.println("Before");
11 }
12
13 @After("anyMethod()")
14 public void after()
15 {
16 System.out.println("After");
17 }
18
19 @Around("anyMethod()")
20 public void Around(ProceedingJoinPoint pjp) throws Throwable
21 {
22 long start = System.currentTimeMillis();
23 pjp.proceed();
24 long end = System.currentTimeMillis();
25 System.out.println("执行时间:" + (end - start));
26 }
27
28 @Before("anyMethod() && args(name)")
29 public void before(String name)
30 {
31 System.out.println("The name is " + name);
32 }
33
34 @AfterReturning(pointcut="anyMethod()", returning="result")
35 public void afterReturning(String result)
36 {
37 System.out.println("The value is " + result);
38 }
39
40 @AfterThrowing(pointcut="anyMethod()", throwing="e")
41 public void afterThrowing(Exception e)
42 {
43 e.printStackTrace();
44 }
45 }

  我们可以看到上面的代码中包含了一些Annotation,这些Annotation是用来实现AOP的关键。

  然后需要修改beans.xml,添加如下内容:

1 <aop:aspectj-autoproxy />
2 <bean id="userDaoImpl" class = "sample.spring.aop.UserDaoImpl"/>
3 <bean id="userDaoImpl2" class = "sample.spring.aop.UserDaoImpl2"/>
4 <bean id="myInterceptor" class="sample.spring.aop.MyInterceptor"/>

  其中第一行是让Spring打开AOP的功能,下面三行定义了三个bean,这里我们把interceptor也看做是一个bean对象。

  接下来是测试代码:

 1 private static void test3() throws InterruptedException
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/aop/beans.xml");
4 UserDao userDao = (UserDao)ctx.getBean("userDaoImpl");
5 userDao.save();
6 UserDaoImpl2 userDao2 = (UserDaoImpl2)ctx.getBean("userDaoImpl2");
7 userDao2.save();
8 userDao2.setName("Zhang San");
9 String name = userDao2.getName();
10 // userDao2.raiseException();
11 }

  这里我们可以看到,测试方法中既使用了UserDaoImpl1(这里是UserDao接口),也是用了UserDaoImpl2。正如我们上面所言,在Spring中,如果类实现了接口,Spring会按照ProxyFactory的方式来处理;如果没有实现接口,Spring会按照Cglib的方式来处理。

  上面测试方法的输出如下:

Before
Before
save() is called for null
执行时间:1
The value is null
After
After
执行时间:1
The value is null
Before
Before
save() is called for null
执行时间:3001
The value is null
After
After
执行时间:3002
The value is null
Before
The name is Zhang San
Before
执行时间:26
The value is null
After
After
执行时间:27
The value is null
Before
Before
执行时间:0
The value is null
After
After
执行时间:1
The value is null

  使用Spring配置文件来配置AOP

  上面的示例中,我们使用Annotation来配置AOP的信息,同样我们也可以使用xml文件的方式来配置AOP。

  还是以上面定义的interceptor为基础,我们去掉里面所有的Annotation,然后在beans.xml中添加如下内容:

 1 <bean id="myInterceptor2" class="sample.spring.aop.MyInterceptor2"/>
2 <aop:config>
3 <aop:aspect id="asp" ref="myInterceptor2">
4 <aop:pointcut id="anyMethod" expression="execution (* sample.spring.aop.*.*(..))"/>
5 <aop:before pointcut-ref="anyMethod" method="before"/>
6 <aop:after pointcut-ref="anyMethod" method="after"/>
7 <aop:around pointcut-ref="anyMethod" method="around"/>
8 <aop:after-returning pointcut-ref="anyMethod" method="afterReturning" returning="result"/>
9 <aop:after-throwing pointcut-ref="anyMethod" method="afterThrowing" throwing="e"/>
10 </aop:aspect>
11 </aop:config>

  测试方法和输出结果同上。

  Spring和JDBC

  Spring中也包含了对JDBC数据访问的支持,它有一个JdbcTemplate的机制,其中提供了大量的API,对ResultSet进行了封装,可以大大简化我们的工作量。

  同时Spring还提供了针对事务的支持,包含了一些Annotation,既可以作用在类上,也可以作用在方法上。

  下面是一个简单的示例,我们还是连接MySQL数据库中的user表,实现对其CRUD操作。

  首先是定义业务对象以及DAO接口:

 1 public class User {
2
3 private int userID;
4 private String userName;
5 public void setUserID(int userID) {
6 this.userID = userID;
7 }
8 public int getUserID() {
9 return userID;
10 }
11 public void setUserName(String userName) {
12 this.userName = userName;
13 }
14 public String getUserName() {
15 return userName;
16 }
17 }
18
19 public interface UserDao {
20
21 void insertUser(User user);
22 void updateUser(User user);
23 void deleteUser(User user);
24 List<User> getAllUser();
25 User getUser(int id);
26 }

  然后是建立一个Dao的实现类,这里使用了一些JdbcTemplate API:

 1 @Transactional
2 public class UserDaoImpl implements UserDao
3 {
4 private JdbcTemplate jdbcTemplate;
5
6 public void setDataSource(DataSource dataSource) throws SQLException
7 {
8 jdbcTemplate = new JdbcTemplate(dataSource);
9 System.out.println(dataSource.getConnection().getMetaData().getDriverName());
10 }
11
12 public void deleteUser(User user) {
13 jdbcTemplate.update("delete from user where id=?",
14 new Object[]{user.getUserID()},
15 new int[]{java.sql.Types.INTEGER});
16 }
17
18 @SuppressWarnings("unchecked")
19 public List<User> getAllUser() {
20 return (List<User>)jdbcTemplate.query("select * from user",
21 new RowMapper()
22 {
23 public Object mapRow(ResultSet rs, int arg) throws SQLException
24 {
25 User user = new User();
26 user.setUserID(rs.getInt("ID"));
27 user.setUserName(rs.getString("NAME"));
28
29 return user;
30 }
31 });
32 }
33
34 public User getUser(int id) {
35 try
36 {
37 return (User)jdbcTemplate.queryForObject("select * from user where id=?",
38 new Object[]{id},
39 new int[]{java.sql.Types.INTEGER},
40 new RowMapper()
41 {
42 public Object mapRow(ResultSet rs, int arg) throws SQLException
43 {
44 User user = new User();
45 user.setUserID(rs.getInt("id"));
46 user.setUserName(rs.getString("name"));
47 return user;
48 }
49 });
50 }
51 catch(Exception ex)
52 {
53 System.out.println(ex.getMessage());
54 }
55 return null;
56
57 }
58
59 public void insertUser(User user) {
60 jdbcTemplate.update("insert into user (id,name) values(?,?)",
61 new Object[]{user.getUserID(), user.getUserName()},
62 new int[]{java.sql.Types.INTEGER, java.sql.Types.VARCHAR});
63 }
64
65 public void updateUser(User user) {
66 jdbcTemplate.update("update user set name=? where id=?",
67 new Object[]{user.getUserName(), user.getUserID()},
68 new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});
69 }
70
71 }

  JdbcTemplate还提供了一些其他的API,也非常实用。

  接下来需要修改beans.xml:

 1 <bean id="theDatasource"  class="org.apache.commons.dbcp.BasicDataSource">
2 <property name="driverClassName" value="com.mysql.jdbc.Driver" />
3 <property name="url" value="jdbc:mysql://localhost/test" />
4 <property name="username" value="root" />
5 <property name="password" value="123" />
6 <property name="initialSize" value="2" />
7 <property name="maxActive" value="100" />
8 <property name="maxIdle" value="2" />
9 <property name="minIdle" value="1" />
10 </bean>
11
12 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
13 <property name="dataSource" ref="theDatasource" />
14 </bean>
15
16 <tx:annotation-driven transaction-manager="txManager" />
17
18 <bean id="userDao" class="sample.spring.jdbc.UserDaoImpl">
19 <property name="dataSource" ref="theDatasource"/>
20 </bean>

  这里theDataSource用来配置数据库连接信息;txManager来配置事务管理器的信息;userDao是我们的Dao实现类信息。

  下面是测试方法:

 1 public static void test1()
2 {
3 ApplicationContext ctx = new ClassPathXmlApplicationContext("sample/spring/jdbc/beans.xml");
4 UserDao userDao = (UserDao)ctx.getBean("userDao");
5 System.out.println("=====get all user=====");
6 List<User> users = userDao.getAllUser();
7 for(User user:users)
8 {
9 System.out.println("ID:" + user.getUserID() + ";Name:" + user.getUserName());
10 }
11 System.out.println("=====insert user=====");
12 User user = new User();
13 user.setUserID(10);
14 user.setUserName("Zhang Fei");
15 userDao.insertUser(user);
16 user = userDao.getUser(10);
17 System.out.println("ID:" + user.getUserID() + ";Name:" + user.getUserName());
18 System.out.println("=====update user=====");
19 user.setUserName("Devil");
20 userDao.updateUser(user);
21 user = userDao.getUser(10);
22 System.out.println("ID:" + user.getUserID() + ";Name:" + user.getUserName());
23 System.out.println("=====delete user=====");
24 userDao.deleteUser(user);
25 user = userDao.getUser(10);
26 if (user == null)
27 {
28 System.out.println("delete successfully.");
29 }
30 }

  输出结果如下:

MySQL-AB JDBC Driver
=====get all user=====
ID:1;Name:Zhang San
ID:2;Name:TEST
=====insert user=====
ID:10;Name:Zhang Fei
=====update user=====
ID:10;Name:Devil
=====delete user=====
Incorrect result size: expected 1, actual 0
delete successfully.

  说到数据库事务,我们在上面的UserDaoImpl中可以看到,这个类的前面有一个名为@Transcational的Annotation声明,这是Spring实现事务的关键点,它既可以作用在类上,也可以作用在方法上。

  @Transactional包含以下参数:

  • propagation参数,Propagation类型(枚举),默认值为Propogation.REQUIRED,支持的值有REQUIRED、MANDATORY、NESTED、NEVER、NOT_SUPPORTED、REQUIRE_NEW、SUPPORTS。
  • isolation参数,Isolation类型(枚举),默认值为Isolation.DEFAULT,支持的值有DEFAULT、READ_COMMITTED、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE。
  • timeout参数,int类型,事务的超时时间,默认值为-1,即不会超时。
  • readOnly参数,boolean类型,true表示事务为只读,默认值为false。
  • rollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
  • rollbackForClassName参数,String[]类型,默认为空数组。
  • noRollbackFor参数,Class<? extends Throwable>[]类型,默认为空数组。
  • noRollbackForClassName参数,String[]类型,默认为空数组。
    

作者:李胜攀

    

 

Java回顾之Spring基础的更多相关文章

  1. java学习之spring基础

    0x00前言 spring框架应用的是ioc模式,ioc模式是指控制反转模式,本质是你不去创建对象让spring框架给你创建对象你去使用对象.多种开发模式通过配置文件和注解的方式去开发的都很值得去学习 ...

  2. Java回顾之一些基础概念

    类的初始化顺序 在Java中,类里面可能包含:静态变量,静态初始化块,成员变量,初始化块,构造函数.在类之间可能存在着继承关系,那么当我们实例化一个对象时,上述各部分的加载顺序是怎样的? 首先来看代码 ...

  3. Spring基础配置

    从毕业到现在我一直从事Android开发,但是对JavaEE一直念念不忘,毕业校招的时候,一个礼拜拿了三个offer,岗位分别是Android.JavaEE和JavaSE,后来觉得Android比较简 ...

  4. 第65节:Java后端的学习之Spring基础

    Java后端的学习之Spring基础 如果要学习spring,那么什么是框架,spring又是什么呢?学习spring中的ioc和bean,以及aop,IOC,Bean,AOP,(配置,注解,api) ...

  5. spring基础回顾

    1.什么是Spring框架?Spring框架有哪些主要模块? Spring框架是一个为Java应用程序的开发提供了综合.广泛的基础性支持的Java平台.Spring帮助开发者解决了开发中基础性的问题, ...

  6. Java 教程整理:基础、项目全都有

    Java 在编程语言排行榜中一直位列前排,可知 Java 语言的受欢迎程度了. 网上有很多 Java 教程,无论是基础入门还是开发小项目的教程都比比皆是,可是系统的很少,对于Java 学习者来说找到系 ...

  7. 初识轻量级Java开源框架 --- Spring

    初识轻量级Java开源框架 --- Spring 作者:egg 微博:http://weibo.com/xtfggef 出处:http://blog.csdn.net/zhangerqing spri ...

  8. 重拾Java Web应用的基础体系结构

    目录 一.背景 二.Web应用 2.1 HTML 2.2 HTTP 2.3 URL 2.4 Servlet 2.4.1 编写第一个Servlet程序 2.5 JSP 2.6 容器 2.7 URL映射到 ...

  9. Spring基础知识

    Spring基础知识 利用spring完成松耦合 接口 public interface IOutputGenerator { public void generateOutput(); } 实现类 ...

随机推荐

  1. 【HDU】4405 Aeroplane chess

    http://acm.hdu.edu.cn/showproblem.php?pid=4405 题意:每次可以走1~6格,初始化在第0格,走到>=n的格子就结束.还有m个传送门,表示可以从X[i] ...

  2. 【BZOJ】2157: 旅游

    http://www.lydsy.com/JudgeOnline/problem.php?id=2157 题解:裸lct不解释.. #include <bits/stdc++.h> usi ...

  3. jquery点击区域显示或隐藏DIV,点击非该DIV的地方隐藏该DIV

    <div class="Content_top"> <div class="Reserve"> <h3><span c ...

  4. 李洪强iOS经典面试题129

    1. 怎么解决缓存池满的问题(cell) ios中不存在缓存池满的情况,因为通常我们ios中开发,对象都是在需要的时候才会创建,有种常用的说话叫做懒加载,还有在UITableView中一般只会创建刚开 ...

  5. UML(一):类、接口、抽象类

    一.类之间的关系 1.继承(包括继承类+接口).聚合.组合.依赖.关联: 1.1 类图表示: 第一行:类名(如果是抽象类斜体) 第二行:特性(字段和属性) 第三行:操作(方法或行为) 操作和特性都分三 ...

  6. php课程---简单的分页练习

    在写代码时,我们可以用类来使代码更加方便简洁,下面是一个简单的查询分页练习 源代码: <html> <head> <style type="text/css&q ...

  7. C# 常用类

    一.Convert 主要用于数据类型的转换,常用的静态方法有: Convert.ToSingle():把数据转换为单精度浮点数,参数常为字符串 Convert.ToDouble():转为双精度浮点数 ...

  8. windows 精简/封装/部署

    给一个精简过的Windows7安装net35,提示自己到『打开或关闭Windows功能』里打开,然而发现并没有,只有一个ie9的功能.搜索尝试各种办法,显然都不行.用dism部署功能的工具,挂载一个完 ...

  9. python学习道路(day2note)(数据类型,运算符,字符串,列表)

    一,数据类型 1.1数字 数字分为int(整型),long(长整型),float(浮点型) 1.1.1 int整型的取值范围为 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31- ...

  10. smaller programs should improve performance

    COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION In this section, we l ...