Spring学习笔记
Spring学习笔记(
1
)----简单的实例
---------------------------------
首先需要准备Spring包,可从官方网站上下载。
下载解压后,必须的两个包是spring.jar和commons-logging.jar。此外为了便于测试加入了JUnit包。
在Myeclipse中创建Java项目。
编写一个接口类,为了简单,只加入了一个方法。
Java代码
1
.
package
com.szy.spring.interfacebean;
2
.
3
.
public
interface
PersonBean
4
.{
5
.
void
show();
6
.}
然后写一个类实现这个接口。
Java代码
1
.
package
com.szy.spring.implbean;
2
.
import
com.szy.spring.interfacebean.PersonBean;
3
.
4
.
public
class
UserBean
implements
PersonBean
5
.{
6
.
7
.
public
void
show()
8
. {
9
. System.out.println(
"Hello Kuka"
);
10
. }
11
.
12
.}
以上的过程我们再熟悉不过了,下面开始加入Spring的内容了。首先从下载的Sping包中找到配置文件,删除不需要的,找到最原始的部分:
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
.
10
.</beans>
我们在配置文件中加入我们的bean信息
Xml代码
1
.<bean id=
"userBean"
class
=
"com.szy.spring.implbean.UserBean"
/>
其中id作为标识符,
class
为类的包路径。
这样我们的配置文件就写好了,完整的配置文件呢如下。
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
.
10
. <bean id=
"userBean"
class
=
"com.szy.spring.implbean.UserBean"
/>
11
.</beans>
最后我们创建一个测试类测试:
Java代码
1
.
package
com.szy.spring.test;
2
.
3
.
import
org.junit.Test;
4
.
import
org.springframework.context.ApplicationContext;
5
.
import
org.springframework.context.support.ClassPathXmlApplicationContext;
6
.
import
com.szy.spring.interfacebean.PersonBean;
7
.
8
.
9
.
public
class
TestClass
10
.{
11
.
@Test
12
.
public
void
testMethod()
throws
Exception
13
. {
14
.
//读取配置文件
15
. ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
16
.
//获取UserBean的实例
17
. PersonBean bean=(PersonBean)ctx.getBean(
"userBean"
);
18
.
//调用方法
19
. bean.show();
20
. }
21
.}
运行,输入如下结果:
结果代码
1
.Hello Kuka
Ok,我们的第一个Spring程序成功运行。
Sping学习笔记(
2
)----实例化Bean的三种方式
-------------------------------------------
Spring的实例化Bean有三种方式:
使用类构造器直接实例化
使用静态工厂的方法实例化
使用实例工厂方法实例化
三种方式对应的配置如下
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <!-- 使用类构造器直接实例化 -->
10
. <bean id=
"userBean1"
class
=
"com.szy.spring.implbean.UserBean"
/>
11
. <!-- 使用静态工厂的方法实例化 -->
12
. <bean id=
"userBean2"
class
=
"com.szy.spring.factory.BeanFactory"
factory-method=
"UserBeanService"
/>
13
. <!-- 使用实例工厂方法实例化 -->
14
. <bean id=
"factory"
class
=
"com.szy.spring.factory.BeanFactory"
/>
15
. <bean id=
"userBean3"
factory-bean=
"factory"
factory-method=
"getUserBeanService"
/>
16
.</beans>
其中BeanFactory类的代码如下
Java代码
1
.
package
com.szy.spring.factory;
2
.
3
.
import
com.szy.spring.implbean.UserBean;
4
.
import
com.szy.spring.interfacebean.PersonBean;
5
.
6
.
public
class
BeanFactory
7
.{
8
.
//使用静态工厂的方法实例化使用
9
.
public
static
PersonBean UserBeanService()
10
. {
11
.
return
new
UserBean();
12
. }
13
.
14
.
public
PersonBean getUserBeanService()
15
. {
16
.
return
new
UserBean();
17
. }
18
.}
在这三种方式中我们最常用的还是第一种。
Spring学习笔记(
3
)----编码剖析Spring管理Bean的原理
--------------------------------------------------
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"userBean"
class
=
"com.szy.spring.implbean.UserBean"
/>
10
.</beans>
Spring的配置文件中记录了类的包路径,因此我们首先是要读入配置文件。在配置文件中Bean有id和
class
两个属性,我们首先定义一个Bean类,包含这两个属性:
Java代码
1
.
package
com.szy.spring.implbean;
2
.
3
.
public
class
Bean
4
.{
5
.
private
String id;
6
.
private
String className;
7
.
public
String getId()
8
. {
9
.
return
id;
10
. }
11
.
public
void
setId(String id)
12
. {
13
.
this
.id = id;
14
. }
15
.
public
String getClassName()
16
. {
17
.
return
className;
18
. }
19
.
public
void
setClassName(String className)
20
. {
21
.
this
.className = className;
22
. }
23
.
24
.}
25
.
由于配置文件是xml文件,在这里使用Jdom包操作xml文件,读入配置文件中的Bean信息。
Java代码
1
.
/**
2. * 读取xml配置文件
3. * @param fileName 配置文件名
4. */
5
.
private
void
readXML(String fileName)
6
. {
7
.
// 寻找配置文件
8
. URL xmlPath =
this
.getClass().getClassLoader().getResource(fileName);
9
. Document doc =
null
;
10
. Element root =
null
;
11
.
try
12
. {
13
. SAXBuilder sb =
new
SAXBuilder(
false
);
14
. doc = sb.build(
new
FileInputStream(
new
File(xmlPath.toURI())));
15
.
// 设置命名空间
16
. Namespace xhtml = Namespace.getNamespace(
"xhtml"
,
17
.
"http://www.springframework.org/schema/beans"
);
18
. root = doc.getRootElement();
// 获取根元素
19
. List<Element> list = root.getChildren(
"bean"
, xhtml);
//获取全部bean节点
20
.
for
(Element element : list)
// 遍历节点,取得每个节点的属性
21
. {
22
. String id = element.getAttributeValue(
"id"
);
23
. String className = element.getAttributeValue(
"class"
);
24
. Bean bean =
new
Bean();
25
. bean.setId(id);
26
. bean.setClassName(className);
27
. beanList.add(bean);
28
. }
29
. }
catch
(Exception e)
30
. {
31
. e.printStackTrace();
32
. }
33
.
34
. }
其中beanList是一个List对象,因为在配置文件中存在很多Bean。
得到了所有的Bean对象后,下面就实例化每个Bean对象,结果存放在Map对象中。
Java代码
1
.
/**
2. * bean的实例化
3. */
4
.
private
void
instanceBeans()
5
. {
6
.
for
(Bean bean : beanList)
7
. {
8
.
try
9
. {
10
.
if
(bean.getClassName() !=
null
&& !
""
.equals(bean.getClassName().trim()))
11
. beanObject.put(bean.getId(), Class.forName(bean.getClassName()).newInstance());
12
. }
catch
(Exception e)
13
. {
14
. e.printStackTrace();
15
. }
16
. }
17
.
18
. }
其中beanObject为Map对象。
最后再加入一个方法,方便外部能获取Map中的对象
Java代码
1
.
/**
2. * 获取bean实例
3. * @param beanName 配置文件中bean的Id
4. * @return
5. */
6
.
public
Object getBean(String beanName)
7
. {
8
.
return
this
.beanObject.get(beanName);
9
. }
完整的MyClassPathXMLApplicationContext见附件中的代码。
下面测试MyClassPathXMLApplicationContext类。
Java代码
1
.
@Test
2
.
public
void
testMethod()
throws
Exception
3
. {
4
.
//读取配置文件
5
. MyClassPathXMLApplicationContext ctx=
new
MyClassPathXMLApplicationContext(
"applicationContext.xml"
);
6
.
//获取UserBean的实例
7
. PersonBean bean=(PersonBean)ctx.getBean(
"userBean"
);
8
.
//调用方法
9
. bean.show();
10
. }
输出结果
结果代码
1
.Hello Kuka
成功。
上面仅是简单的演示了Spring管理Bean的原理,但是在实际操作中还需要考虑很对其它因素。
Spring学习笔记(
4
)----Bean节点信息配置
---------------------------------------
默认情况下,Spring的Ioc容器启动时会初始化bean,但是我们可以指定Bean节点的lazy-init=
"true"
,来延迟初始化bean。这时候,只有第一次获取bean才会初始化bean。如
Xml代码
1
.<bean id=
"userBean"
class
=
"com.szy.spring.implbean.UserBean"
lazy-init=
"true"
/>
如果想对所有的bean有应用延迟初始化,可以在跟节点beans设置
default
-lazy-init=
"true"
,如下:
Xml代码
1
.<beans
default
-lazy-init=
"true"
....>
此外,如果我们还想UserBean在实例化是调用初始化方法时,我们可以加入“init-method=
"init"
”属性,其中init为Userbean中的init()方法,与之对应,“destroy-method=
"destroy"
”为销毁属性。
在Spring中我们通过getBean(name)方法获得实例,那么我们每次获取的实例化对象是一个还是多个呢?
我们可以通过“==”进行测试
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
.PersonBean bean1=(PersonBean)ctx.getBean(
"userBean"
);
3
.PersonBean bean2=(PersonBean)ctx.getBean(
"userBean"
);
4
.System.out.println(bean1==bean2);
运行输出结果为:
true
这说明了Bean交给sping容器管理之后,Bean默认情况下是单实例的。
如果我们想每次通过getBean(name)方法获得实例是一个新的实例化对象该怎么办呢?
在配置文件中节点bean有一个属性scope,只要我们配置如下即可:
Xml代码
1
.<bean id=
"userBean"
class
=
"com.szy.spring.implbean.UserBean"
scope=
"prototype"
/>
在运行测试代码,输出结果为:
false
Spring学习笔记(
5
)----依赖注入的简单实现
-----------------------------------------
Spring的核心机制是依赖注入。依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。
下面通过简单的实例演示依赖注入。
项目中主要包含一下一个文件:
UserDAO是一个接口,包含了一个方法:
Java代码
1
.
package
com.szy.spring.dao;
2
.
3
.
public
interface
UserDAO
4
.{
5
.
void
show();
6
.}
而UserDAO4MySqlImpl和UserDAO4OracleImpl实现了UserDAO中的方法。
Java代码
1
.
package
com.szy.spring.dao;
2
.
public
class
UserDAO4MySqlImpl
implements
UserDAO
3
.{
4
.
public
void
show()
5
. {
6
. System.out.println(
"MySqlDAO Implement"
);
7
. }
8
.}
Java代码
1
.
package
com.szy.spring.dao;
2
.
public
class
UserDAO4OracleImpl
implements
UserDAO
3
.{
4
.
public
void
show()
5
. {
6
. System.out.println(
"OracleDAO Implement"
);
7
. }
8
.}
UserService是另外一个包中的接口,
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
public
interface
UserService
4
.{
5
.
void
show();
6
.}
UserServiceImpl实现了这个接口,
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
com.szy.spring.dao.UserDAO;
4
.
5
.
public
class
UserServiceImpl
implements
UserService
6
.{
7
.
private
UserDAO userDAO;
8
.
9
.
public
void
show()
10
. {
11
. userDAO.show();
12
. }
13
.
14
.
public
UserDAO getUserDAO()
15
. {
16
.
return
userDAO;
17
. }
18
.
public
void
setUserDAO(UserDAO userDAO)
19
. {
20
.
this
.userDAO = userDAO;
21
. }
22
.}
但是在实现这个接口中,调用了UserDAO中的方法。一般情况下我们需要在这里实例化一个UserDAO对象,比如
Java代码
1
.UserDAO userDAO=
new
UserDAO4MySqlImpl();
这样的话耦合度就比较高,通过spring我们可以降低耦合度。
在Sping的配置文件中,我们需要这样配置
Java代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"mySqlDAO"
class
=
"com.szy.spring.dao.UserDAO4MySqlImpl"
/>
10
. <bean id=
"oracleDAO"
class
=
"com.szy.spring.dao.UserDAO4OracleImpl"
/>
11
. <bean id=
"userService"
class
=
"com.szy.spring.service.UserServiceImpl"
>
12
. <!--构造方法注入
13
. <property name=
"userDAO"
ref=
"mySqlDAO"
></property>
14
. -->
15
. <property name=
"userDAO"
ref=
"oracleDAO"
></property>
16
. </bean>
17
.</beans>
下面我们测试
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. UserService service=(UserService)ctx.getBean(
"userService"
);
3
. service.show();
输入内容为
输出代码
1
.OracleDAO Implement
如果我们想实用Mysql数据库呢?
此时我们只要修改配置文件即可,而不需要修改Java文件。
Xml代码
1
.<property name=
"userDAO"
ref=
"mySqlDAO"
></property>
Spring学习笔记(
6
)----编码剖析Spring依赖注入的原理
---------------------------------------------------
在Spring学习笔记(
3
)中剖析了Spring管理Bean的原理,下面解释下Spring依赖注入的原理
在进行依赖注入时,我们的配置文件如下配置:
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"mySqlDAO"
class
=
"com.szy.spring.dao.UserDAO4MySqlImpl"
/>
10
. <bean id=
"oracleDAO"
class
=
"com.szy.spring.dao.UserDAO4OracleImpl"
/>
11
. <bean id=
"userService"
class
=
"com.szy.spring.service.UserServiceImpl"
>
12
. <!--构造方法注入
13
. <property name=
"userDAO"
ref=
"mySqlDAO"
></property>
14
. -->
15
. <property name=
"userDAO"
ref=
"oracleDAO"
></property>
16
. </bean>
17
.</beans>
根据配置文件信息,我们首先需要建立一个Bean类,用来保存bean节点的信息:
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
import
java.util.List;
4
.
5
.
public
class
Bean
6
.{
7
.
private
String id;
8
.
private
String className;
9
.
private
List<Property> propertyList;
10
.
public
Bean(String id, String className, List<Property> propertyList)
11
. {
12
.
super
();
13
.
this
.id = id;
14
.
this
.className = className;
15
.
this
.propertyList = propertyList;
16
. }
17
.
public
String getId()
18
. {
19
.
return
id;
20
. }
21
.
public
void
setId(String id)
22
. {
23
.
this
.id = id;
24
. }
25
.
public
String getClassName()
26
. {
27
.
return
className;
28
. }
29
.
public
void
setClassName(String className)
30
. {
31
.
this
.className = className;
32
. }
33
.
public
List<Property> getPropertyList()
34
. {
35
.
return
propertyList;
36
. }
37
.
public
void
setPropertyList(List<Property> propertyList)
38
. {
39
.
this
.propertyList = propertyList;
40
. }
41
.}
此外,由于bean下存在property信息,因此我们还需要建立property类
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Property
4
.{
5
.
private
String name;
6
.
private
String ref;
7
.
8
.
public
Property(String name, String ref)
9
. {
10
.
super
();
11
.
this
.name = name;
12
.
this
.ref = ref;
13
. }
14
.
public
String getName()
15
. {
16
.
return
name;
17
. }
18
.
public
void
setName(String name)
19
. {
20
.
this
.name = name;
21
. }
22
.
public
String getRef()
23
. {
24
.
return
ref;
25
. }
26
.
public
void
setRef(String ref)
27
. {
28
.
this
.ref = ref;
29
. }
30
.
31
.}
在Spring学习笔记(
3
)中,我们在读取xml文件时bean节点下面是不存在property节点的,因此在这里我们需要修改readXML()方法:
Java代码
1
.
/**
2. * 读取xml配置文件
3. * @param fileName 配置文件名
4. */
5
.
private
void
readXML(String fileName)
6
. {
7
.
// 寻找配置文件
8
. URL xmlPath =
this
.getClass().getClassLoader().getResource(fileName);
9
. Document doc =
null
;
10
. Element root =
null
;
11
.
try
12
. {
13
. SAXBuilder sb =
new
SAXBuilder(
false
);
14
. doc = sb.build(
new
FileInputStream(
new
File(xmlPath.toURI())));
15
.
// 设置命名空间
16
. Namespace xhtml = Namespace.getNamespace(
"xhtml"
,
17
.
"http://www.springframework.org/schema/beans"
);
18
. root = doc.getRootElement();
// 获取根元素
19
. List<Element> bList = root.getChildren(
"bean"
, xhtml);
//获取全部bean节点
20
.
for
(Element beanElement : bList)
// 遍历节点,取得每个节点的属性
21
. {
22
. String id = beanElement.getAttributeValue(
"id"
);
23
. String className = beanElement.getAttributeValue(
"class"
);
24
.
//获得每个bean下面的属性
25
. List<Element> pList = beanElement
26
. .getChildren(
"property"
, xhtml);
27
. List<Property> propertyList =
new
ArrayList<Property>();
//存储属性信息
28
.
if
(pList.size() >
0
)
//如果存在属性
29
. {
30
.
for
(Element propertyElement : pList)
//遍历属性节点
31
. {
32
. String name = propertyElement.getAttributeValue(
"name"
);
33
. String ref = propertyElement.getAttributeValue(
"ref"
);
34
. Property property =
new
Property(name, ref);
35
. propertyList.add(property);
//保存属性节点
36
. }
37
. }
38
. Bean bean =
new
Bean(id, className, propertyList);
39
. beanList.add(bean);
40
. }
41
.
42
. }
catch
(Exception e)
43
. {
44
. e.printStackTrace();
45
. }
46
. }
读取完配置文件后我们还是需要对bean进行实例化的,这方法和Spring学习笔记(
3
)中的instanceBeans()方法一样。下面就是我们需要给bean属性进行注入,实现方法如下:
Java代码
1
.
/**
2. * 为bean对象的属性注入值
3. */
4
.
public
void
injectObject()
5
. {
6
.
for
(Bean bean : beanList)
7
. {
8
. Object object = beanObject.get(bean.getId());
//获取bean的实例
9
.
if
(object !=
null
)
10
. {
11
.
try
12
. {
13
. PropertyDescriptor[] ps = Introspector.getBeanInfo(
14
. object.getClass()).getPropertyDescriptors();
//取得bean的属性描述
15
.
for
(Property property : bean.getPropertyList())
//获取bean节点的属性
16
. {
17
.
for
(PropertyDescriptor properdesc : ps)
18
. {
19
.
if
(property.getName().equals(properdesc.getName()))
20
. {
21
. Method setter = properdesc.getWriteMethod();
//获取属性的setter方法 ,private
22
.
if
(setter !=
null
)
23
. {
24
. Object value = beanObject.get(property.getRef());
//取得值
25
. setter.setAccessible(
true
);
//设置为允许访问
26
. setter.invoke(object, value);
//把引用对象注入到属性
27
. }
28
.
break
;
29
. }
30
. }
31
. }
32
. }
catch
(Exception e)
33
. {
34
. e.printStackTrace();
35
. }
36
. }
37
. }
我们进行测试:
Java代码
1
.MyClassPathXMLApplicationContext ctx=
new
MyClassPathXMLApplicationContext(
"applicationContext.xml"
);
2
. UserService service=(UserService)ctx.getBean(
"userService"
);
3
. service.show();
运行输出
结果代码
1
.OracleDAO Implement
上面仅是简单的演示了Spring依赖注入的原理,但是Spring学习笔记(
7
)----装配各种集合类型的属性在实际操作中还需要考虑很对其它因素,在此就不进行讨论了。
Spring学习笔记(
7
)----装配各种集合类型的属性
---------------------------------------------
前面已经介绍了如何给属性注入对象,下面介绍一下如何装配集合类型的属性
1
.Set类型
Java代码
1
.
private
Set<String> sets=
new
HashSet<String>();
2
.
//我们需要给它添加set方法
3
.
public
Set<String> getSets()
4
. {
5
.
return
sets;
6
. }
7
.
public
void
setSets(Set<String> sets)
8
. {
9
.
this
.sets = sets;
10
. }
11
.
public
Set<String> showSet()
12
. {
13
.
return
sets;
14
. }
然后根据属性修改配置文件
Xml代码
1
.<bean id=
"userService"
class
=
"com.szy.spring.service.UserServiceImpl"
>
2
. <property name=
"sets"
>
3
. <set>
4
. <value>Set1</value>
5
. <value>Set2</value>
6
. <value>Set3</value>
7
. </set>
8
. </property>
9
.
10
.</bean>
与以前不同的是我们在property下面添加了<set></set>
这样就能装配set类型的属性
2
.List类型
List类型的属性和Set类型的方法一样,主要是把配置文件中的set修改成list。
Java代码
1
.
private
List<String> lists=
new
ArrayList<String>();
2
.
public
List<String> getLists()
3
. {
4
.
return
lists;
5
. }
6
.
public
void
setLists(List<String> lists)
7
. {
8
.
this
.lists = lists;
9
. }
10
.
public
List<String> showList()
11
. {
12
.
return
lists;
13
. }
配置文件修改如下
Xml代码
1
.<bean id=
"userService"
class
=
"com.szy.spring.service.UserServiceImpl"
>
2
.<property name=
"lists"
>
3
. <list>
4
. <value>List1</value>
5
. <value>List2</value>
6
. <value>List3</value>
7
. </list>
8
. </property>
9
. </bean>
3
.Properties类型
Java代码
1
.
private
Properties properties=
new
Properties();
2
.
public
void
setProperties(Properties properties)
3
. {
4
.
this
.properties = properties;
5
. }
6
.
public
Properties getProperties()
7
. {
8
.
return
properties;
9
. }
10
.
public
Properties showProperties()
11
. {
12
.
return
properties;
13
. }
配置文件需要如下配置
Xml代码
1
.<bean id=
"userService"
class
=
"com.szy.spring.service.UserServiceImpl"
>
2
.<property name=
"properties"
>
3
. <props>
4
. <prop key=
"key1"
>Properties1</prop>
5
. <prop key=
"key2"
>Properties2</prop>
6
. <prop key=
"key3"
>Properties3</prop>
7
. </props>
8
. </property>
9
. </bean>
10
.
4
.Map类型
Java代码
1
.
private
Map<String, String> maps=
new
HashMap<String, String>();
2
.
public
List<String> getLists()
3
. {
4
.
return
lists;
5
. }
6
.
public
void
setLists(List<String> lists)
7
. {
8
.
this
.lists = lists;
9
. }
10
.
public
Map<String, String> showMaps()
11
. {
12
.
return
maps;
13
. }
配置文件做相应的配置
Xml代码
1
.<bean id=
"userService"
class
=
"com.szy.spring.service.UserServiceImpl"
>
2
.lt;property name=
"maps"
>
3
. <map>
4
. <entry key=
"key1"
value=
"Map1"
></entry>
5
. <entry key=
"key2"
value=
"Map2"
></entry>
6
. <entry key=
"key3"
value=
"Map3"
></entry>
7
. </map>
8
. </property>
9
.</bean>
这样就完成了对Map类型的属性进行装配。
Spring学习笔记(
8
)----属性注入的方式
--------------------------------------
Spring中属性注入的方式有三种:
1
.使用属性setter方法注入
2
.使用构造器注入
3
.使用注解方式注入
使用属性setter方法注入
使用属性setter方法注入就是给属性添加set()方法,在前面都是使用这种方法。
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
com.szy.spring.dao.PersonDao;
4
.
5
.
public
class
UserServiceImplBySetter
implements
UserService
6
.{
7
.
private
PersonDao personDao;
8
.
9
.
public
void
show()
10
. {
11
. personDao.show();
12
. }
13
.
public
PersonDao getPersonDao()
14
. {
15
.
return
personDao;
16
. }
17
.
public
void
setPersonDao(PersonDao personDao)
18
. {
19
.
this
.personDao = personDao;
20
. }
21
.}
然后在配置文件中如下配置
Xml代码
1
.<bean id=
"personDao"
class
=
"com.szy.spring.dao.PersonDaoBean"
/>
2
. <!-- 使用属性Setter方法注入配置 -->
3
. <bean id=
"userService1"
class
=
"com.szy.spring.service.UserServiceImplBySetter"
>
4
. <property name=
"personDao"
ref=
"personDao"
></property>
5
. </bean>
使用构造器注入
使用构造器注入就是在类中添加含参构造函数
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
com.szy.spring.dao.PersonDao;
4
.
5
.
public
class
UserServiceImplConstructor
implements
UserService
6
.{
7
.
private
PersonDao personDao;
8
.
private
String name;
9
.
10
.
public
UserServiceImplConstructor()
11
. {
12
. }
13
.
14
.
public
UserServiceImplConstructor(PersonDao personDao, String name)
15
. {
16
.
this
.personDao = personDao;
17
.
this
.name = name;
18
. }
19
.
20
.
public
void
show()
21
. {
22
. personDao.show();
23
. System.out.println(
"name属性:"
+name);
24
. }
25
.}
下面就是在配置文件中添加配置信息,给每个参数注入值
Xml代码
1
.<bean id=
"personDao"
class
=
"com.szy.spring.dao.PersonDaoBean"
/>
2
. <!-- 使用构造器参数方法注入配置 -->
3
. <bean id=
"userService2"
class
=
"com.szy.spring.service.UserServiceImplConstructor"
>
4
. <constructor-arg index=
"0"
type=
"com.szy.spring.dao.PersonDao"
ref=
"personDao"
/>
5
. <constructor-arg index=
"1"
value=
"Kuka"
/>
6
. </bean>
注意:constructor-arg index是从
0
开始的
使用注解方式注入
如果使用前面的两种方法,配置文件将会显得很臃肿,因此我们可以使用注解的方式注入,使用注解方式注入有两种方法,第一种使用javax.annotation.Resource中提供的注解方式方法如下:
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
javax.annotation.Resource;
4
.
5
.
import
com.szy.spring.dao.PersonDao;
6
.
7
.
public
class
UserServiceImplByAnnotation4Resource
implements
UserService
8
.{
9
.
//@Resource默认是按照名称装配,找不到与名称匹配的bean时按类型装配
10
.
@Resource
(name=
"personDao"
)
private
PersonDao personDao;
11
.
12
.
public
void
show()
13
. {
14
. personDao.show();
15
. }
16
.
// 下面方法同样可以
17
.
// @Resource
18
.
// public void setPersonDao(PersonDao personDao)
19
.
// {
20
.
// this.personDao = personDao;
21
.
// }
22
.
23
.}
此时配置文件要做相应的改变
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
8
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
9
. <context:annotation-config/>
10
. <bean id=
"personDao"
class
=
"com.szy.spring.dao.PersonDaoBean"
/>
11
. <bean id=
"userService"
class
=
"com.szy.spring.service.UserServiceImplByAnnotation4Autowired"
>
12
. </bean>
13
.</beans>
注意添加这句配置信息
<context:annotation-config/>
第二中方式就是使用spring提供的注解方式
org.springframework.beans.factory.annotation.Autowired;
注入使用时需要导入spring目录lib\j2ee\common-annotations.jar这个包
使用方法如下:
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
org.springframework.beans.factory.annotation.Autowired;
4
.
import
org.springframework.beans.factory.annotation.Qualifier;
5
.
6
.
import
com.szy.spring.dao.PersonDao;
7
.
8
.
public
class
UserServiceImplByAnnotation4Autowired
implements
UserService
9
.{
10
.
//@Autowired默认使用类型进行装配,
11
.
@Autowired
private
PersonDao personDao;
12
.
// 如果使用按名称进行装配,则需要如下
13
.
// @Autowired @Qualifier("personDao")private PersonDao personDao;
14
.
public
void
show()
15
. {
16
. personDao.show();
17
. }
18
.
19
.}
配置文件和上面一样。
在使用时建议使用
@Resource
,因为
@Resource
不依赖于spring框架。
Spring学习笔记(
9
)----让Spring自动扫描和管理Bean
-------------------------------------------------
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
org.springframework.stereotype.Service;
4
.
5
.
import
com.szy.spring.dao.PersonDao;
6
.
@Service
(
"service"
)
7
.
public
class
UserServiceImpl
implements
UserService
8
.{
9
.
private
PersonDao personDaoBean;
10
.
11
.
public
void
show()
12
. {
13
. personDaoBean.show();
14
. }
15
.
16
.
public
void
setPersonDaoBean(PersonDao personDaoBean)
17
. {
18
.
this
.personDaoBean = personDaoBean;
19
. }
20
.}
在前面的例子中,都是使用XML的bean定义来使用组件,在大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会使配置文件显得很臃肿,查找和维护起来不方便。Spring2.
5
为我们引入了组件自动扫描机制,它可以在类路径下寻找标记了
@Component
、
@Service
、
@Controller
、
@Repository
注解的类,并把这些类纳入到spring容器中管理,它的作用和在xml中使用bean节点配置组件一样。要使用自动扫描机制,我们需要把配置文件如下配置:
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <context:component-scan base-
package
=
"com.szy.spring"
></context:component-scan>
10
.</beans>
其中base-
package
为需要扫描的包(包括子包)
@Service
用于标注业务层的组件,
@Controller
用于标注控制层组件(如struts中的action),
@Repository
用于标注数据访问组件,即DAO组件,而
@Component
泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。但是在目前的spring版本中,这几个注解的作用是一样的,但是在以后可能会进行区分。
下面把先前的例子修改一下:
首先是PersonDaoBean类,修改如下
Java代码
1
.
package
com.szy.spring.dao;
2
.
3
.
import
org.springframework.stereotype.Repository;
4
.
5
.
@Repository
6
.
//告诉spring这个类要交给spring管理,
7
.
public
class
PersonDaoBean
implements
PersonDao
8
.{
9
.
public
void
show()
10
. {
11
. System.out.println(
"执行PersonDaoBean中的add()方法"
);
12
. }
13
.}
然后是UserServiceImpl类
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
org.springframework.stereotype.Service;
4
.
5
.
import
com.szy.spring.dao.PersonDao;
6
.
@Service
7
.
//把这个类交给spring管理,作为服务了。
8
.
public
class
UserServiceImpl
implements
UserService
9
.{
10
.
private
PersonDao personDaoBean;
11
.
12
.
public
void
show()
13
. {
14
. personDaoBean.show();
15
. }
16
.
17
.
public
void
setPersonDaoBean(PersonDao personDaoBean)
18
. {
19
.
this
.personDaoBean = personDaoBean;
20
. }
21
.
22
.
public
PersonDao getPersonDaoBean()
23
. {
24
.
return
personDaoBean;
25
. }
26
.}
下面我们进行测试,原来的测试代码是userServiceImpl
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. UserService service=(UserService)ctx.getBean(
"userService"
);
3
. service.show();
其中userService是我们在配置文件中配置的bean的id。但是如今我们并没有id这个属性,在spring2.
5
中,默认的id是类的名称,但是开后是小写,也就是userServiceImpl,因此测试代码应修改如下:
Java代码
1
.AbstractApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. UserService service=(UserService)ctx.getBean(
"userServiceImpl"
);
3
. System.out.println(service);
如果我们想自己命名的话,则只需在注解后加上括号,里面写入你希望的名字,如
@Service
(
"userService"
)。
在spring中默认的是之生成一个bean实例,如果我们想每次调用都产生一个实例,则标注需如下配置
@Service
@Scope
(
"prototype"
)
在xml中我们还可以配置初始化方法和销毁方法,使用标注后只需如下标注
Java代码
1
.
@PostConstruct
2
.
public
void
init()
3
. {
4
. System.out.println(
"初始化"
);
5
. }
6
.
@PreDestroy
7
.
public
void
destory()
8
. {
9
. System.out.println(
"销毁"
);
10
. }
使用注解后,我们的xml文件变得十分简单,因此建议Spring学习笔记(
10
)----公共属性的注入配置大家在以后的开发中使用注解。
Spring学习笔记(
10
)----公共属性的注入配置
-------------------------------------------
假设我们定义了四个bean类,其代码分别如下:
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean1 {
4
.
private
Bean2 bean2;
5
.
private
Bean3 bean3;
6
.
private
Bean4 bean4;
7
.
8
.
public
Bean2 getBean2()
9
. {
10
.
return
bean2;
11
. }
12
.
public
void
setBean2(Bean2 bean2)
13
. {
14
.
this
.bean2 = bean2;
15
. }
16
.
public
Bean3 getBean3()
17
. {
18
.
return
bean3;
19
. }
20
.
public
void
setBean3(Bean3 bean3)
21
. {
22
.
this
.bean3 = bean3;
23
. }
24
.
public
Bean4 getBean4()
25
. {
26
.
return
bean4;
27
. }
28
.
public
void
setBean4(Bean4 bean4)
29
. {
30
.
this
.bean4 = bean4;
31
. }
32
.}
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean2
4
.{
5
.
private
int
id;
6
.
private
String name;
7
.
private
String password;
8
.
9
.
public
int
getId()
10
. {
11
.
return
id;
12
. }
13
.
public
void
setId(
int
id)
14
. {
15
.
this
.id = id;
16
. }
17
.
public
String getName()
18
. {
19
.
return
name;
20
. }
21
.
public
void
setName(String name)
22
. {
23
.
this
.name = name;
24
. }
25
.
public
String getPassword()
26
. {
27
.
return
password;
28
. }
29
.
public
void
setPassword(String password)
30
. {
31
.
this
.password = password;
32
. }
33
.}
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean3
4
.{
5
.
private
int
id;
6
.
private
String name;
7
.
8
.
public
int
getId()
9
. {
10
.
return
id;
11
. }
12
.
public
void
setId(
int
id)
13
. {
14
.
this
.id = id;
15
. }
16
.
public
String getName()
17
. {
18
.
return
name;
19
. }
20
.
public
void
setName(String name)
21
. {
22
.
this
.name = name;
23
. }
24
.}
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean4
4
.{
5
.
private
int
age;
6
.
7
.
public
int
getAge()
8
. {
9
.
return
age;
10
. }
11
.
public
void
setAge(
int
age)
12
. {
13
.
this
.age = age;
14
. }
15
.}
按照正常的思路,我们下面就要给每个类进行属性的注入,配置文件如下设置:
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"bean1"
class
=
"com.szy.spring.bean.Bean1"
>
10
. <property name=
"bean2"
ref=
"bean2"
/>
11
. <property name=
"bean3"
>
12
. <ref bean=
"bean3"
/>
13
. </property>
14
. <property name=
"bean4"
ref=
"bean4"
/>
15
. </bean>
16
.
17
. <bean id=
"bean2"
class
=
"com.szy.spring.bean.Bean2"
>
18
. <property name=
"id"
value=
"100"
/>
19
. <property name=
"name"
>
20
. <value>kuka</value>
21
. </property>
22
. <property name=
"password"
value=
"123"
/>
23
. </bean>
24
.
25
. <bean id=
"bean3"
class
=
"com.szy.spring.bean.Bean3"
>
26
. <property name=
"id"
value=
"100"
/>
27
. <property name=
"name"
value=
"kuka"
/>
28
. </bean>
29
.
30
. <bean id=
"bean4"
class
=
"com.szy.spring.bean.Bean4"
>
31
. <property name=
"age"
value=
"22"
/>
32
. </bean>
33
.</beans>
我们进行测试:
Java代码
1
.
@Test
2
.
public
void
testMethod()
throws
Exception
3
. {
4
. ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
5
. Bean1 bean1 = (Bean1)ctx.getBean(
"bean1"
);
6
.
7
. System.out.println(
"bean1.bean2.id="
+ bean1.getBean2().getId());
8
. System.out.println(
"bean1.bean2.name="
+ bean1.getBean2().getName());
9
. System.out.println(
"bean1.bean2.password="
+ bean1.getBean2().getPassword());
10
. System.out.println(
"bean1.bean3.id="
+ bean1.getBean3().getId());
11
. System.out.println(
"bean1.bean3.name="
+ bean1.getBean3().getName());
12
. System.out.println(
"bean1.bean4.age="
+ bean1.getBean4().getAge());
13
. }
正常输出我们所预期的信息,但是我们观察发现bean2和bean3的部分属性的配置信息是相同的,这仅是两个bean,如果是多个bean的话我们要修改就好修改多处,因此我们可以把这些公共的部分提出出来,进行抽象。这个在Spring中是支持的。我们在建立一个配置文件,命名为:applicationCommon.xml,其内容如下配置
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"beanAbstract"
abstract
=
"true"
>
10
. <property name=
"id"
value=
"100"
/>
11
. <property name=
"name"
value=
"kuka"
/>
12
. </bean>
13
.
14
. <bean id=
"bean2"
class
=
"com.szy.spring.bean.Bean2"
parent=
"beanAbstract"
>
15
. <property name=
"password"
value=
"123"
/>
16
. </bean>
17
.
18
. <bean id=
"bean3"
class
=
"com.szy.spring.bean.Bean3"
parent=
"beanAbstract"
/>
19
.
20
.</beans>
beanAbstract就是我们抽象出来的,设置
abstract
=
"true"
属性后就不需要指定
class
属性。
我们把原来配置文件里的关于bean2和bean3节点注释掉。
下面进行测试,在这里要注意由于我们使用了两个配置文件,因此我们在读取是要写两个配置文件名。我们查看ClassPathXmlApplicationContext源文件发现其有个构造函数参数是string数组,因此我们可以把这个配置文件名放在数组里面。此外我们还有另外一种实现方法,两个配置文件一个叫applicationContext.xml,另一个applicationCommon.xml,公共部分是applicationC*.xml,下面我们就可以这样进行测试:
Java代码
1
.
@Test
2
.
public
void
testMethod()
throws
Exception
3
. {
4
. ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationC*.xml"
);
5
. Bean1 bean1 = (Bean1)ctx.getBean(
"bean1"
);
6
.
7
. System.out.println(
"bean1.bean2.id="
+ bean1.getBean2().getId());
8
. System.out.println(
"bean1.bean2.name="
+ bean1.getBean2().getName());
9
. System.out.println(
"bean1.bean2.password="
+ bean1.getBean2().getPassword());
10
. System.out.println(
"bean1.bean3.id="
+ bean1.getBean3().getId());
11
. System.out.println(
"bean1.bean3.name="
+ bean1.getBean3().getName());
12
. System.out.println(
"bean1.bean4.age="
+ bean1.getBean4().getAge());
13
. }
如果我们bean2的name属性的值不是kuka,那么我们只需在applicationCommon.xml文件的bean2节点下再添加property属性即可
Xml代码
1
.<property name=
"name"
value=
"coolszy"
/>
Spring学习笔记(
11
)----自定义属性编辑器
-------------------------------------------
前面我们所定义的属性都是几本的属性,如果我们定义一个属性是Date类型,例如如下类中:
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
import
java.util.Date;
4
.
5
.
public
class
Bean {
6
.
private
Date date;
7
.
8
.
public
Date getDate()
9
. {
10
.
return
date;
11
. }
12
.
public
void
setDate(Date date)
13
. {
14
.
this
.date = date;
15
. }
16
.}
按照我们以前学过的知识我们需要在配置文件中给该属性注入值
Xml代码
1
.<bean id=
"bean"
class
=
"com.szy.spring.bean.Bean"
>
2
. <property name=
"date"
value=
"2009-11-21"
/>
3
. </bean>
下面我们测试是否成功注入值
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. Bean bean = (Bean)ctx.getBean(
"bean"
);
3
. System.out.println(bean.getDate());
运行包如下异常
Exception代码
1
.org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'bean'
defined in
class
path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [java.util.Date]
for
property
'date'
; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [java.util.Date]
for
property
'date'
: no matching editors or conversion strategy found
通过错误提示信息我们得知spring不能将string转换成date类型,没有匹配的编辑器或者转换机制。
如果想实现string转换成Date,那么我们自己需要写一个属性编辑器
我们新建一个类DatePropertyEditor,这个类要继承PropertyEditorSupport类。
我们需要复写这个类中的setAsText方法,其中text参数就是配置文件中的值。我们的任务就是把text转换成date类型的值。
Java代码
1
.
package
com.szy.spring.util;
2
.
3
.
import
java.beans.PropertyEditorSupport;
4
.
import
java.text.SimpleDateFormat;
5
.
import
java.util.Date;
6
.
7
.
public
class
DatePropertyEditor
extends
PropertyEditorSupport
8
.{
9
.
10
.
@Override
11
.
public
void
setAsText(String text)
throws
IllegalArgumentException
12
. {
13
. String format=
"yyyy-MM-dd"
;
14
. SimpleDateFormat sdf=
new
SimpleDateFormat(format);
15
.
try
16
. {
17
. Date date=sdf.parse(text);
18
.
this
.setValue(date);
//把转换后的值传过去
19
. }
catch
(Exception e)
20
. {
21
. e.printStackTrace();
22
. }
23
. }
24
.
25
.}
写完编辑器后我们还需要把编辑器注入到spring中。 为了方便管理我们再新建一个配置文件applicationEditor.xml,用来配置属性编辑器
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"customEditorConfigurer"
class
=
"org.springframework.beans.factory.config.CustomEditorConfigurer"
>
10
. <!-- 把值注入到CustomEditorConfigurer的 Map类型的customEditors属性-->
11
. <property name=
"customEditors"
>
12
. <map>
13
. <entry key=
"java.util.Date"
>
14
. <!-- 内部bean只供自己使用 -->
15
. <bean
class
=
"com.szy.spring.util.DatePropertyEditor"
/>
16
. </entry>
17
. </map>
18
. </property>
19
. </bean>
20
.
21
.</beans>
下面我们修改下测试代码已读取所有的配置文件
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"application*.xml"
);
2
. Bean bean = (Bean)ctx.getBean(
"bean"
);
3
. System.out.println(bean.getDate());
最后测试,成功输出时间。
刚才我们在配置文件中时间的格式是
2009
-
11
-
21
,如果我们修改成
2009
/
11
/
21
呢?
运行报错:Unparseable date:
"2009/11/21"
这时我们需要修改属性编辑器类文件的格式了,很麻烦。既然spring支持注入,那么我们为什么不对格式进行注入呢?
修改属性编辑器类:
Java代码
1
.
package
com.szy.spring.util;
2
.
3
.
import
java.beans.PropertyEditorSupport;
4
.
import
java.text.SimpleDateFormat;
5
.
import
java.util.Date;
6
.
7
.
public
class
DatePropertyEditor
extends
PropertyEditorSupport
8
.{
9
.
10
.
private
String format;
11
.
@Override
12
.
public
void
setAsText(String text)
throws
IllegalArgumentException
13
. {
14
.
15
. SimpleDateFormat sdf=
new
SimpleDateFormat(format);
16
.
try
17
. {
18
. Date date=sdf.parse(text);
19
.
this
.setValue(date);
//把转换后的值传过去
20
. }
catch
(Exception e)
21
. {
22
. e.printStackTrace();
23
. }
24
. }
25
.
public
String getFormat()
26
. {
27
.
return
format;
28
. }
29
.
public
void
setFormat(String format)
30
. {
31
.
this
.format = format;
32
. }
33
.}
同时给该类对应的bean添加属性节点
Xml代码
1
.<bean
class
=
"com.szy.spring.util.DatePropertyEditor"
>
2
. <property name=
"format"
value=
"yyyy/MM/dd"
></property>
3
. </bean>
下次只要我们修改配置文件即可,灵活性很大。
Spring学习笔记(
12
)----静态代理模式分析演示
--------------------------------------------
代理模式分为静态代理和动态代理。静态代理就是我们自己定义的代理类,动态代理是程序在运行时生成的代理类。
下面演示下静态代理类。首先我们要定义一个接口:
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
interface
UserManager
4
.{
5
.
public
void
addUser(String username,String password);
6
.
public
void
deleteUser(
int
userId);
7
.
public
void
modifyUser(
int
userId,String username,String password);
8
.
public
void
findUser(
int
userId);
9
.}
比较常见的对用户进行增删改查。
下面我们常见一个实现类,实现这个接口。
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
void
findUser(
int
userId)
17
. {
18
. System.out.println(
"--------UserManagerImpl.findUser()----------"
);
19
. }
20
.
21
.
public
void
modifyUser(
int
userId, String username, String password)
22
. {
23
. System.out.println(
"--------UserManagerImpl.modifyUser()----------"
);
24
. }
25
.}
每个方法仅仅是输出一句话。
下面我们定义一个客户端类来调用这些方法。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
Client
4
.{
5
.
public
static
void
main(String[] args)
6
. {
7
. UserManager userManager=
new
UserManagerImpl();
8
. userManager.addUser(
"coolszy"
,
"kuka"
);
9
. }
10
.}
运行正常输出我们期望的结果。
下面我们需要加入安全性检查,就是调用方法前我们需要进行验证,比较常见的就是权限验证,验证用户是否拥有权限,
比较常见的做法就是在UserManagerImpl类中定义一个检查安全性的方法:
Java代码
1
.
public
void
checkSecurity()
2
. {
3
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
4
. }
然后在每个方法中都要调用这个方法。但是这样不符合开-闭原则(Open-Closed principle,简称OCP)。因此我们可以使用代理类来实现这个功能。代理模式很显著的特征就是和目标对象的接口一致。在代理类中我们可以控制目标对象。要控制目标对象我们必须有一个目标对象的引用。为了灵活我们可以把目标对象传到方法中,而不是在方法中实例化。同时我们把安全性检查的代码也放到代理类中,在调用每个方法之前调用这个检查方法,通过代理对我们以前的类没有破坏。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
UserManagerImplProxy
implements
UserManager
4
.{
5
.
private
UserManager userManager;
6
.
7
.
public
UserManagerImplProxy(UserManager userManager)
8
. {
9
.
this
.userManager = userManager;
10
. }
11
.
public
void
addUser(String username, String password)
12
. {
13
. checkSecurity();
14
.
this
.userManager.addUser(username, password);
15
. }
16
.
public
void
deleteUser(
int
userId)
17
. {
18
. checkSecurity();
19
.
this
.userManager.deleteUser(userId);
20
. }
21
.
public
String findUser(
int
userId)
22
. {
23
. checkSecurity();
24
.
return
this
.userManager.findUser(userId);
25
. }
26
.
public
void
modifyUser(
int
userId, String username, String password)
27
. {
28
. checkSecurity();
29
.
this
.userManager.modifyUser(userId, username, password);
30
. }
31
.
public
void
checkSecurity()
32
. {
33
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
34
. }
35
.}
下面修改客户端类。
Java代码
1
.UserManager userManager=
new
UserManagerImplProxy(
new
UserManagerImpl());
2
. userManager.addUser(
"coolszy"
,
"kuka"
);
这样总的来说比较灵活。这个依赖关系是我们自己做的,我们完全可以交给spring处理。
按照上面的这种做法有一个缺点,如果接口中方法很多,那么我们实现每一个方法都要添加检查方法checkSecurity(),影响了我们的业务处理。采用静态代理模式我们是没法解决的,这时我们需要使用AOP思想。
Spring学习笔记(
13
)----动态代理模式分析演示
-----------------------------------------------
上一节演示的是静态代理模式,本节演示的是静态代理模式,既然是动态,那么就不存在UserManagerImplProxy类。
使用动态代理我们需要声明一个类SecurityHandler,这个类要实现InvocationHandler接口。
在类中定义一个产生动态代理的方法newProxy();同时把我们验证的代码放到这个类中。通过SecurityHandler,当我们调用方法时默认会调用SecurityHandler类invoke方法,我们在这个方法中进行安全性检查,检查通过后在调用真实的方法。需要注意的是目标对象接口中的部分方法是存在返回值的。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
import
java.lang.reflect.InvocationHandler;
4
.
import
java.lang.reflect.Method;
5
.
import
java.lang.reflect.Proxy;
6
.
7
.
public
class
SecurityHandler
implements
InvocationHandler
8
.{
9
.
private
Object targetObject;
10
.
11
.
public
Object newProxy(Object targetObject)
12
. {
13
.
this
.targetObject=targetObject;
14
.
//返回动态代理
15
.
return
Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
16
. targetObject.getClass().getInterfaces(),
17
.
this
);
18
. }
19
.
public
Object invoke(Object proxy, Method method, Object[] args)
20
.
throws
Throwable
21
. {
22
. checkSecurity();
23
. Object ret=
null
;
24
.
try
25
. {
26
.
//调用目标对象的真实方法
27
. ret=method.invoke(
this
.targetObject, args);
28
.
//ret接受存在的返回值,不存在返回值则为Null
29
. }
catch
(Exception e)
30
. {
31
. e.printStackTrace();
32
. }
33
.
return
null
;
34
. }
35
.
public
void
checkSecurity()
36
. {
37
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
38
. }
39
.}
使用这种方式维护起来相对比较好,我想进行安全性检查就进行,不想就不进行,很方便。
下面进行客户端调用
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
Client
4
.{
5
.
public
static
void
main(String[] args)
6
. {
7
. SecurityHandler handler=
new
SecurityHandler();
8
.
//创建代理对象
9
. UserManager userManager=(UserManager)handler.newProxy(
new
UserManagerImpl());
10
. userManager.addUser(
"coolszy"
,
"kuka"
);
11
. }
12
.}
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语句是在两个不同的事务中运行。