1 spring基础
1.1 spring是什么?
Spring是一个轻量级开源框架(有很多服务不是默认开启的,可以控制开启关闭),提供了对大多数基于java的框架的集成,例如Dao的jdbc,hibernate,mybitas,mvc框架struts。
对于现在大多数企业级项目,可能不用hibernate,可能不用struts2,但是应该都要使用spring。
它自己做的事情主要分俩个方面:ioc和aop。
Ioc:inverse control (控制反转)DI (依赖注入 depenciy inject)
Aop:aspect origined program 面向切面编程
寓意:java程序员的春天到了。强大,灵活,不笨重。
1.2 搭建spring开发环境
加入jar文件(spring中dist下所有jar和common-logging.jar 从struts的lib中找)
Src下写配置文件(schema从reference中找 搜索xml version 第一个包含beans就可以)
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- 相当于程序中的User user = new User(); -->
<bean id="user" class="com.qzh.oa.User"></bean>
写测试类
User类
package com.qzh.oa;
public class User{
public void show(){
System.out.println("欢迎来到Spring");
}
}
TestSpring
public class TestSpring{
@Text
public void textSpring(){
ApplicateContext ac = new ClassPathXmlApplicateContext("applicateContext ");
User user = ac.bean("user",User.class);
user.show();
}
}
总结:如果对象直接在程序中写死,改的话就麻烦了。配置在配置文件要灵活。
Ioc:对象的控制权由程序转移给了容器。
2 spring的ioc 和DI(依赖注入)
依赖是容器帮你注入的,而不是靠程序自己实现。
Action Service DAO
Service
UserDao dao = new UserDao();-->意味着依赖于实现类,将来如果更改实现类,在调用的地方需要全部修改
使用Factory可以解决这一的问题
DI来注入对象
2.1 spring的对象类型
singleton和Prototype
singleton是单例
Prototyp是多例
默认是单例的对象
使用范围:
只要属性中没有需要修改的值(dao,service这两层的数据一般不会有相应的属性会修改)所以可以考虑用单例
如果属性中有需要修改的变量如:action中会存储很多要操作的vo类,此时这个对象的状态会被修改,就要使用多例
2.2 依赖注入
依赖注入方式有多种:
最常用是set方法注入(set注入分普通类型int String 和 引用类型 ,引用类比较特殊的比如list set Properties)。
还有构造器注入。
自动注入
通过autowire byName byType
按名称自动注入用的多
按类型 如果找到多个类型都符合的bean,不知道注入哪个,抛异常
实际,自动注入也有不好处:因为看不出来类于类的关系
好处:减少代码量 智能
2.2.1 set注入
基本条件:所有的类都要被spring所管理才能进行依赖注入
有多种方式可以进行注入
1、使用set注入(最常用的方式)
1.1、提供相应的要注入的类的setter
private IUserDao userDao;
public IUserDao getUserDao(){
return userDao;
}
//提供要注入的类的set方法
public void setUserDao(IUserDao userDao){
this.userDao = userDao;
}
1.2、在配置文件中注入
2.2.2 构造器注入
了解
2.2.3 属性注入
2.2.4 自动注入
一般不使用
byName是根据set的名称来注入,如果名称不对就无法注入(默认情况)
byType表示是根据类型来注入,和名称无关,如果一个类中有两个相同类型的对象就无法注入
如果要使用一般使用byName
2.2.5 基于annotation的注入
annotation注入
(5个标注 Component Controller Service Respoisty Scope)
@Component 申明某个类被spring管理 帮你创建以及设定关系 名字一般是以类名首字母变小写
@Autowire和@Resource
前者是按照类型 ,后者是按照名称 后者用的多
@scope(value=”prototype”)
1、设置Beans.xml的schma
2、在类上面设置
3、spring3.0之后的Annotation建议
由于开发中一般都是分为四层体系:data,dao,service,action,
建议在dao层
service
action层
3 aop
aspect orient programm
3.1 aop产生原因
考虑一种场景:程序开发完成需要加入日志功能。。。
用system太死了。。。可以将日志代码提出到一个公共类 比如Logger void info(String)
由于违反了OCP原则也不能采用,应该使用静态代理
3.2 静态代理
3.3 动态代理
但是静态代理功能局限,比如要在订单模块也加入日志。。。结论就是使用动态代理,写一个类代理所有对象
3.4 标注增加灵活性
3.4.1定义标注
3.4.2接口中增加标注
3.4.3动态代理类处理标注:
3.5 Aop概念总结
总结:Aop关注的几件事情:
哪些代码和核心功能无关而且各个模块通用?
这些代码应该加在哪些类的哪些方法?
加在该方法的哪个位置?前?后?环绕?发生异常位置?
Aop的几个名词
Aspect
Advice
Pointcut 多个joincut组成pointcut
Joincut 一个切入点
Weave
程序运行期将adivce织入pointcut
3.6 spring 实现aop
Spring不是自己实现的aop,用了第三方的aspectj。
有俩种选择:一种是基于annotation 一种是基于xml
3.6.1 基于annotation
基于annotation需在xml中打开支持
然后就是切面类
3.6.2基于xml的:
4 spring整合jdbc
4.1 集成jdbc
4.1.1 步骤
1、导入Spring的包和数据库的驱动包
2、选择一个数据源(DBCP和C3p0)
3、导入数据源的包:DBCP
4、在beans.xml中创建dataSource数据源
5、创建一个jdbc.properties文件来设置数据库的连接信息
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/sram_spring
jdbc.username = root
jdbc.password = 123456
6、在beans.xml中导入相应的properties文件
<context:property-placeholder location="jdbc.properties"/>
7、写相应的DAO,并且为这个DAO创建一个JDBCTemplate对象,通过JdbcTemplate对象可以方便的完成对数据库的操作
8、为DAO注入相应的DataSource并且创建JdbcTemplate
@Resource
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
9、完成数据对象的添加
4.1.2 完成增删改
用update就可以完成普通增删改
以下是一个特例,增加用户的时候用到用户组的id,所以保存用户组时候要得到用户组递增id。
测试
4.1.3 基于RowMapper完成查询
4.2 jdbcTemplate实现思路
模板设计模式指的是将相应的模板方法提取出来在专门的一个位置定义,然后把相同调用过程的操作,通过模板来实现
对于模板设计模式而言,一般有两种方式
1、基于继承的实现
2、基于组合的实现
4.2.1 基于继承方式实现模板
钩子函数
4.2.2 基于组合方式实现模板
5 ssh整合
5.1和hibernate整合
加jar包
加入spring的jar
加入hibernate的jar
Dbcp和pool的jar(commons)
Log4j
Junit
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- 自动扫描与装配 -->
<context:component-scan base-package="com.qzh.oa"></context:component-scan>
<!-- 引用外部文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据源dataSource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"> </property>
<property name="user" value="${user}"> </property>
<property name="password" value="${password}"> </property>
<!-- 其他配置 -->
<!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize" value="3"></property>
<!--连接池中保留的最小连接数。Default: 3 -->
<property name="minPoolSize" value="3"></property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize" value="5"></property>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="3"></property>
<!-- 控制数据源内加载的PreparedStatements数量。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
<property name="maxStatements" value="8"></property>
<!-- maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
<property name="maxStatementsPerConnection" value="5"></property>
<!--最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="1800"></property>
</bean>
由于我们习惯于用jdbc.properties ,又去找了以下DBCP数据源配置
driverClass = com.mysql.jdbc.Driver
jdbcUrl = jdbc:mysql://localhost:3306/test
user = root
password =root
总结:集成hibernate3和4有一定的区别,目前基本都在使用3,所以该部分的内容以3为基础
1、导入hibernate的包和Spring的包
1.1、导入Spring的依赖包
1.2、导入Log4j的依赖包
1.3、导入dbcp的依赖包
1.4、导入Hibernate3的依赖包(hibernate3.jar,require文件中的所有,slf4j-api.jar,jpa文件夹中的包)
2、创建beans.xml
2.1、使用DBCP创建dataSource(和集成JDBC一样)
2.2、创建Hibernate的SessionFactory
<!--创建Spring的SessionFactory工厂 -->
<beanid="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 设置Spring取那个包中查找相应的实体类 -->
<property name="packagesToScan">
<value>com.sram.model</value>
</property>
<property name="hibernateProperties">
<!-- <value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value> -->
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
3、为实体类添加hibernate的Annotation或者hbm文件
4、创建基于Hibernate的DAO
4.1、在相应的DAO中注入相应的SessionFactory
4.2、如果通过Spring来管理相应的SessionFactory,不再使用factory.openSession()开启session,而应该是一facotry.getCurrentSession来打开Session,这个Session就会被Spring
所管理,此时开发人员不用进行事务控制,也不用关闭Session,全部有Spring容器来完成
5、配置Spring事务处理,只有配置了事务处理之后,Spring才能有效的管理事务
<!-- 配置Spring的事务处理 -->
<!-- 创建事务管理器-->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置AOP,Spring是通过AOP来进行事务管理的 -->
<aop:config>
<!-- 设置pointCut表示哪些方法要加入事务处理 -->
<aop:pointcut id="allMethods"
expression="execution(* com.sram.dao.impl.*.*(..))" />
<!-- 通过advisor来确定具体要加入事务控制的方法 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="allMethods" />
</aop:config>
<!-- 配置哪些方法要加入事务控制 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 让所有的方法都加入事务管理 -->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
5.2集成struts2
1、导入Struts2的包(导入之后检查一下是否存在有冲突的包)
2、导入Struts2和Spring的整合包(struts2-spring-plugin-2.3.4.1.jar)
3、配置Struts2的struts.xml文件
<!-- 表示Action由Spring来进行创建,可以直接使用Spring依赖注入来注入 -->
<constant name="struts.objectFactory" value="spring " />
4、创建action
/**
* 此时等于用Spring来创建了userAction对象,在struts的配置文件中写action的class的时候
* 就不能写类,而应该是userAction中对象
* @author Administrator
*
*/
@Controller("userAction")
5、重新配置struts.xml的基于通配符的访问方式
6、在web.xml中配置获取BeanFacotry的操作
6.1、创建监听器获取Spring的工厂
<!-- 创建Spring的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring 的监听器可以通过这个上下文参数来获取beans.xml的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:beans.xml</param-value>
</context-param>
6.2、创建Struts2的过滤器
<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>
6 openSessionInView
由于Hibernate存在延迟加载的问题,当DAO的事务提交之后,session就关闭此时如果到显示层就没有办法获取对象,使用OpenSessionInViewer是解决延迟加载问题的方案
关键:1.view层提交请求(底层浏览器提交http请求,请求真正到达action之前)打开session
2.dao层如何获取view打开的session
3.应该在http响应内容生成以后关闭session
解决1,3的问题 用filter
解决2的用ThreadLocal(强调:只要涉及到跨层传值都可以用ThreadLocal 三个方法 set get remove)