spring 2.5 基础知识和与其他框架的集成
spring环境搭建:
一:导入spring2.5所需的包,在classpath目录下建一个名为"beans.xml"模板文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
这里写代码
</beans>
二:spring得到实例:一:通过该类本身的构造方法(可以进行构造注入)得到实例,然后再进行setter注入。
二是:通过其他类的静态方法或其他bean的动态方法(可以进行构造注入)得到未知实例,未知实例再调用setter进行注入
例如:
<bean id="id号" class="包名.类名"/>
<bean id="id号" class="包名.类名" factory-method="该类的静态方法"/>
<bean id="id号" factory-bean="其他的bean" factory-method="其他bean中动态方法" />
解释:如果在"bean" 标签上加了 scope="prototype"设置,表示原型,那么spring容器开启时,不能获得实例,只有getBean()时才会得到实例,这样得到的实例不是同一个实例。加了lazy-init="true"表示懒加载,那么spring容器开启时,不能获得实例,但得到是同一个实例。同理,如果在"beans" 标签上加了 default-lazy-init="true",则是对所有bean设置的。
如果在"bean" 标签上加了 init-method="该bean对应类中的方法"设置,则表示得到实例后就调用的方法。
如果在"bean" 标签上加了 destroy-method="该bean对应类中的方法"设置,则表示实例销毁前调用的方法(spring 容器关闭,则实例销毁)
A:依赖注入:
一种方式为构造注入:<constructor-arg index="0" type="包名.类名" value="***"/> //基本类型和String类型可以不用写type
一种方式为setter方法注入:
<property name=" setter方法名的关键字" value=""/> //适用于基本类型和String类型
<property name="setter方法名的关键字" [ref=""|local=""]/> //其中local表示本地的bean,就是该xml文件中bean,
<property name="setter方法名的关键字"><bean class="包名.类名"/></property>
如果bean中的属性是集合类型,那么一般采用setter方式进行注入:
对于Set集合:
<property name="sets">
<set>
<value>李鹏生</value>
<value>李小龙</value>
<value>李嘉城</value>
<value>李鹏</value>
</set>
</property>
对于List集合和数组:
<property name="list">
<list>
<value>秦始皇</value>
<value>李世民</value>
<value>李自成</value>
</list>
</property>
对于Map集合:
<property name="map">
<map>
<entry key="key1" value="one"/>
<entry key="key2" value="two"/>
<entry key="key3" value="three"/>
</map>
</property>
对于Properties集合:
<property name="prop">
<props>
<prop key="key1">第一个</prop>
<prop key="key2">第二个</prop>
<prop key="key3">第三个</prop>
</props>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=false
</value>
</property>
B:采用注解方式进行依赖注入:
在beans.xml中加入代码:
xmlns:context=http://www.springframework.org/schema/context
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
打开注解配置项:
<context:annotation-config/>
两种注解:一是:@Autowired 是按类型装配 二是:@Resource 默认是按名称装配,就是根据id名称装配,如果找不到,会按类型装配。
下面举两个例子说明下: 如:@Resource PersonDao personDao; 其中PersonDao是一个接口,如果PersonDaoImpl是PersonDao接口的实现类。它是怎么装配的呢,首先它是找到名称为"personDao"id的bean,如果找到,但并不是PersonDao接口的实现类,则出异常;如果找不到名称为"personDao"id的bean,则按类型找,找PersonDao接口的实现类,如果实现类是多个,那么就会异常。
所以说接口的实现类为多个的话,就按名称装配。同样的道理,如果一个类有它的子类,而我们想得到子类的实例,然后进行向上转型,那么就要按照名称装配,而不是类型装配了。
例子:@Resource private Ni n,或者这样:private Ni n; @Resource public void setNi(Ni n){this.n=n;} 方法名可以是任意名称,不一定是"setNi",本质是调用这个方法而已,只是容易见名思义。
建议:使用@Resource 注解;变量名称为bean的id名称;使用"setNi"这种格式的方法名。本质是调用这个方法而已,只是容易见名思义。
三:spring容器的实例化:
例如:
ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[]{"beans.xml"}); --可以实例化多个.xml文件。
得到bean的实例,得到之后要进行相应的转型,如:类名,父类,接口。
(类名,父类,接口) 引用名=(类名,父类,接口) ctx.getBean("该bean相应的id名");
四:spring 容器自动扫描和管理bean(代替了在beans.xml配置的<bean id="" class=""/>):
在beans.xml中加入代码:<context:component-scan base-package="com.itcast">(可以删掉之前的<context:annotation-config/> ) --其 中"com.itcast"也包括该包下的子包下类。
然后在该包及该包的子包下的类加上@Service(服务层组件)或@Controller(控制层组件)或@Repository(DAO层组件)或@Component(泛指组件)表示该类由
spring容器实例。
那么我们又是怎样得到哪些bean的实例呢,默认是这样得到的:该类的首字母小写。如:类名为:PersonServiceImpl,那么它的id为:personServiceImpl。
当然我们也可以更改bean的id.如:@Service("所要更改的id名称")。
我们也可以设置bean的作用域:没设置,默认是单例,也就是@Scope("singleton"),@Scope("[singleton|prototype|request|session|global session]")。
如果在类的某方法前面加上@PostConstruct 注解,表示该bean类实例后将执行该方法,通常命名为"init";如果在类的某方法前面加上@PreDestroy 注解,表示该bean类实例后将执行该方法,通常命名为"destroy".
总结:一种.xml中有bean标签,一种.xml中没有bean标签(即自动扫描和注解)。一种是.xml中依赖注入,一种是注解方式的依赖注入。
建议:使用@Resource 注解;变量名称为bean的id名称;使用"setNi"这种格式的方法名。本质是调用这个方法而已,只是容易见名思义。
spring管理的bean是怎么完成该bean父类的依赖注入的。如果父类是采用的是注解注入,则它按照装配原则自动完成的。
如果父类是采用的是在.xml中依赖注入,则需要在管理的bean中的bean标签中加入parent="父类bean所对应的id名称"。
五:spring集成jdbc和spring集成hibernate
步骤:一:配置数据源 二:配置SessionFactory(如果是集成hibernate的就会配置) 三:配置事务管理器 四:配置事务。
其中一、二步骤用于数据库连接方面的,三、四步骤用于Service层方面的,利用AOP技术对DAO层中的方法进行事务管理
配置数据源:
代码列子:
这里用到了.properties文件,当然你也可以不用,不过这样修改起来方便。
例子:
classpath下的jdbc.properties文件的代码:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/itcast?useUnicode=true&characterEncoding=UTF-8
username=root
password=admin
initialSize=1
maxActive=500
maxIdle=2
minIdle=1
相应beans.xml下的代码:
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="${initialSize}"/>
<!-- 连接池的最大值 -->
<property name="maxActive" value="${maxActive}"/>
<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
<property name="maxIdle" value="${maxIdle}"/>
<!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
<property name="minIdle" value="${minIdle}"/>
</bean>
<context:property-placeholder location="classpath:jdbc.properties"/> 指明.properties文件。
配置SessionFactory(将数据源注入到SessionFactory中):
例子一:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>cn/itcast/bean/Person.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=false
</value>
</property>
</bean>
例子二(数据源和SessionFactory都用到了.properties 文件):
classpath下jdbc.properties文件代码:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/cms?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
jdbc.username=root
jdbc.password=123456
jdbc.maxActive=300
jdbc.maxWait=5000
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
hibernate.format_sql=true
hibernate.connection.autocommit=false
hibernate.order_updates=true
hibernate.jdbc.use_scrollable_resultset=true
hibernate.use_sql_comments=true
hibernate.connection.release_mode=after_transaction
hibernate.current_session_context_class=thread
相应的beans.xml代码(这里就省略不写数据源了,当然也要指明.properties文件,这里也省略了):
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"> </property> <!-- 映射所有实体 --> <property name="packagesToScan"> <list> <value>com.yojosources.admin.po</value> <value>com.yojosources.business.po</value> <value>com.yojosources.member.po</value> <value>com.yojosources.privilege.po</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="javax.persistence.validation.mode">none</prop> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> <!-- 输出所有SQL语句到控制台 --> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <!-- 在log和console中打印出更漂亮的SQL --> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> <!-- 允许被缓存的JDBC 连接开启自动提交 --> <prop key="hibernate.connection.autocommit">${hibernate.connection.autocommit}</prop> <!-- 强制Hibernate按照被更新数据的主键,为SQL更新排序。 --> <prop key="hibernate.order_updates">${hibernate.order_updates}</prop> <!-- 允许Hibernate使用JDBC2的可滚动结果集。 --> <prop key="hibernate.jdbc.use_scrollable_resultset">${hibernate.jdbc.use_scrollable_resultset}</prop> <!-- hibernate将在SQL中生成有助于调式的注解信息 --> <prop key="hibernate.use_sql_comments">${hibernate.use_sql_comments}</prop> <!-- 指定Hibernate在何时释放 JDBC 连接 --> <prop key="hibernate.connection.release_mode">${hibernate.connection.release_mode}</prop> <!-- 同一个事务用一个session --> <!-- <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>--> </props> </property> </bean>
解释:这里用到了packagesToScan属性,它是指定要扫描哪些包里的数据库映射类,是mappingResource属性对立的又一种方式。先说说packagesToSan的用法:
1. <property name="packagesToScan" value="com.xxx.entity" />, 会解析成"classpath*:com/xxx/entity**/*.class",这个路径可以找出com/xxx/entity根目录下的类文件
2. <property name="packagesToScan" value="com.xxx.entity.*" />, 会解析成"classpath*:com/xxx/entity/***/*.class",这个路径可以找出com/xxx/entity根目录下一级子目录中的类文件,如com/xxx/entity/son/Hi.class ,而不能找出com/xxx/entity目录下的类文件。
3. <property name="packagesToScan" value="com.xxx.entity." />(注意最后的点) , 会转换成"classpath*:com/xxx/entity/**/*.class",这个路径可以找出com/xxx/entity根目录下及其子孙目录下所有的类文件. 一般来讲,这些就是我们要的文件。
数据库映射类(它没有配置文件hbm.xml,全部采用注解的方式),例子:
package com.yojosources.admin.po;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.stereotype.Repository;
/**
* 文章实体
* @author Beamstar
*/
@Entity
@Repository(value="t_article")
@Table(name="t_article")
public class Article {
/**
* 主键
* 文章 id
*/
private Integer ar_id;
/**
* 文章 标题
*/
private String ar_name;
/**
* 文章发布人
*/
private String ar_author;
/**
* 文章内容
*/
private String ar_content;
/**
* 发布日期
*/
private Date ar_date;
/**
* 浏览次数
*/
private Integer ar_readCount;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "article_id", unique = true, nullable = false)
public Integer getAr_id() {
return ar_id;
}
public void setAr_id(Integer arId) {
ar_id = arId;
}
@Column(name="headline")
public String getAr_name() {
return ar_name;
}
public void setAr_name(String arName) {
ar_name = arName;
}
@Column(name="author")
public String getAr_author() {
return ar_author;
}
public void setAr_author(String arAuthor) {
ar_author = arAuthor;
}
@Lob
@Column(name="article_contents", columnDefinition="TEXT", nullable=true)
public String getAr_content() {
return ar_content;
}
public void setAr_content(String arContent) {
ar_content = arContent;
}
@Column(name="artcleues_date")
@Temporal(TemporalType.TIMESTAMP)
public Date getAr_date() {
return ar_date;
}
public void setAr_date(Date arDate) {
ar_date = arDate;
}
@Column(name="page_view")
public Integer getAr_readCount() {
return ar_readCount;
}
public void setAr_readCount(Integer arReadCount) {
ar_readCount = arReadCount;
}
public Article() {
super();
// TODO Auto-generated constructor stub
}
public Article(Integer arId, String arName, String arAuthor,
String arContent, Date arDate, Integer arReadCount) {
super();
ar_id = arId;
ar_name = arName;
ar_author = arAuthor;
ar_content = arContent;
ar_date = arDate;
ar_readCount = arReadCount;
}
}
配置事务管理器:
jdbc:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
hibernate:
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
配置事务(利用了AOP技术。主要是拦截方法(建议不管是注解方式还是.xml方式,最好是拦截类中的方法,而不是接口);配置事务(主要指事务的传播性);调用方法时,那么它生成的是代理对象):
首先要引入命名空间,在beans.xml中插入代码:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop //引入AOP命名空间
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx //引入事务命名空间
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
在.xml里配置事务:
例子一:
<aop:config proxy-target-class="true"> //proxy-target-class="true"表示允许实现了接口的类,生成的代理对象可以是类的对象。
<aop:pointcut id="transactionPointcut" expression="execution(* cn.itcast.service.PersonService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
例子二:
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(public * com.yojosources.service.impl.*.*(..))"
id="bussinessService" />
<aop:pointcut expression="execution(public * com.yojosources..*Service.*(..))"
id="service" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="bussinessService" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="service" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="merge*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="put*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" /> //read-only="true"表示该方法只执行读取数据操作
<tx:method name="count*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="query*" propagation="SUPPORTS" read-only="true" />
<tx:method name="list*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" /> "*" 表示其他的方法
<tx:method name="batchSaveOrUpdate" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
注解方式配置事务:
在beans.xml加上代码:<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
例子:
package cn.itcast.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;
@Transactional
public class PersonServiceBean implements PersonService {
@Resource private SessionFactory sessionFactory;
@Transactional(readOnly=true)
public void save(Person person){
sessionFactory.getCurrentSession().persist(person);
}
public void update(Person person){
sessionFactory.getCurrentSession().merge(person);
}
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
public Person getPerson(Integer personid){
return (Person)sessionFactory.getCurrentSession().get(Person.class, personid);
}
public void delete(Integer personid){
sessionFactory.getCurrentSession().delete(
sessionFactory.getCurrentSession().load(Person.class, personid));
}
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
@SuppressWarnings("unchecked")
public List<Person> getPersons(){
return sessionFactory.getCurrentSession().createQuery("from Person").list();
}
}
事务的传播性:
常用的传播性主要是 REQUIRED,NOT_SUPPORTED,SUPPORTS。
spring集成struts
spring容器实例化交给web.xml:
<!-- 指定spring的配置文件,默认从web根目录寻找配置文件,我们可以通过spring提供的classpath:前缀指定从类路径下寻找 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value> //多个.xml文件用逗号隔开
</context-param>
<!-- 对Spring容器进行实例化 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
web容器实例化spring容器,详细见:http://blog.csdn.net/yangxueyong/article/details/6579700
当然spring也提供了方法让我们得到spring容器的实例,从而得到想要的bean。
集成struts1.x(其实就是让struts1.x中的action交给spring管理)
代码例子:
beans.xml中的代码:
struts-config.xml中的代码:
集成struts2.x(其实就是让struts2.x中的action交给spring管理)
beans.xml中的代码:
struts.xml中代码:
<constant name="struts.objectFactory" value="spring" /> //将action交给spring管理。
注意其中的class="".
这里采用了在.xml中,当然也可以采用注解方式.
struts.xml默认放在classpath路径的根目录下。web容器会找到,如果要改变路径,那么要在web.xml中配置,详细见:http://blog.163.com/wunan_23/blog/static/1955623202011102105925798/。