一、spring所需的jar包(http://download.csdn.net/detail/huangzebiao007/6368161)
二、数据源jar包(http://download.csdn.net/detail/huangzebiao007/6367981)
三、第一个Spring例子
1、创建applicationContext.xml文件,配置要管理的bean
<?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">
<bean id="test" class="com.hzb.business.TestBusiness" scope="prototype"><!--scope属性表示为不是单例,因为spring中默认是单例的,所以这里要加上-->
<property name="name" value="hzb"/>
</bean>
</beans>
2、创建business类
package com.hzb.business;
public class TestBusiness {
private String name;
public String sayHello(){
return name+":hello world!";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3、创建测试类
package com.hzb.DI;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hzb.business.TestBusiness;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
TestBusiness business = (TestBusiness)ctx.getBean("test");
System.out.println(business.sayHello());
}
}
说明:通过ClassPathXmlApplicationContext找到spring配置文件,配置文件名可以任意,也可以有多个,放在任意文件夹下也行,只要指定他的路径就可以了,例如如果是放在com.hzb.business包下,则可以通过/com/hzb/business/applicationContext.xml找到该配置文件;然后获取到bean中对应的实例对象,从而调用,实例对象中的属性也通过<property name="name" value="hzb"/>标签设置进去。
四、web应用中加入spring框架
1、如果是放在WEB-INF路径下,则直接在web.xml中加入
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2、如果不是,则
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:/com/hzb/business/applicationContext.xml </param-value> </context-param>
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
3、如果有多个spring配置文件,可以有3种方式解决
一种是先执行上面第一步,然后在spring文件中导入其他配置文件
<import resource="applicationContext-business.xml"/>
<import resource="applicationContext-hibernate.xml"/>
另一种是直接在web.xml中配置,用通配符的形式
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
还有一种是直接在<param-value> 写,但要用逗号隔开
五、各种数据类型的属性在XML文件中的注入方式
1、普通属性
<property name="类中属性名" value="值"/>
<property name="类中属性名">
<value>值</value>
</property>
如果是外部类路径下有个properties配置文件,则我们可以用context:property-placeholder把配置文件加载进来,再通过${dir}来读取键从而读取到值。
<context:property-placeholder location="classpath:info.properties"/>
<bean id="test" class="com.hzb.test.Test"> <property name="dir" value="${dir}"/> </bean>
2、其他bean
<property name="类中属性名" ref="另一个bean"/>
<property name="类中属性名">
<ref bean="另一个bean"/>
</property>
<property name="reportType">
<ref local="另一个bean"/>
</property>
bean和local的区别是local是表示只在该xml文件中查找,而bean则是会查找所有的xml文件,一般都是用bean
3、List类型
<property name="listValue">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<property name="listValue">
<list>
<ref bean="admin"/>
<ref bean="person"/>
</list>
</property>
如果我们用spring的util标签,则还有以下的方式(要先在spring配置文件中引入一些配置)
spring的头部文件改为了如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<property name="lists2">
<ref bean="listtwo"/>
</property>
<!-- list-class="java.util.ArrayList" value-type="com.isw2.po.People"可不写 -->
<util:list id="listtwo" list-class="java.util.ArrayList" value-type="com.hzb.po.People">
<!-- <bean class="com.hzb.po.Admin"/>
<bean class="com.hzb.po.Person"/>
<bean class="com.hzb.po.User"/>-->
<ref bean="admin"/>
<ref bean="person"/>
<ref bean="user"/>
</util:list>
<bean id="admin" class="com.hzb.po.Admin"/>
<bean id="person" class="com.hzb.po.Person"/>
<bean id="user" class="com.hzb.po.User"/>
4、map类型
<property name="maps">
<map>
<entry key="hzb" value="14"/>
<entry key="hzb2" value="24"/>
<entry key="hzb3" value="34"/>
</map>
</property>
<property name="maps">
<ref bean="mapsone"/>
</property>
<!-- map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String"可不写 -->
<util:map id="mapsone" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
<entry key="lihuoming" value="28"/>
<entry key="lihuoming2" value="38"/>
<entry key="lihuoming3" value="48"/>
</util:map>
<property name="maps2">
<map>
<entry key="a" value-ref="admin"/>
<entry key="p" value-ref="person"/>
<entry key="u" value-ref="user"/>
</map>
</property>
<property name="maps3">
<map>
<entry key-ref="admin" value-ref="admin"/>
<entry key-ref="person" value-ref="person"/>
<entry key-ref="user" value-ref="user"/>
</map>
</property>
map说明,如果是基本属性,就不加-ref,如果不是,则要加-ref,key和value都一样
5、set类型
<property name="setValue">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<property name="setValue">
<set>
<ref bean="admin"/>
<ref bean="user"/>
</set>
</property>
6、数组类型
<property name="arrayValue">
<list>
<value>array1</value>
<value>array1</value>
</list>
</property>
<property name="arrayValue">
<list>
<ref bean="user"/>
<ref bean="user"/>
</list>
</property>
六、三种实例化 bean 的方式:1.使用类构造器实例化
<bean id=“orderService" class="com.hzb.OrderServiceBean"/>
2.使用静态工厂方法实例化
<bean id="personService" class="com.hzb.service.OrderFactory" factory-method="createOrder"/>
public class OrderFactory {
public static OrderServiceBean createOrder(){
return new OrderServiceBean();
}
}
3.使用实例工厂方法实例化:
<bean id="personServiceFactory" class="com.hzb.service.OrderFactory"/>
<bean id="personService" factory-bean="personServiceFactory" factory-method="createOrder"/>
public class OrderFactory {
public OrderServiceBean createOrder(){
return new OrderServiceBean();
}
}
七、AOP
1、spring配置文件中添加头部aop配置和配置aop切面
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:config>
<aop:aspect id="log" ref="logPrint">
<aop:pointcut id="businessService"
expression="execution(* com.hzb.business.*.*(..))" /> <!-- 配置com.hzb.business包下所有类或接口的所有方法 -->
<aop:before pointcut-ref="businessService" method="doBefore"/> <!--这里的method参数是指定前置通知的方法,跟切面类中的方法一致-->
<aop:after pointcut-ref="businessService" method="doAfter"/>
<aop:around pointcut-ref="businessService" method="doAround"/>
</aop:aspect>
</aop:config>
<bean id="logPrint" class="com.hzb.aop.LogPrint" />
<bean id="test" class="com.hzb.business.TestBusiness" />
</beans>
2、创建切面类,该切面类就可以对aop标签中配置的类进行处理了
package com.hzb.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class LogPrint {
private long beforeTime;
private long afterTime;
//定义前置通知
public void doBefore() {
beforeTime = System.currentTimeMillis();
System.out.println("方法开始运行前的时间:" + beforeTime);
}
//定义后置通知
public void doAfter() {
afterTime = System.currentTimeMillis();
System.out.println("方法运行结束后的时间:" + afterTime);
System.out.println("该方法运行时间:"+(afterTime-beforeTime));
}
//定义环绕通知
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知1");
pjp.proceed();//如果是用了环绕通知,这步就一定要,不然不会执行主程序
System.out.println("环绕通知2");
return null;
}
}
3、创建被aop处理的业务类
package com.hzb.business;
public class TestBusiness {
public void sayHello(){
System.out.println("hello world!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4、用测试类调用上面的业务类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hzb.business.TestBusiness;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
TestBusiness business = (TestBusiness) ctx.getBean("test");
business.sayHello();
}
}
运行结果如下:
方法开始运行前的时间:1381287198203
环绕通知1
hello world!
方法运行结束后的时间:1381287199203
该方法运行时间:1000
环绕通知2
5、execution(* com.hzb.business.*.*(..))说明
第一个*表示匹配任意的返回类型,第二个*表示匹配com.hzb.business包下的任意子类(不包括孙子类),第三个*表示匹配子类中的任意方法,(..)表示匹配方法中任意的参数
6、个人总结:aop的执行流程:前置通知代码块->环绕通知pjp.proceed();方法前的代码块->业务逻辑代码块->后置通知代码块->环绕通知pjp.proceed();方法后的代码块
八、配置数据源
1、dbcp数据源的配置
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/shujukuName?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="1"/>
<!-- 连接池的最大值 -->
<property name="maxActive" value="20"/>
<!-- 最大空闲值。当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
<property name="minIdle" value="3"/>
<property name="maxIdle" value="20"/>
<!-- 最小空闲值。当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
<property name="maxWait" value="60000"/>
<property name="defaultAutoCommit" value="true" />
<!--#在取出连接时进行有效验证-->
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="180" />
</bean>
2、c3p0数据源的配置
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="jdbcUrl">
<value>jdbc:mysql://localhost:3306/shujukuName?useUnicode=true&characterEncoding=UTF-8</value>
</property>
<property name="user">
<value>root</value>
</property>
<property name="password">
<value>root</value>
</property>
<!--连接池中保留的最小连接数。-->
<property name="minPoolSize">
<value>1</value>
</property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">
<value>30</value>
</property>
<!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize">
<value>3</value>
</property>
<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">
<value>60</value>
</property>
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime">
<value>60</value>
</property>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">
<value>5</value>
</property>
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements">
<value>0</value>
</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">
<value>30</value>
</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">
<value>true</value>
</property>
<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">
<value>false</value>
</property>
</bean>
上面的配置是从以前的项目中拷贝过来的,具体怎样的配置才是最好的,还有待研究。
九、配置sessionFactory
如果spring跟hibernate整合的话,一般还要配置会话工厂
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>
</props>
</property>
<!-- Mapping 到对应的Bo文件 -->
<property name="mappingResources">
<list>
<value>com/hzb/xml/A.hbm.xml</value>
<value>com/hzb/xml/B.hbm.xml</value>
</list>
</property>
</bean>
DAO一般都继承了HibernateDaoSupport类,里面有个sessionFactory属性,所以,可以用下面的方式注册DAO
<bean id="UserDAO" class="com.hzb.dao.UserDAO">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
十、Spring
对
Hibernate
事务管理
当Spring对Hibernate进行整合之后,我们不再是每次都去拿Session进行数据操作了,也不需要每次都开启事务,提交事务,我们只需要Spring给我们提供的一个HibernateTemplate,我们直接用这个类里面给我们提供的数据操作方法就可以操作数据了。Spring在他的操作方法里面封装了事务处理。用HibernateTemplate里面提供的方法操作数据时我们要注意的一点是,在集成Hibernate时,数据源要配置在spring文件中,不能配置在hibernate.cfg.xml中,因为如果你用 hibernate.cfg.xml文件配置数据源,由于Hibernate默认是手动提交事务,所以你用HibernateTemplate里面的方法插入数据库就会不成功了,而如果你用Spring的配置文件来配置数据源,Sping默认是自动提交的,所以就会成功。
虽然spring会自动提交事务,但是这样并不满足我们实际的业务需求,因为有时候在我保存一个数据之后,我希望他能继续保存另一条数据,我希望在保存完两条或者多条之后一起进行事务提交,这样即使出错,我们可以回滚,取得数据的一致性,要么都成功要么都失败,而spring是默认保存一条数据就提交的,这样不能让几条语句在同一个事务当中,我们不能保证数据的一致行。所以这时候我们就需要手动的来配置我们的事务,这就需要用到Spring为Hibernate提供的事务管理机制,Spring提供的事务管理可以分为两类:编程式的和声明式的,编程式,其实就是在代码里面来控制,像Hibernate操作数据一样,开启事务,提交事务,这种方式有一定的局限性,所以我们一般是用声明式来配置我们的事务,步骤如下:
<!--1、配置事务管理器 指定其作用的sessionFactory把事务交给Spring去处理 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!-- 2、配置事务的传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="get*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 3、配置那些类的哪些方法参与事务,一般我们是把事务边界设置到业务逻辑层 -->
<aop:config>
<aop:pointcut id="allBusinessMethod" expression="execution(* com.hzb.business.*.*(..))"/>
<aop:advisor pointcut-ref="allBusinessMethod" advice-ref="txAdvice"/>
</aop:config>
十一、Spring中HibernateDaoSupport类中的常用方法
package com.hzb.dao;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* 所实现的DAO类必须继承BaseDAO, BaseDAO提供了一组常用的持久方法.
* 在使用时只需要直接调用即可.
*/
public abstract class BaseDAO extends HibernateDaoSupport {
/**
* 将对象持久化到数据库中.
*
* @param transientInstance - 持久化对象.
*/
public void save(Object transientInstance) {
getHibernateTemplate().save(transientInstance);
}
/**
* 更新方法.
*
* @param detachedInstance - 持久化对象.
*/
public void update(Object detachedInstance) {
getHibernateTemplate().update(detachedInstance);
}
/**
* 更新方法.
*
* @param detachedInstance - 持久化对象.
* @return - Object 更新后的持久化对象.
*/
public Object merge(Object detachedInstance) {
return getHibernateTemplate().merge(detachedInstance);
}
/**
* 新增或更新方法.
*
* @param transientInstance - 持久化对象.
*/
public void saveOrUpdate(Object transientInstance) {
getHibernateTemplate().saveOrUpdate(transientInstance);
}
/**
* 删除方法.
*
* @param persistentInstance - 持久化对象.
*/
public void delete(Object persistentInstance) {
getHibernateTemplate().delete(persistentInstance);
}
/**
* 根据主键(id)进行查找一条数据.
*
* @param id - 要查找的主键(id).
* @return - 返回一个Object对象, 在使用方需要转型.
*/
public Object get(Class<?> clazz, long id) {
return getHibernateTemplate().get(clazz, id);
}
/**
* 根据主键(id)进行查找一条数据.
*
* @param id - 要查找的主键(id).
* @return - 返回一个Object对象, 在使用方需要转型.
*/
public Object get(Class<?> clazz, String id) {
return getHibernateTemplate().get(clazz, id);
}
/**
* 根据传入ID查找数据
* @param id
* @return
*/
public Object load(Class<?> clazz,long id) {
return getHibernateTemplate().load(clazz, id);
}
/**
* 根据传入ID查找数据
* @param id
* @return
*/
public Object load(Class<?> clazz, String id) {
return getHibernateTemplate().load(clazz, id);
}
/**
* 根据传入hql查找数据
* @param hql
* @return
*/
public List<?> find(String hql){
return getHibernateTemplate().find(hql);
}
/**
* 根据传入hql查找数据
* @param hql,attrs,values
* @return
*/
public List<?> findByNamedParam(String hql, String[] attrs, Object[] values){
if (null != attrs && null != values &&
attrs.length == values.length) {
return getHibernateTemplate().findByNamedParam(hql,attrs,values);
} else {
return null;
}
}
/**
* 在SessionFactory中获取Session对象.
* @return - Hibernate Session对象.
*/
public Session getCurrentSession() {
return SessionFactoryUtils.getSession(getSessionFactory(), true);
}
/**
* 在SessionFactory中关闭Session对象.
*/
public void closeSession(Session session) {
SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
}
如果需要使用hibernate中的方法,则可以用下面的方法:
getHibernateTemplate().executeFind(new HibernateCallback(){
@Override
public List<?> doInHibernate(Session session)
throws HibernateException, SQLException {
String hql = "*****";
return session.createSQLQuery(hql).list();
}
})