1、Spring框架
概述:spring框架可以解决对象创建以及对象之间依赖关系的一中框架。
常用专业术语:
- 组建/框架设计:
非侵入式设计:引入了框架对现有的结构无影响。例如:hibernate、spring框架。
- 控制反转(inversion on control----IOC)
依赖注入(DI):处理对象的依赖关系
区别:
控制反转解决对象的创建问题。而依赖注入是在对象创建成功后解决对象的关系的处理。
- AOP面向切面编程
2、Spring IOC容器(applicationContext.xml)
IOC容器是spring核心,作用:创建对象和处理对象的依赖关系
默认的applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
</beans>
2.1 对象创建的细节
a、什么时候创建
scope="prototype"(默认值) 在用到对象的时候才创建-------------多例(action对象)
scope="singleton" 在启动(容器初始化之前),就已经创建了对象,整个web应用只有一个-------------------单例(dao、service、工具类)
b、是否延迟创建
lazy-init="false"(默认值) 不延迟创建,即在启动的时候就创建。
lazy-init="true" 延迟初始化,在用到对象的时候才创建。
2.2 创建对象的几种方式
a、调用无参构造器
b、带参构造器
c、工厂类创建:静态/动态
<!-- ###############对象创建############### -->
<!-- 1. 默认无参数构造器
<bean id="user1" class="cn.User"></bean>
-->
<!-- 2. 带参数构造器 -->
<bean id="user2" class="cn.User">
<constructor-arg index="0" type="int" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="Jack"></constructor-arg>
</bean>
<!-- 定义一个字符串,值是"Jack" ; String s = new String("jack")-->
<bean id="str" class="java.lang.String">
<constructor-arg value="Jacks"></constructor-arg>
</bean>
<bean id="user3" class="cn.User">
<constructor-arg index="0" type="int" value="100"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" ref="str"></constructor-arg>
</bean>
<!-- 3. 工厂类创建对象 -->
<!-- # 3.1 工厂类,实例方法 -->
<!-- 先创建工厂 -->
<bean id="factory" class="cn.ObjectFactory"></bean>
<!-- 在创建user对象,用factory方的实例方法 -->
<bean id="user4" factory-bean="factory" factory-method="getInstance"></bean>
<!-- # 3.2 工厂类: 静态方法 -->
<!--
class 指定的就是工厂类型
factory-method 一定是工厂里面的“静态方法”
-->
<bean id="user" class="cn.ObjectFactory" factory-method="getStaticInstance"></bean>
2.3 对象依赖关系
spring中常用的几种注入方式
a、通过构造器
b、通过set方法给属性注入值(最常用)
*****************************
需要给set方法。
*****************************
<!-- dao instance -->
<bean id="userDao" class="cn.dao.UserDao"></bean>
<!-- service instance -->
<bean id="userService" class="cn.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- action instance -->
<bean id="userAction" class="cn.action.UserAction">
<property name="userService" ref="userService"></property>
</bean>
c、p名称空间
<span style="white-space:pre"> </span><bean id="userDao" class="cn.dao.UserDao"></bean>
<bean id="userService" class="cn.service.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="cn.action.UserAction" p:userService-ref="userService"></bean>
<p align="left"><span style="color:teal;"><span style="white-space:pre"> </span><</span><span style="color: rgb(63, 127, 127);">bean</span> <span style="color: rgb(127, 0, 127);">id</span>=<em><span style="color:#2A00FF;">"user"</span></em><span style="color: rgb(127, 0, 127);">class</span>=<em><span style="color:#2A00FF;">"cn.entity.User"</span></em> <span style="color: rgb(127, 0, 127);">p:name</span>=<em><span style="color:#2A00FF;">"Jack0001"</span></em><span style="color: teal;">></</span><span style="color: rgb(63, 127, 127);">bean</span><span style="color: teal;">></span></p>
d、注解
注解方式可以简化spring的IOC容器的配置。。但不利于后期的维护。
使用步骤:
1)先引入context名称空间
xmlns:context="http://www.springframework.org/schema/context"
2)开启注解扫描
<context:component-scanbase-package="包"></context:component-scan>
3)使用注解
通过注解的方式,把对象加入ioc容器。 创建对象以及处理对象依赖关系,相关的注解:
@Component 指定把一个对象加入IOC容器
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
@Resource 属性注入
3、AOP编程
3.1 概述:
aop(aspectobject programming 面向切面编程)功能:让关注点代码和业务代码分离
关注点:重复代码
切面:关注点形成的类就叫切面类。
面向切面编程就是对重复代码进行抽取,在业务执行的时候再动态植入。
切入点:
可以通过切入点表达式拦截指定的类的指定方法,在类或方法执行的时候动态植入切面类代码。
3.2 注解方式实现AOP编程
步骤
1) 先引入aop相关jar文件 (aspectj aop优秀组件)
spring-aop-3.2.5.RELEASE.jar 【spring3.2源码】
aopalliance.jar 【spring2.5源码/lib/aopalliance】
aspectjweaver.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】
aspectjrt.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】
注意:用到spring2.5版本的jar文件,如果用jdk1.7可能会有问题。
需要升级aspectj组件,即使用aspectj-1.8.2版本中提供jar文件提供。
2) bean.xml中引入aop名称空间
3) 开启aop注解
4) 使用注解
@Aspect 指定一个类为切面类
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
3.3 XML实现AOP编程
Xml实现aop编程:
1) 引入jar文件 【aop 相关jar, 4个】
2) 引入aop名称空间
3)aop 配置
*配置切面类 (重复执行代码形成的类)
*aop配置: 拦截哪些方法 / 拦截到方法后应用通知代码
<!-- dao 实例 -->
<bean id="userDao" class="cn.dao.UserDao"></bean>
<bean id="orderDao" class="cn.dao.OrderDao"></bean>
<!-- 切面类 -->
<bean id="aop" class="cn.aop.Aop"></bean>
<!-- Aop配置 -->
<aop:config>
<!-- 定义一个切入点表达式: 拦截哪些方法 -->
<aop:pointcut expression="execution(* cn.*.*.*(..))" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pt"/>
<!-- 前置通知: 在目标方法调用前执行 -->
<aop:before method="begin" pointcut-ref="pt"/>
<!-- 后置通知: -->
<aop:after method="after" pointcut-ref="pt"/>
<!-- 返回后通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
3.4 切入点表达式
切入点表达式: 可以对指定的“方法”进行拦截; 从而给指定的方法所在的类生层代理对象。
<aop:config>
<!-- 定义一个切入点表达式: 拦截哪些方法 -->
<!--<aop:pointcut expression="execution(* cn.*.*(..))" id="pt"/>-->
<!-- 【拦截所有public方法】 -->
<!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>-->
<!-- 【拦截所有save开头的方法 】 -->
<!--<aop:pointcut expression="execution(* save*(..))" id="pt"/>-->
<!-- 【拦截指定类的指定方法, 拦截时候一定要定位到方法】 -->
<!--<aop:pointcut expression="execution(public * cn.g_pointcut.OrderDao.save(..))" id="pt"/>-->
<!-- 【拦截指定类的所有方法】 -->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.*(..))" id="pt"/>-->
<!-- 【拦截指定包,以及其自包下所有类的所有方法】 -->
<!--<aop:pointcut expression="execution(* cn..*.*(..))" id="pt"/>-->
<!-- 【多个表达式】 -->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) || execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) or execution(* cn..g_pointcut.OrderDao.save())" id="pt"/>-->
<!-- 下面2个且关系的,没有意义 -->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) && execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<!--<aop:pointcut expression="execution(* cn.g_pointcut.UserDao.save()) and execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<!-- 【取非值】 -->
<!--<aop:pointcut expression="!execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>-->
<aop:pointcut expression=" not execution(* cn.g_pointcut.OrderDao.save())" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
4、事务
事务是一组操作的执行单元,相对于数据库操作来讲,事务管理的是一组SQL指令,比如增加,修改,删除等,事务的一致性,要求,这个事务内的操作必须全部执
行成功,如果在此过程种出现了差错,比如有一条SQL语句没有执行成功,那么这一组操作都将全部回滚
事务特性(ACID)
•Atomic(原子性):要么都成功,要么都失败
•Consistent(一致性):数据应该不被破坏
•Isolate(隔离性):用户间操作不相混淆
•Durable(持久性):永久保存
4.1 事务控制概述
编程式事务控制
自己手动控制事务,就叫做编程式事务控制。
Jdbc代码: Conn.setAutoCommite(false); // 设置手动控制事务
Hibernate代码: Session.beginTransaction(); // 开启一个事务
【细粒度的事务控制:可以对指定的方法、指定的方法的某几行添加事务控制】
(比较灵活,但开发起来比较繁琐:每次都要开启、提交、回滚.)
声明式事务控制
Spring提供了对事务的管理, 这个就叫声明式事务管理。
Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可;不想使用时直接移除配置。这个
实现了对事务控制的最大程度的解耦。
Spring声明式事务管理,核心实现就是基于Aop。
【粗粒度的事务控制:只能给整个方法应用事务,不可以对方法的某几行应用事务。】
(因为aop拦截的是方法。)
Spring声明式事务管理器类:
Jdbc技术:DataSourceTransactionManager
Hibernate技术:HibernateTransactionManager
4.2 声明式事务管理
步骤:
1) 引入spring-aop相关的4个jar文件
2) 引入aop名称空间 【XML配置方式需要引入】
3) 引入tx名称空间 【事务方式必须引入】
xml实现:
<!-- 数据源对象: C3P0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass"value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl"value="jdbc:mysql:///hib_demo"></property> <property name="user"value="root"></property> <property name="password"value="root"></property> <property name="initialPoolSize"value="3"></property> <property name="maxPoolSize"value="10"></property> <property name="maxStatements"value="100"></property> <property name="acquireIncrement"value="2"></property> </bean> <span style="white-space:pre"> </span><!-- 配置事务管理器类 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务增强(如果管理事务?) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="find*" read-only="true"/> <tx:method name="*" read-only="false"/> </tx:attributes> </tx:advice> <!-- Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 --> <aop:config> <aop:pointcut expression="execution(* cn.itcast.a_tx.DeptService.*())" id="pt"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> </aop:config>
注解方式实现:
使用注解实现Spring的声明式事务管理,更加简单!
步骤:
1) 必须引入Aop相关的jar文件
2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类
3)在需要添加事务控制的地方,写上: @Transactional
@Transactional注解:
1)应用事务的注解
2)定义到方法上: 当前方法应用spring的声明式事务
3)定义到类上: 当前类的所有的方法都应用Spring声明式事务管理;
4)定义到父类上: 当执行父类的方法时候应用事务。
<!-- 数据源对象: C3P0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> <property name="initialPoolSize" value="3"></property> <property name="maxPoolSize" value="10"></property> <property name="maxStatements" value="100"></property> <property name="acquireIncrement" value="2"></property> </bean> <!-- 事务管理器类 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 开启注解扫描 --> <context:component-scan base-package="包"></context:component-scan> <!-- 注解方式实现事务: 指定注解方式实现事务 --> <tx:annotation-driven transaction-manager="txManager"/>
事务属性:
@Transactional( readOnly = false, // 读写事务 timeout = -1, // 事务的超时时间不限制 noRollbackFor = ArithmeticException.class, // 遇到数学异常不回滚 isolation = Isolation.DEFAULT, // 事务的隔离级别,数据库的默认 propagation = Propagation.REQUIRED // 事务的传播行为 ) public void save(Dept dept){ deptDao.save(dept); int i = 1/0; deptDao.save(dept); }
事务传播行为:
Propagation.REQUIRED
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务, 就会加入当前的事务;
Propagation.REQUIRED_NEW
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后; 刚才挂起的事务才继续运行。