首页 > WEB开发 > 后台开发 > Spring框架整合篇
2014
10-05

Spring框架整合篇

二、Spring整合Hibernate

在整合Hibernate时,Spring也提供了如下三个类:

11. 框架整合篇7458

有了Spring整合Jdbc的基础,不难推出:在实际开发时,大多是继承HibernateDaoSupport,且在IoC中配置xxxDao时应向其注入SessionFactory。

1、整合Demo

Demo说明:实体类为Person,PersonDaoImpl、PersonServiceImpl为Dao层和Service层的实现类,其提供了保存和查找一条记录的操作。要求在Dao层实现Spring和Hibernate整合,在Service层的事务管理使用Spring的声明式事务管理。

1)搭建整合开发环境

① 搭建Hibernate开发环境(拷贝jar包、配置文件、映射文件等等,这儿的重点不是这个)

② 搭建Spring开发环境(拷贝jar包、配置文件等)

2)Dao层

PersonDaoImpl类(继承HibernateDaoSupport):

public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao {

	public void save(Person person) {
		this.getHibernateTemplate().save(person);
	}

	public Person getById(String id) {
		return (Person) this.getHibernateTemplate().find("from Person where id = ?", id).get(0);
	}
}

修改Spring配置文件:在Spring容器中配置sessionFactory,并注入到PersonDaoImpl中:

<bean id="sessionFactory"
	class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
	<property name="configLocation">
		<value>classpath:hibernate.cfg.xml</value>
	</property>
</bean>

<!-- 配置Dao:注入sessionFactory -->
<bean id="personDao" class="org.flyne.dao.impl.PersonDaoImpl">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

3) Service层、事务管理配置

public class PersonServiceImpl implements PersonService{

	private PersonDao personDao;

	public void setPersonDao(PersonDao personDao) {
		this.personDao = personDao;
	}

	public void savePerson(Person person) {
		personDao.save(person);
	}

	public Person getPersonById(String id) {
		return personDao.getById(id);
	}
}
-------------在applicationContext.xml中配置Service----------
<bean id="personService" class="org.flyne.service.impl.PersonServiceImpl">
	<property name="personDao" ref="personDao"></property>
</bean>

修改Spring配置文件:声明事务通知、配置AOP

<!-- 事务通知需要引用事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
	<property name="sessionFactory">
		<ref bean="sessionFactory"/>
	</property>
</bean>
<!-- 事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
		<tx:method name="*"/>
	</tx:attributes>
</tx:advice>

<!-- 配置AOP -->
<aop:config>
	<aop:pointcut
			expression="execution(* org.flyne.service.impl.*.*(..))"
			id="perform"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="perform"/>
</aop:config>

4)测试

① 插入成功的测试

public class PersonDaoImplTest {
	private static ApplicationContext applicationContext;

	@BeforeClass
	public static void init(){
		applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	}
	@Test
	public void testPersonDaoImpl() throws Exception{
		Person person = new Person();
		person.setName("flyne-Hibernate");
		person.setAge(24);

		PersonService personService = (PersonService)applicationContext.getBean("personService");

		personService.savePerson(person);
	}
}

数据库中增加了一条记录则表明整合成功。

② 事务测试:修改PersonServiceImpl.savePerson方法如下:

personDao.save(person);
int i = 1/0;
personDao.save(person);

再次运行测试类中的测试方法,如果数据库中没有插入新数据,则表明事务管理被添加到savePerson上了。

5)sessionFactory的另外一种声明方式(推荐)

将在Hibernate配置文件中的内容移到Spring配置文件中:在sessionFactory中注入dataSource、指定映射文件目录以及Hibernate属性。所以,一个整合了Hibernate的项目中可以不出现Hibernate配置文件。

<bean id="sessionFactory"
	class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="mappingDirectoryLocations">
		<list>
			<!-- spring容器会去该包及子包下搜索所有的映射文件 -->
			<value>org/flyne/domain</value>
		</list>
	</property>
	<property name="hibernateProperties">
		<props>
			<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
			<prop key="hibernate.show_sql">true</prop>
			<prop key="hibernate.hbm2ddl.auto">update</prop>
		</props>
	</property>
</bean>

2、HibernateCallBack接口(策略设计模式)

Spring提供的HibernateTemplate封装了常用的Hibernate操作,但却降低了访问数据库时的灵活性(只能按照Spring提供的操作方式)。为此,Spring还提供了一个HibernateCallBack接口,开发人员通过该接口的doInHibernate方法,可以完全使用Hibernate灵活的方式来访问数据库,解决Spring封装Hibernate后灵活性不足的问题。该接口是以一个参数传递给HibernateTemplate.execute方法的。

