原文链接:http://blog.csdn.net/chenggil10/article/details/5899353
知识点名称 | 介绍 | 工作重要程度 | 面试重要程度 | 方法建议 |
IOC XML | *** | 练 | ||
IOC Annotation | *** | 练 | ||
IOC 注入方式(两种) | *** | * | 练+背 | |
简单属性 | * | |||
集合注入 | * | 查 | ||
自动装配 | * | * | ||
生命周期 | * | * | 查 | |
AOP概念 | *** | |||
AOP配置 | * | 查 | ||
事务管理AOP(xml annotation) | *** | ** | 练+背 | |
hibernateTemplate | *** | |||
架构 | *** | *** | 练+理解+说 | |
OpenSessionInView | *** | ** | ||
CharacterEncodingFilter | *** | |||
TestContext | * | |||
SpringJDBCTemplate | 用到现学 |
课程内容
1. 面向接口(抽象)编程的概念与好处
2. IOC/DI的概念与好处
a) inversion of control
b) dependency injection
3. AOP的概念与好处
4. Spring简介
5. Spring应用IOC/DI(重要)
a) xml
b) annotation
6. Spring应用AOP(重要)
a) xml
b) annotation
7. Struts2.1.6 + Spring2.5.6 + Hibernate3.3.2整合(重要)
a) opensessionInviewfilter(记住,解决什么问题,怎么解决)
8. Spring JDBC
面向接口编程(面向抽象编程)
1. 场景:用户添加
2. Spring_0100_AbstractOrientedProgramming
a) 不是AOP:Aspect Oriented Programming
3. 好处:灵活
什么是IOC(DI),有什么好处
1. 把自己new的东西改为由容器提供
a) 初始化具体值
b) 装配
2. 好处:灵活装配
Spring简介
1. 项目名称:Spring_0200_IOC_Introduction
2. 环境搭建
a) 只用IOC
i. spring.jar , jarkata-commons/commons-loggin.jar
3. IOC容器
a) 实例化具体bean
b) 动态装配
4. AOP支持
a) 安全检查
b) 管理transaction
Spring IOC配置与应用
1. FAQ:不给提示:
a) window – preferences – myeclipse – xml – xml catalog
b) User Specified Entries – add
i. Location: D:/share/0900_Spring/soft/spring-framework-2.5.6/dist/resources/spring-beans-2.5.xsd
ii. URI: file:///D:/share/0900_Spring/soft/spring-framework-2.5.6/dist/resources/spring-beans-2.5.xsd
iii. Key Type: Schema Location
iv. Key: http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
2. 注入类型
a) Spring_0300_IOC_Injection_Type
b) setter(重要)
c) 构造方法(可以忘记)
d) 接口注入(可以忘记)
3. id vs. name
a) Spring_0400_IOC_Id_Name
b) name可以用特殊字符
4. 简单属性的注入
a) Spring_0500_IOC_SimpleProperty
b) <property name=… value=….>
5. <bean 中的scope属性
a) Spring_0600_IOC_Bean_Scope
b) singleton 单例
c) proptotype 每次创建新的对象
6. 集合注入
a) Spring_0700_IOC_Collections
b) 很少用,不重要!参考程序
7. 自动装配
a) Spring_0800_IOC_AutoWire
b) byName
c) byType
d) 如果所有的bean都用同一种,可以使用beans的属性:default-autowire
8. 生命周期
a) Spring_0900_IOC_Life_Cycle
b) lazy-init (不重要)
c) init-method destroy-methd 不要和prototype一起用(了解)
9. Annotation第一步:
a) 修改xml文件,参考文档<context:annotation-config/>
10. @Autowired
a) 默认按类型by type
b) 如果想用byName,使用@Qulifier
c) 写在private field(第三种注入形式)(不建议,破坏封装)
d) 如果写在set上,@qualifier需要写在参数上
11. @Resource(重要)
a) 加入:j2ee/common-annotations.jar
b) 默认按名称,名称找不到,按类型
c) 可以指定特定名称
d) 推荐使用
e) 不足:如果没有源码,就无法运用annotation,只能使用xml
12. @Component @Service @Controller @Repository
a) 初始化的名字默认为类名首字母小写
b) 可以指定初始化bean的名字
13. @Scope
14. @PostConstruct = init-method; @PreDestroy = destroy-method;
什么是AOP
1. 面向切面编程Aspect-Oriented-Programming
a) 是对面向对象的思维方式的有力补充
2. Spring_1400_AOP_Introduction
3. 好处:可以动态的添加和删除在切面上的逻辑而不影响原来的执行代码
a) Filter
b) Struts2的interceptor
4. 概念:
a) JoinPoint
b) PointCut
c) Aspect(切面)
d) Advice
e) Target
f) Weave
Spring AOP配置与应用
1. 两种方式:
a) 使用Annotation
b) 使用xml
2. Annotation
a) 加上对应的xsd文件spring-aop.xsd
b) beans.xml <aop:aspectj-autoproxy/>
c) 此时就可以解析对应的Annotation了
d) 建立我们的拦截类
e) 用@Aspect注解这个类
f) 建立处理方法
g) 用@Before来注解方法
h) 写明白切入点(execution …….)
i) 让spring对我们的拦截器类进行管理@Component
3. 常见的Annotation:
a) @Pointcut
b) @Before
c) @AfterReturning
d) @AfterThrowing
e) @After
f) @Around
4. 织入点语法
a) void !void
b) 参考文档(* ..)
5. xml配置AOP
a) 把interceptor对象初始化
b) <aop:config
i. <aop:aspect …..
1. <aop:pointcut
2. <aop:before
Spring整合Hibernate
1. Spring 指定datasource
a) 参考文档,找dbcp.BasicDataSource
i. c3p0
ii. dbcp
iii. proxool
b) 在DAO或者Service中注入dataSource
c) 在Spring中可以使用PropertyPlaceHolderConfigure来读取Properties文件的内容
2. Spring整合Hibernate
a) <bean .. AnnotationSessionFactoryBean>
i. <property dataSource
ii. <annotatedClasses
b) 引入hibernate 系列jar包
c) User上加Annotation
d) UserDAO或者UserServie 注入SessionFactory
e) jar包问题一个一个解决
3. 声明式的事务管理
a) 事务加在DAO层还是Service层?
b) annotation
i. 加入annotation.xsd
ii. 加入txManager bean
iii. <tx:annotation-driven
iv. 在需要事务的方法上加:@Transactional
v. 需要注意,使用SessionFactory.getCurrentSession 不要使用OpenSession
c) @Transactional详解
i. 什么时候rollback
1. 运行期异常,非运行期异常不会触发rollback
2. 必须uncheck (没有catch)
3. 不管什么异常,只要你catch了,spring就会放弃管理
4. 事务传播特性:propagation_required
5. read_only
d) xml(推荐,可以同时配置好多方法)
i. <bean txmanager
ii. <aop:config
1. <aop:pointcut
2. <aop:advisor pointcut-ref advice-ref
iii. <tx:advice: id transaction-manager =
e) HibernateTemplate、HibernateCallback、HibernateDaoSupport(不重要)介绍
i. 设计模式:Template Method
ii. Callback:回调/钩子函数
iii. 第一种:(建议)
1. 在spring中初始化HibernateTemplate,注入sessionFactory
2. DAO里注入HibernateTemplate
3. save写getHibernateTemplate.save();
iv. 第二种:
1. 从HibernateDaoSupport继承
2. 必须写在xml文件中,无法使用Annotation,因为set方法在父类中,而且是final的
f) spring整合hibernate的时候使用packagesToScan属性,可以让spring自动扫描对应包下面的实体类
Struts2.1.6 + Spring2.5.6 + Hibernate3.3.2
1. 需要的jar包列表
jar包名称 | 所在位置 | 说明 |
antlr-2.7.6.jar | hibernate/lib/required | 解析HQL |
aspectjrt | spring/lib/aspectj | AOP |
aspectjweaver | .. | AOP |
cglib-nodep-2.1_3.jar | spring/lib/cglib | 代理,二进制增强 |
common-annotations.jar | spring/lib/j2ee | @Resource |
commons-collections-3.1.jar | hibernate/lib/required | 集合框架 |
commons-fileupload-1.2.1.jar | struts/lib | struts |
commons-io-1.3.2 | struts/lib | struts |
commons-logging-1.1.1 | 单独下载,删除1.0.4(struts/lib) | struts spring |
dom4j-1.6.1.jar | hibernate/required | 解析xml |
ejb3-persistence | hibernate-annotation/lib | @Entity |
freemarker-2.3.13 | struts/lib | struts |
hibernate3.jar | hibernate |
|
hibernate-annotations | hibernate-annotation/ |
|
hibernate-common-annotations | hibernate-annotation/lib |
|
javassist-3.9.0.GA.jar | hiberante/lib/required | hibernate |
jta-1.1.jar | .. | hibernate transaction |
junit4.5 |
|
|
mysql- |
|
|
ognl-2.6.11.jar | struts/lib |
|
slf4j-api-1.5.8.jar | hibernate/lib/required | hibernate-log |
slf4j-nop-1.5.8.jar | hibernate/lib/required |
|
spring.jar | spring/dist |
|
struts2-core-2.1.6.jar | struts/lib |
|
xwork-2.1.2.jar | struts/lib | struts2 |
commons-dbcp | spring/lib/jarkata-commons |
|
commons-pool.jar | .. |
|
struts2-spring-plugin-2.1.6.jar | struts/lib |
|
2. BestPractice:
a) 将这些所有的jar包保存到一个位置,使用的时候直接copy
3. 步骤
a) 加入jar包
b) 首先整合Spring + Hibernate
i. 建立对应的package
1. dao / dao.impl / model / service / service.impl/ test
ii. 建立对应的接口与类框架
1. S2SH_01
iii. 建立spring的配置文件(建议自己保留一份经常使用的配置文件,以后用到的时候直接copy改)
iv. 建立数据库
v. 加入Hibernate注解
1. 在实体类上加相应注解@Entity @Id等
2. 在beans配置文件配置对应的实体类,使之受管
vi. 写dao service的实现
vii. 加入Spring注解
1. 在对应Service及DAO实现中加入@Component,让spring对其初始化
2. 在Service上加入@Transactional或者使用xml方式(此处建议后者,因为更简单)
3. 在DAO中注入sessionFactory
4. 在Service中注入DAO
5. 写DAO与Service的实现
viii. 写测试
c) 整合Struts2
i. 结合点:Struts2的Action由Spring产生
ii. 步骤:
1. 修改web.xml加入 struts的filter
2. 再加入spring的listener,这样的话,webapp一旦启动,spring容器就初始化了
3. 规划struts的action和jsp展现
4. 加入struts.xml
a) 修改配置,由spring替代struts产生Action对象
5. 修改action配置
a) 把类名改为bean对象的名称,这个时候就可以使用首字母小写了
b) @Scope(“prototype”)不要忘记
iii. struts的读常量:
1. struts-default.xml
2. struts-plugin.xml
3. struts.xml
4. struts.properties
5. web.xml
iv. 中文问题:
1. Struts2.1.8已经修正,只需要改i18n.encoding = gbk
2. 使用spring的characterencoding
3. 需要严格注意filter的顺序
4. 需要加到Struts2的filter前面
v. LazyInitializationException
1. OpenSessionInViewFilter
2. 需要严格顺序问题
3. 需要加到struts2的filter前面
---------------------------------------------------------------------------------------------------------------------------------------
【详细版】
课程内容
1. 面向接口(抽象)编程的概念与好处
2. IOC/DI的概念与好处
a) inversion of control
b) dependency injection
3. AOP的概念与好处
4. Spring简介
5. Spring应用IOC/DI(重要)
a) xml
b) annotation
6. Spring应用AOP(重要)
a) xml
b) annotation
7. Struts2.1.6 + Spring2.5.6 + Hibernate3.3.2整合(重要)
a) opensessionInviewfilter(记住,解决什么问题,怎么解决)
8. Spring JDBC
面向接口编程(面向抽象编程)
1. 场景:用户添加
2. Spring_0100_AbstractOrientedProgramming
a) 不是AOP:Aspect Oriented Programming
3. 好处:灵活
什么是IOC(DI),有什么好处
1. 把自己new的东西改为由容器提供
a) 初始化具体值
b) 装配
<?xml version="1.0"?>
-<beans>
<bean class="com.bjsxt.dao.impl.UserDAOImpl"id="u"/>(class 是个类。Id就等于构造了一个对象)
<bean class="com.bjsxt.service.UserService" id="userService">
<property bean="u"name="userDAO"/> </bean>
(把u这个对象注入到UserService这个类的一个userDAO的一个属性里)
-</beans>
2. 好处:灵活装配
Spring简介
1. 项目名称:Spring_0200_IOC_Introduction
2. 环境搭建
a) 只用IOC
i. spring.jar , jarkata-commons/commons-loggin.jar
3. IOC容器
a) 实例化具体bean
b) 动态装配
4. AOP支持
a) 安全检查
b) 管理transaction
Spring IOC配置与应用
1. FAQ:不给提示:
a) window – preferences – myeclipse – xml – xml catalog
b) User Specified Entries – add
i. Location: D:\share\0900_Spring\soft\spring-framework-2.5.6\dist\resources\spring-beans-2.5.xsd
ii. URI: file:///D:/share/0900_Spring/soft/spring-framework-2.5.6/dist/resources/spring-beans-2.5.xsd
iii. KeyType: Schema Location
iv. Key: http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
2. 注入类型
a) Spring_0300_IOC_Injection_Type
b) setter(重要)
c) 构造方法(可以忘记)
d) 接口注入(可以忘记)
3. id vs. Name(可以把Id换成name,没什么区别!)
a) Spring_0400_IOC_Id_Name
b) name可以用特殊字符
4. 简单属性的注入
a) Spring_0500_IOC_SimpleProperty
b) <property name=… value=….>
在配置文件里直接赋值!(在此简单属性为int和string,会自动转换)
5. <bean 中的scope属性
a) Spring_0600_IOC_Bean_Scope
b) singleton 单例(无论去多少次都是同一个bean)
c) proptotype 每次创建新的对象
6. 集合注入
a) Spring_0700_IOC_Collections
b) 很少用,不重要!参考程序
7. 自动装配
a) Spring_0800_IOC_AutoWire
b) byName
c) byType
d) 如果所有的bean都用同一种,可以使用beans的属性:default-autowire
-<beanclass="com.bjsxt.dao.impl.UserDAOImpl" name="userDAO">
<property name="daoId"value="1"/> </bean>
<bean class="com.bjsxt.dao.impl.UserDAOImpl"name="userDAO2">
<property name="daoId"value="2"/> </bean>
<bean class="com.bjsxt.service.UserService"
autowire="byType"scope="prototype" id="userService">
</bean> </beans>
(这里会报错,因为有两个userDAO和UserDAO2都是int类型!)
(如果说byname则会显示第一个的内容“1”!,因为UserService类里面的userDAO属性与第一个的名字一样!)
8. 生命周期
a) Spring_0900_IOC_Life_Cycle
b) lazy-init (不重要)
c) init-method与destroy-methd 不要和prototype一起用(了解)
<bean class="com.bjsxt.dao.impl.UserDAOImpl"id="u">
</bean>
<bean class="com.bjsxt.service.UserService"id="userService" scope="prototype" destroy-method="destroy"init-method="init">
</bean>
</beans>
9. Annotation第一步:
a) 修改xml文件,参考文档<context:annotation-config />
b) 默认按类型by type
c) 如果想用byName,使用@Qulifier
d) 写在private field(第三种注入形式)(不建议,破坏封装)
e) 如果写在set上,@qualifier需要写在参数上
f)
10. @Resource(重要)
a) 加入:j2ee/common-annotations.jar
b) 默认按名称,名称找不到,按类型
c) 可以指定特定名称
d) 推荐使用
e) 不足:如果没有源码,就无法运用annotation,只能使用xml
11. @Component
@Service @Controller @Repository(四个一样的功能!!)
a) 初始化的名字默认为类名首字母小写
b) 可以指定初始化bean的名字
首先先加载
ClassPathXmlApplicationContextctx = new ClassPathXmlApplicationContext("beans.xml");
即读beans.xml里面的内容,然后通过
找从com.bjsxt开始“scan”含@component的类,
找到之后就初始化对象,结果在
其一个属相的set方法上找到一个源为“u”的一个bean,于是就加载那个bean!
12. @Scope
13. @PostConstruct = init-method;(在构造对象后执行此方法)
@PreDestroy =destroy-method;(在容器销毁前执行此方法)
什么是AOP
1. 面向切面编程Aspect-Oriented-Programming(权限)
a) 是对面向对象的思维方式的有力补充
2. Spring_1400_AOP_Introduction
3. 好处:可以动态的添加和删除在切面上的逻辑而不影响原来的执行代码
a) Filter
b) Struts2的interceptor
4. 概念:
a) JoinPoint 释意:切面与原方法交接点 即 切入点
b) PointCut 释意:切入点集合
是com.xyz.someapp.service.下面的任何类,任何方法,任何返回值的一个切入点的集合。
c) Aspect(切面)释意:可理解为代理类前说明(简单的理解为夹在类的新的业务逻辑,就是业务逻辑类)
d) Advice 释意:可理解为代理方法前说明例如@Before(即加在切面上的说明)
e) Target 释意:被代理对象 被织入对象
f) Weave 释意:织入
Spring AOP配置与应用
Spring AOP的底层实现技术---JDK动态代理
2008-06-12 10:38:54
JDK动态代理(proxy invocationhandler)
在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在我们终于发现动态代理是实现AOP的绝好底层技术。
JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
而Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例。这样讲一定很抽象,我们马上着手动用Proxy和InvocationHandler这两个魔法戒对上一节中的性能监视代码进行AOP式的改造。
首先,我们从业务类ForumServiceImpl 中删除性能监视的横切代码,使ForumServiceImpl只负责具体的业务逻辑,如所示:
代码清单 5 ForumServiceImpl:移除性能监视横切代码
package com.baobaotao.proxy;
public class ForumServiceImpl implementsForumService {
public void removeTopic(int topicId) {
①
System.out.println("模拟删除Topic记录:"+topicId);
try {
Thread.currentThread().sleep(20);
}catch (Exception e) {
throw new RuntimeException(e);
}
②
}
public void removeForum(int forumId) {
①
System.out.println("模拟删除Forum记录:"+forumId);
try {
Thread.currentThread().sleep(40);
}catch (Exception e) {
throw new RuntimeException(e);
} ②
}
}
在代码清单 5中的①和②处,原来的性能监视代码被移除了,我们只保留了真正的业务逻辑。
从业务类中移除的横切代码当然还得找到一个寄居之所,InvocationHandler就是横切代码的家园乐土,我们将性能监视的代码安置在PerformaceHandler中,如代码清单 6所示:
代码清单 6 PerformaceHandler
package com.baobaotao.proxy;
importjava.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PerformaceHandler implementsInvocationHandler {
private Object target; 一般的都有一个object对象,object是被代理对象!
public PerformaceHandler(Object target){//①target为目标的业务类
this.target = target;
}
public Object invoke(Object proxy, Methodmethod, Object[] args)
throws Throwable {
PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName());
Object bj = method.invoke(target, args);//②通过反射方法调用目标业务类的业务方法
PerformanceMonitor.end();
return obj;
}
}
粗体部分的代码为性能监视的横切代码,我们发现,横切代码只出现一次,而不是原来那样星洒各处。大家注意②处的method.invoke(),该语句通 过反射的机制调用目标对象的方法,这样InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法就将横切代码和目标业务类代码编织到一起了,所以我们可以将InvocationHandler看成是业务逻辑和横切逻辑的编织器。下面, 我们对这段代码做进一步的说明。
首先,我们实现InvocationHandler接口,该接口定义了一个 invoke(Object proxy, Method method, Object[] args)的方法,proxy是代理实例,一般不会用到;method是代理实例上的方法,通过它可以发起对目标类的反射调用;args是通过代理类传入 的方法参数,在反射调用时使用。
此外,我们在构造函数里通过target传入真实的目标对象,如①处所示,在接口方法invoke(Object proxy, Method method, Object[] args)里,将目标类实例传给method.invoke()方法,通过反射调用目标类方法,如②所示。
下面,我们通过Proxy结合PerformaceHandler创建ForumService接口的代理实例,如代码清单 7所示:
代码清单 7 TestForumService:创建代理实例
package com.baobaotao.proxy;
import java.lang.reflect.Proxy;
public class TestForumService {
public static void main(String[] args) {
ForumService target = new ForumServiceImpl();//①目标业务类
//② 将目标业务类和横切代码编织到一起
PerformaceHandler handler = newPerformaceHandler(target);
//③为编织了目标业务类逻辑和性能监视横切逻辑的handler创建代理类
ForumService proxy = (ForumService)Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
//④ 操作代理实例
proxy.removeForum(10);
proxy.removeTopic(1012);
}
}
上面的代码完成了业务类代码和横切代码编织和接口代理实例生成的工作,其中在②处,我们将ForumService实例编织为一个包含性能监视逻辑的PerformaceHandler实例,然后在③处,通过Proxy的静态方法newProxyInstance()为融合了业务类逻辑和性能监视逻辑 的handler创建一个ForumService接口的代理实例,该方法的第一个入参为类加载器,第二个入参为创建的代理实例所要实现的一组接口,第三 个参数是整合了业务逻辑和横切逻辑的编织器对象。
按照③处的设置方式,这个代理实例就实现了目标业务类的所有接口,也即ForumServiceImpl的ForumService接口。这样,我们就可以按照调用ForumService接口的实例相同的方式调用代理实例,如④所示。运行以上的代码,输出以下的信息:
begin monitor...
模拟删除Forum记录:10
end monitor...
com.baobaotao.proxy.ForumServiceImpl.removeForum花费47毫秒。
begin monitor...
模拟删除Topic记录:1012
end monitor...
com.baobaotao.proxy.ForumServiceImpl.removeTopic花费26毫秒。
我们发现,程序的运行效果和直接在业务类中编写性能监视逻辑的效果一致,但是在这里,原来分散的横切逻辑代码已经被我们抽取到 PerformaceHandler中。当其它业务类(如UserService、SystemService等)的业务方法也需要使用性能监视时,我们 只要按照以上的方式,分别为它们创建代理对象就可以了。下面,我们用时序图描述调用关系,进一步代理实例的本质,如图1所示:
图 1代理实例的时序图
我们在上图中特别使用虚线阴影的方式对通过代理器创建的ForumService实例进行凸显,该实例内部利用PerformaceHandler整合横 切逻辑和业务逻辑。调用者调用代理对象的的removeForum()和removeTopic()方法时,上图的内部调用时序清晰地告诉了我们实际上所 发生的一切。
public class UserServiceTest {
@Test
public void testProxy() {
UserDAO userDAO = new UserDAOImpl();
LogInterceptor li = new LogInterceptor();
li.setTarget(userDAO);
UserDAO userDAOProxy =
(UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(),li);
System.out.println(userDAOProxy.getClass());
userDAOProxy.delete();
userDAOProxy.save(new User());
}
/*class $Proxy4 implements UserDAO
* {
* save(User u) {
* Method m = UserDAO.getclass.getmethod
* li.invoke(this, m, u)
* }
* }
*/
}
public class LogInterceptor implements InvocationHandler {
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public void beforeMethod(Method m) {
System.out.println(m.getName() + " start");
}
public Object invoke(Objectproxy, Method m, Object[] args)
throws Throwable {
beforeMethod(m);
m.invoke(target, args);
return null;
}
}
1. 两种方式:
a) 使用Annotation
b) 使用xml
2. Annotation
a) 加上对应的xsd文件spring-aop.xsd
b) beans.xml <aop:aspectj-autoproxy />(aspectj是专门产生代理的类)
c) 此时就可以解析对应的Annotation了
d) 建立我们的拦截类
e) 用@Aspect(切面逻辑)注解这个类
f) 建立处理方法
g) 用@Before来注解方法
h) 写明白切入点(execution …….)
i) 让spring对我们的拦截器类进行管理@Component
3. 常见的Annotation:
a) @JoinPoint
b) @Pointcut 切入点声明以供其他方法使用 , 例子如下:
@Aspect
@Component
public class LogInterceptor {
@Pointcut("execution(public * com.bjsxt.dao..*.*(..))")(dao..代表包的任何子类)
public void myMethod(){}
@Around("myMethod()")
public void before(ProceedingJoinPointpjp) throws Throwable{
System.out.println("method before");
pjp.proceed();
}
@AfterReturning("myMethod()")
public void afterReturning() throws Throwable{
System.out.println("method afterReturning");
}
@After("myMethod()")
public void afterFinily() throws Throwable{
System.out.println("method end");
}
}
c) @Before 发放执行之前织入
d) @AfterReturning 方法正常执行完返回之后织入(无异常)
e) @AfterThrowing 方法抛出异常后织入
f) @After 类似异常的finally
g) @Around 环绕 类似filter , 如需继续往下执行则需要像filter中执行FilterChain.doFilter(..)对象一样 执行 ProceedingJoinPoint.proceed()方可,例子如下:
@Around("execution(* com.bjsxt.dao..*.*(..))")
public voidbefore(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("method start");
pjp.proceed();//类似FilterChain.doFilter(..)告诉jvm继续向下执行
}
4. 织入点语法
a) void !void
b) 参考文档(* ..)
如果execution(* com.bjsxt.dao..*.*(..))中声明的方法不是接口实现则无法使用AOP实现动态代理,此时可引入包” cglib-nodep-2.1_3.jar” 后有spring自动将普通类在jvm中编译为接口实现类,从而打到可正常使用AOP的目的.
5. xml配置AOP(重要)
a) 把interceptor对象初始化
b) <aop:config
i. <aop:aspect …..
1. <aop:pointcut
2. <aop:before
例子:
<bean id="logInterceptor" class="com.bjsxt.aop.LogInterceptor"></bean>
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="point"ref="logInterceptor">
<!-- 配置切入点,指定切入点表达式 -->
<!-- 此句也可放到 aop:aspect标签外依然有效-->
<aop:pointcut
expression=
"execution(public * com.bjsxt.service..*.*(..))"
id="myMethod"/>
<!-- 应用前置通知 -->
<aop:beforemethod="before" pointcut-ref="myMethod" />
<!-- 应用环绕通知需指定向下进行 -->
<aop:aroundmethod="around" pointcut-ref="myMethod" />
<!-- 应用后通知 -->
<aop:after-returningmethod="afterReturning"
pointcut-ref="myMethod" />
<!-- 应用抛出异常后通知 -->
<aop:after-throwingmethod="afterThrowing"
pointcut-ref="myMethod" />
<!-- 应用最终通知 -->
<aop:after method="afterFinily"
pointcut="execution(public* om.bjsxt.service..*.*(..))" />
</aop:aspect>
</aop:config>
Spring整合Hibernate
1. Spring 指定datasource javax中的一个接口,里面有一个getConnection()的方法(标准化的取得连接的一种方式!)
a) 参考文档,找dbcp.BasicDataSource(dbcp databaseconnect pour 数据库连接池)
第一种写法:
<beanid="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results ina setDriverClassName(String) call -->
<propertyname="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<propertyname="url">
<value>jdbc:mysql://localhost:3306/mydb</value>
</property>
<propertyname="username">
<value>root</value>
</property>
<propertyname="password">
<value>masterkaoli</value>
</property>
</bean>
第二种写法:
<bean id="myDataSource"class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results ina setDriverClassName(String) call -->
<propertyname="driverClassName" value="com.mysql.jdbc.Driver"/>
<propertyname="url" value="jdbc:mysql://localhost:3306/mydb"/>
<propertyname="username" value="root"/>
<propertyname="password" value="masterkaoli"/>
</bean>
i. c3p0
ii. dbcp
Proxool不管通过何种持久化技术,都必须通过数据连接访问数据库,在Spring中,数据连接是通过数据源获得的。在以往的应用中,数据源一般是 Web应用服务器提供的。在Spring中,你不但可以通过JNDI获取应用服务器的数据源,也可以直接在Spring容器中配置数据源,此外,你还可以 通过代码的方式创建一个数据源,以便进行无依赖的单元测试配置一个数据源
Spring在第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP,其二是 C3P0。可以在Spring配置文件中利用这两者中任何一个配置数据源。
DBCP数据源
DBCP类包位于 /lib/jakarta-commons/commons-dbcp.jar,DBCP是一个依赖 Jakarta commons-pool对象池机制的数据库连接池,所以在类路径下还必须包括/lib/jakarta- commons/commons-pool.jar。下面是使用DBCP配置MySql数据源的配置片断:
xml 代码
<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<propertyname="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url"value="jdbc:mysql://localhost:3309/sampledb" />
<propertyname="username" value="root" />
<propertyname="password" value="1234" />
</bean>
BasicDataSource提供了close()方法关闭数据源,所以必须设定destroy-method=”close”属性,以便Spring 容器关闭时,数据源能够正常关闭。除以上必须的数据源属性外,还有一些常用的属性:
defaultAutoCommit:设置从数据源中返回的连接是否采用自动提交机制,默认值为 true;
defaultReadOnly:设置数据源是否仅能执行只读操作, 默认值为 false;
maxActive:最大连接数据库连接数,设置为0时,表示没有限制;
maxIdle:最大等待连接中的数量,设置为0时,表示没有限制;
maxWait:最大等待秒数,单位为毫秒, 超过时间会报出错误信息;
validationQuery:用于验证连接是否成功的查询SQL语句,SQL语句必须至少要返回一行数据, 如你可以简单地设置为:“select count(*) from user”;
removeAbandoned:是否自我中断,默认是 false ;
removeAbandonedTimeout:几秒后数据连接会自动断开,在removeAbandoned为true,提供该值;
logAbandoned:是否记录中断事件, 默认为 false;
C3P0数据源
C3P0是一个开放源代码的JDBC数据源实现项目,它在lib目录中与Hibernate一起发布,实现了JDBC3和JDBC2扩展规范说明的 Connection 和Statement 池。C3P0类包位于/lib/c3p0/c3p0-0.9.0.4.jar。下面是使用C3P0配置一个 Oracle数据源:
xml 代码
<bean id="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<propertyname="driverClass" value=" oracle.jdbc.driver.OracleDriver"/>
<property name="jdbcUrl"value=" jdbc:oracle:thin:@localhost:1521:ora9i "/>
<property name="user"value="admin"/>
<property name="password"value="1234"/>
</bean>
ComboPooledDataSource和BasicDataSource一样提供了一个用于关闭数据源的close()方法,这样我们就可以保证Spring容器关闭时数据源能够成功释放。
C3P0拥有比DBCP更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制:
acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目;
acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30;
acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000;
autoCommitOnClose:连接关闭时默认将所有未提交的操作回滚。默认为false;
automaticTestTable: C3P0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数,那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将中为C3P0测试所用,默认为null;
breakAfterAcquireFailure:获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调 用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为 false;
checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒,默认为0;
connectionTesterClassName: 通过实现ConnectionTester或QueryConnectionTester的类来测试连接,类名需设置为全限定名。默认为com.mchange.v2.C3P0.impl.DefaultConnectionTester;
idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;
initialPoolSize:初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3;
maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0;
maxPoolSize:连接池中保留的最大连接数。默认为15;
maxStatements:JDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属 于单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatements与 maxStatementsPerConnection均为0,则缓存被关闭。默认为0;
maxStatementsPerConnection:连接池内单个连接所拥有的最大缓存Statement数。默认为0;
numHelperThreads:C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3;
preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认为null;
propertyCycle: 用户修改系统配置参数执行前最多等待的秒数。默认为300;
testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。默认为false;
testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false。
读配置文件的方式引用属性:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<propertyname="location" value="/WEB-INF/jdbc.properties"/>
</bean>
<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<propertyname="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url"value="${jdbc.url}" />
<property name="username"value="${jdbc.username}" />
<propertyname="password" value="${jdbc.password}" />
</bean>
在jdbc.properties属性文件中定义属性值:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url= jdbc:mysql://localhost:3309/sampledb
jdbc.username=root
jdbc.password=1234
提示 经常有开发者在${xxx}的前后不小心键入一些空格,这些空格字符将和变量合并后作为属性的值。如: 的属性配置项,在前后都有空格,被解析后,username的值为“ 1234 ”,这将造成最终的错误,因此需要特别小心。
获取JNDI数据源
如果应用配置在高性能的应用服务器(如WebLogic或Websphere等)上,我们可能更希望使用应用服务器本身提供的数据源。应用服务器的数据源 使用JNDI开放调用者使用,Spring为此专门提供引用JNDI资源的JndiObjectFactoryBean类。下面是一个简单的配置:
xml 代码
<bean id="dataSource"class="org.springframework.jndi.JndiObjectFactoryBean">
<propertyname="jndiName" value="java:comp/env/jdbc/bbt"/>
</bean>
通过jndiName指定引用的JNDI数据源名称。
Spring 2.0为获取J2EE资源提供了一个jee命名空间,通过jee命名空间,可以有效地简化J2EE资源的引用。下面是使用jee命名空间引用JNDI数据源的配置:
xml 代码
<beans xmlns=http://www.springframework.org/schema/beans
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns:jee=http://www.springframework.org/schema/jee
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/bbt"/>
</beans>
Spring的数据源实现类
Spring本身也提供了一个简单的数据源实现类DriverManagerDataSource ,它位于org.springframework.jdbc.datasource包中。这个类实现了javax.sql.DataSource接口,但它并没有提供池化连接的机制,每次调用getConnection()获取新连接时,只是简单地创建一个新的连接。因此,这个数据源类比较适合在单元测试 或简单的独立应用中使用,因为它不需要额外的依赖类。
下面,我们来看一下DriverManagerDataSource的简单使用:当然,我们也可以通过配置的方式直接使用DriverManagerDataSource。
java 代码
DriverManagerDataSource ds = new DriverManagerDataSource ();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3309/sampledb");
ds.setUsername("root");
ds.setPassword("1234");
Connection actualCon = ds.getConnection();
小结
不管采用何种持久化技术,都需要定义数据源。Spring附带了两个数据源的实现类包,你可以自行选择进行定义。在实际部署时,我们可能会直接采用应用服 务器本身提供的数据源,这时,则可以通过JndiObjectFactoryBean或jee命名空间引用JNDI中的数据源。
DBCP与C3PO配置的区别:
C3PO :DBCP:
xml 代码
<bean id="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource"destroy-method="close">
<propertyname="driverClass">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<propertyname="jdbcUrl">
<value>jdbc:oracle:thin:@10.10.10.6:1521:DataBaseName</value>
</property>
<property name="user">
<value>testAdmin</value>
</property>
<propertyname="password">
<value>123456</value>
</property>
</bean>
xml 代码
<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<propertyname="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<propertyname="url">
<value>jdbc:oracle:thin:@10.10.10.6:1521:DataBaseName</value>
</property>
<propertyname="username">
<value>testAdmin</value>
</property>
<propertyname="password">
<value>123456</value>
</property>
</bean>
iii.
b) 在DAO或者Service中注入dataSource
c) 在Spring中可以使用PropertyPlaceHolderConfigure来读取Properties文件的内容
<beanclass="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:com/foo/jdbc.properties</value>
</property>
</bean>
(在这个bin(PropertyPlaceholderConfigurer)下面有一个属性“locations”,在classpath下的jdbc.properties文件里面有配置,设置到相关下面bin里面,于是可以在src目录下建一个jdbc.properties的文件,里面写上,与下面的datasource相对应!)
<bean id="dataSource"destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
2. Spring整合Hibernate
a) <bean .. AnnotationSessionFactoryBean>
i. <property dataSource
ii. <annotatedClasses
b) 引入hibernate 系列jar包
c) User上加Annotation
d) UserDAO或者UserServie 注入SessionFactory
e) jar包问题一个一个解决
3. 声明式的事务管理
a) 事务加在DAO层还是Service层?(加在Service层)
b) annotation
i. 加入annotation.xsd
ii. 加入txManager bean
iii. <tx:annotation-driven
例如: <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<propertyname="sessionFactory">
<refbean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
iv. 在需要事务的方法上加:@Transactional
v.
vi. 需要注意,Hibernate获得session时要使用SessionFactory.getCurrentSession不能使用OpenSession
c) @Transactional详解
i. 什么时候rollback
1. 运行期异常,非运行期异常不会触发rollback
2. 必须uncheck (没有catch)
3. 不管什么异常,只要你catch了,spring就会放弃管理
4. 事务传播特性:propagation_required(propagation是一个enum,默认值是required!唯一需要记住的)
例如:@Transactional(propagation=Propagation.REQUIRED)等同于(@Transactional)
作用,一个方法声明了@Transactional事务后,其内再调用的方法不需要再声明@Transactional.
5. read_only
例如:@Transactional(propagation=Propagation.REQUIRED,readOnly=true)
当方法声明readOnly=true时,该方法及其调用的方法内都不执行insert update等
Property | Type | Description |
|
enum: Propagation | optional propagation setting |
| |
isolation | enum: Isolation | optional isolation level |
|
readOnly | boolean | read/write vs. read-only transaction |
|
timeout | int (in seconds granularity) | the transaction timeout |
|
rollbackFor | an array of Class objects, which must be derived from Throwable | an optional array of exception classes which must cause rollback | 自己设置的异常回滚 |
rollbackForClassname | an array of class names. Classes must be derived from Throwable | an optional array of names of exception classes that must cause rollback |
|
noRollbackFor | an array of Class objects, which must be derived from Throwable | an optional array of exception classes that must not cause rollback. |
|
noRollbackForClassname | an array of String class names, which must be derived from Throwable | an optional array of names of exception classes that must not cause rollback |
|
d) xml(推荐,可以同时配置好多方法)
i. <bean txmanager
ii. <aop:config
1. <aop:pointcut
2. <aop:advisor pointcut-ref advice-ref
iii. <tx:advice: idtransaction-manager =
iv. <propertyname="packagesToScan"> 可定义扫描目标包下所有实体类
例如: <bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource"ref="dataSource" />
<propertyname="hibernateProperties">
<props>
<propkey="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<propkey="hibernate.show_sql">true</prop>
</props>
</property>
<!--
<propertyname="annotatedClasses">
<list>
<value>com.bjsxt.model.TestUser</value>
<value>com.bjsxt.model.Log</value>
</list>
</property>
-->
<!-- 将参数名称设为packagesToScan 可定义扫描目标包下所有实体类 -->
<property name="packagesToScan">
<list>
<value>com.bjsxt.model</value>
</list>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<propertyname="sessionFactory">
<refbean="sessionFactory" />
</property>
</bean>
<aop:config>
<aop:pointcut
expression="execution(public* com.bjsxt.service..*.*(..))"
id="myServiceMethod"/>
<aop:advisor pointcut-ref="myServiceMethod"advice-ref="txAdvice"/>
</aop:config>
<tx:adviceid="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="cancel*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
e) HibernateTemplate(理解这个)、HibernateCallback、HibernateDaoSupport(不重要)介绍
i. 设计模式:TemplateMethod(模板方法)
ii. Callback:回调/钩子函数
iii. 第一种:(建议)
1. 在spring中初始化HibernateTemplate,注入sessionFactory
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory"ref="sessionFactory" />
</bean>
2. DAO里注入HibernateTemplate
private HibernateTemplate hibernateTemplate;
@Resource
public void setHibernateTemplate(HibernateTemplatehibernateTemplate) {
this.hibernateTemplate= hibernateTemplate;
}
3. save写getHibernateTemplate.save();
public void save(TestUser testUser) {
hibernateTemplate.save(testUser);
}
iv. 第二种:
1. 从HibernateDaoSupport继承(此方法不好用可忽略)
2. 必须写在xml文件中,无法使用Annotation,因为set方法在父类中,而且是final的
例如:
首先,新建SuperDAOImpl类(使用Annotation注入--@Component):
@Component
public class SuperDAOImpl {
privateHibernateTemplate hibernateTemplate; //此处定义由spring注入管理
publicHibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
@Resource
public voidsetHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate =hibernateTemplate;
}
}
此时,xml中必须要有:
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<propertyname="sessionFactory" ref="sessionFactory" />
</bean>
或者,SuperDAOImpl类写成下面代码:
@Component
public class SuperDAOImpl extends HibernateDaoSupport {
@Resource(name="sessionFactory")
public voidsetSuperHibernateTemplate(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
}
对应的xml中则可省略
<bean id="hibernateTemplate"………部分
只要包含
<bean id="sessionFactory"……..部分即可
最后,其他类继承SuperDaoImpl类后便可直接使用HibernateTemplate
@Component("u")
public class UserDAOImpl extends SuperDAOImpl implementsUserDAO {
public voidsave(TestUser testUser) {
this.getHibernateTemplate().save(testUser);
}
}
第三种:
f) spring整合hibernate的时候使用packagesToScan属性,可以让spring自动扫描对应包下面的实体类
Struts2.1.6 + Spring2.5.6 + Hibernate3.3.2
1. 需要的jar包列表
jar包名称 | 所在位置 | 说明 |
antlr-2.7.6.jar | hibernate/lib/required | 解析HQL |
aspectjrt | spring/lib/aspectj | AOP |
aspectjweaver | .. | AOP |
cglib-nodep-2.1_3.jar | spring/lib/cglib | 代理,二进制增强 |
common-annotations.jar | spring/lib/j2ee | @Resource |
commons-collections-3.1.jar | hibernate/lib/required | 集合框架 |
commons-fileupload-1.2.1.jar | struts/lib | struts |
commons-io-1.3.2 | struts/lib | struts |
commons-logging-1.1.1 | 单独下载,删除1.0.4(struts/lib) | struts spring |
dom4j-1.6.1.jar | hibernate/required | 解析xml |
ejb3-persistence | hibernate-annotation/lib | @Entity |
freemarker-2.3.13 | struts/lib | struts |
hibernate3.jar | hibernate |
|
hibernate-annotations | hibernate-annotation/ |
|
hibernate-common-annotations | hibernate-annotation/lib |
|
javassist-3.9.0.GA.jar | hiberante/lib/required | hibernate |
jta-1.1.jar | .. | hibernate transaction |
junit4.5 |
|
|
mysql- |
|
|
ognl-2.6.11.jar | struts/lib |
|
slf4j-api-1.5.8.jar | hibernate/lib/required | hibernate-log |
slf4j-nop-1.5.8.jar | hibernate/lib/required |
|
spring.jar | spring/dist |
|
struts2-core-2.1.6.jar | struts/lib |
|
xwork-2.1.2.jar | struts/lib | struts2 |
commons-dbcp | spring/lib/jarkata-commons |
|
commons-pool.jar | .. |
|
struts2-spring-plugin-2.1.6.jar | struts/lib |
|
2. BestPractice:
a) 将这些所有的jar包保存到一个位置,使用的时候直接copy
3. 步骤
a) 加入jar包
b) 首先整合Spring + Hibernate
i. 建立对应的package
1. dao / dao.impl / model / service / service.impl/ test
ii. 建立对应的接口与类框架
1. S2SH_01
iii. 建立spring的配置文件(建议自己保留一份经常使用的配置文件,以后用到的时候直接copy改)
iv. 建立数据库
v. 加入Hibernate注解
1. 在实体类上加相应注解@Entity @Id等
在字段属性的get方法上加--@Column(name = "表字段名")
2. 在beans配置文件配置对应的实体类,使之受管
vi. 写dao service的实现
vii. 加入Spring注解
1. 在对应Service及DAO实现中加入@Component,让spring对其初始化
2. 在Service上加入@Transactional或者使用xml方式(此处建议后者,因为更简单)
3. 在DAO中注入sessionFactory
4. 在Service中注入DAO
5. 写DAO与Service的实现
viii. 写测试
c) 整合Struts2
i. 结合点:Struts2的Action由Spring产生
ii. 步骤:
1. 修改web.xml加入 struts的filter
如下:
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 再加入spring的listener,这样的话,webapp一旦启动,spring容器就初始化了
如下:
<!-- 指定由spring初始化加载xml配置文件 spring与struts结合必备 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
<!-- 默认寻找xml路径:WEB-INF/applicationContext.xml -->
</listener-class>
</listener>
<!--整个应用的参数服务启动时读取.
可指定spring初始化文件路径位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:spring/*applicationContext.xml
</param-value>
</context-param>
3. 规划struts的action和jsp展现
4. 加入struts.xml
a) 修改配置,由spring替代struts产生Action对象
5. 修改action配置
a) 把类名改为bean对象的名称,这个时候就可以使用首字母小写了
b) @Scope(“prototype”)不要忘记
iii. struts的读常量:
1. struts-default.xml
2. struts-plugin.xml
3. struts.xml
4. struts.properties
5. web.xml
iv. 中文问题:
1. Struts2.1.8已经修正,只需要改i18n.encoding= gbk
2. 使用spring的characterencoding
例:
<!-- 过滤器相关配置 ======== 字符编码过滤======== -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
3. 需要严格注意filter的顺序
4. 需要加到Struts2的filter前面
v. LazyInitializationException
1. OpenSessionInViewFilter
2. 需要严格顺序问题
3. 需要加到struts2的filter前面
附:
1.
@Autowired 与@Resource 都可以用来装配bean. 都可以写在属性定义上,或写在set方法上
@Autowired (srping提供的) 默认按类型装配
@Resource ( j2ee提供的 ) 默认按名称装配,当找不到(不写name属性)名称匹配的bean再按类型装配.
可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是指定了name属性, 就用字段名去做name属性值,一般不用写name属性.
@Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.
@Autowired 与@Resource可作用在属性定义上, 就不用写set方法了(此方法不提倡);
2.
a.
Action类前加@Component,则Action可由spring来管理,例子如下:
Action中写:
@Component("u") //spring管理注解
@Scope("prototype") //多态
public class UserAction extends ActionSupportimplements ModelDriven{
//内部属性需要有get/set方法且需要set方法前加@Resource或@Autowired
}
Struts2配置文件中写
<action name="u"class="u">
Jsp中
<form method="post"action="u.do" >
b.
Action中也可不加@Component,Action由struts2-spring-plugin管理。此时,如果Action中定义的属性有set方法则@Autowired 与@Resource也可不写,但是如果没有set方法,则需要在属性前加上@Autowired 或@Resource才能生效。
3.
Hibernate如果使用load来查询数据,例如:
Service中:
public User loadById(int id) {
returnthis.userDao.loadById(id);
}
DAO中:
public User loadById(int id) {
return(User)this.hibernateTemplate.load(User.class, id);
}
此时,session(应该说的是Hibernate的session)在事物结束(通常是service调用完)后自动关闭。由于使用的是load获取数据,在jsp页面申请取得数据时才真正的执行sql,而此时session已经关闭,故报错。
Session关闭解决方法:
在web.xml中增加filter—openSessionInView,用于延长session在jsp调用完后再关闭
如下所示:
注意:filter–openSessionInView 一定要在 filter—struts2之前调用
Filter顺序—先进后出!
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sf</param-value>(此处默认指定的sessionFactory应为” sessionFactory” 默认可省略此行如果shring配置文件中配置的sessionFactory为”sf” 则此处需要写sf 一般用不到)
</init-param>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter </filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>