HibernateTemplate类和HibernateCallBack接口的关系 以及 在XxxDaoImpl中调用HibernateTemplate.execute后的执行流程见下图:

11. 框架整合篇11531

Demo:HibernateCallBack的用法(仅仅是为了举例,实际不会这么用)

public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao {
	public Person getByName(final String name){
		return (Person)this.getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session){
				Query query = session.createQuery("from Person where name=:name");
				query.setParameter("name", name);
				return query.uniqueResult();
			}
		});
	}
}

三、Struts2整合Spring

Struts2晚于Spring出现,所以Struts2框架提供了整合Spring的插件:struts-spring-plugin.jar。关于Struts2和Spring整合的原理见《Struts2工作流程、源码分析》一文。

1、Spring容器只管理Service、Dao

1)搭建Struts2的开发环境,包括拷贝jar包、配置web.xml和struts.xml等,这一步具体见《Struts2入门》一文。

2)搭建Spring开发环境:

① 拷贝开发包spring.jar,该包位于spring\dist目录下。

② 创建Spring工程的配置文件applicationContext.xml,放置于WEB-INF目录下,内如如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

</beans>

③ 在web.xml中配置Spring的监听器:

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息(之前的项目不是web项目,所以不用配这一项)。

3)拷贝struts2-spring-plugin-2.3.15.3.jar包,该插件包由Struts提供,位于struts-2.3.15.3\lib目录下。

4)编写Service、Dao层

仅作演示使用,没有实现任何逻辑和功能,在Dao层的实现中打印一句话去模拟。

--------------Dao层--------------
public interface UserDao {
	void add();
}
public class UserDaoImpl implements UserDao {
	public void add() {
		System.out.println("保存了");
	}
}
-----------------Service层-----------------------
public interface UserService {
	void register();
}
public class UserServiceImpl implements UserService {
	private UserDao dao ;

	//提供setDao方法,dao实例可由Spring注入
	public void setDao(UserDao dao) {
		this.dao = dao;
	}

	public void register() {
		dao.add();
	}
}

5)在applicationContext.xml中增加如下配置

<bean name="userService" class="org.flyne.service.impl.UserServiceImpl" >
	<property name="dao" ref="userDao"></property>
</bean>
<bean name="userDao" class="org.flyne.dao.impl.UserDaoImpl"></bean>

6)编写动作类

public class StrutsSpringAction extends ActionSupport {
	private UserService userService ;

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public String execute() throws Exception {
		userService.register();
		return NONE;
	}
}

7)在struts.xml中增加如下配置

<package name="p1" extends="struts-default">
	<action name="act1" class="org.flyne.action.StrutsSpringAction"/>
</package>

8)访问http://localhost:8080/struts2_spring2/act1,控制台输出“保存了”,说明StrutsSpringAction类中的execute方法成功的执行了。

9)Spring框架和Struts-Spring插件都做了什么?

Spring框架会生成UserDaoImpl和UserServiceImpl的实例放在Spring容器中。

Struts2框架在执行动作类中的userService.register()时,由于userService为null.,就会去Spring容器中看有没有userService这个对象。这一过程是由Struts2-Spring插件完成的。

2、将动作类也放入Spring容器

本节在上面的案例的基础上进行修改。

1)在applicationContext.xml中增加一个bean元素,如下:

<bean name="SSAction" class="org.flyne.action.StrutsSpringAction" scope="prototype">
	<property name="userService" ref="userService" />
</bean>

2)修改struts.xml中action元素

<package name="p1" extends="struts-default">
	<action name="act1" class="SSAction"/>
</package>

3)访问http://localhost:8080/struts2_spring2/act1,控制台输出“保存了”,说明StrutsSpringAction类中的execute方法成功的执行了。

4)说明:

① Spring配置文件中,bean元素的scope属性默认值为singleton(单例)。在Spring容器中配置动作类时要设置scope为prototype(多例),这是因为用户的每次action请求都会生成一个动作类的实例。

② 当接收一个action请求时,struts-spring插件会根据class属性值(此处为SSAction)去Spring容器中查找相应的Action对象,找不到时会利用反射(根据class属性值)创建Action对象,并放入Spring容器中。


Spring框架整合篇》有 1 条评论

留下一个回复

你的email不会被公开。