java深入探究12-框架之Spring
1.引入Spring
我们在搭建框架时常常会解决问题:对象创建,对象之间依赖关系如何处理,Spring就是来解决这类问题的:控制反转依赖注入
2.环境搭建
1)下载源码:其中3.0以下版本源码中有Spring相关所有包【核心包+依赖包】
3.0以上版本源码中只有spring核心包
2)导入jar包:spring-framework-3.2.5.RELEASE
commons-logging-1.1.3.jar 日志
spring-beans-3.2.5.RELEASE.jar bean节点
spring-context-3.2.5.RELEASE.jar spring上下文节点
spring-core-3.2.5.RELEASE.jar spring核心功能
spring-expression-3.2.5.RELEASE.jar spring表达式相关表
以上是必须引入的5个jar文件,在项目中可以用户库管理!
3)核心配置文件applicationContext.xml 和bean的属性描述
- <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">
- </beans>
bean属性描述
- /**
- * 1) 对象创建: 单例/多例
- * scope="singleton", 默认值, 即 默认是单例 【service/dao/工具类】
- * scope="prototype", 多例; 【Action对象】
- *
- * 2) 什么时候创建?
- * scope="prototype" 在用到对象的时候,才创建对象。
- * scope="singleton" 在启动(容器初始化之前), 就已经创建了bean,且整个应用只有一个。
- * 3)是否延迟创建
- * lazy-init="false" 默认为false, 不延迟创建,即在启动时候就创建对象
- * lazy-init="true" 延迟初始化, 在用到对象的时候才创建对象
- * (只对单例有效)
- * 4) 创建对象之后,初始化/销毁
- * init-method="init_user" 【对应对象的init_user方法,在对象创建爱之后执行 】
- * destroy-method="destroy_user" 【在调用容器对象的destriy方法时候执行,(容器用实现类)】
- */
- @Test
- public void testIOC() throws Exception {
- // 得到IOC容器对象 【用实现类,因为要调用销毁的方法】
- ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_hello/applicationContext.xml");
- System.out.println("-----容器创建-----");
- // 从容器中获取bean
- User user1 = (User) ac.getBean("user");
- User user2 = (User) ac.getBean("user");
- System.out.println(user1);
- System.out.println(user2);
- // 销毁容器对象
- ac.destroy();
- }
4)获取IOC两种方式:
通过BeanFactory获得IOC容器
- // 现在,把对象的创建交给spring的IOC容器
- Resource resource = new ClassPathResource("cn/itcast/a_hello/applicationContext.xml");
- // 创建容器对象(Bean的工厂), IOC容器 = 工厂类 + applicationContext.xml
- BeanFactory factory = new XmlBeanFactory(resource);
- // 得到容器创建的对象
- User user = (User) factory.getBean("user");
直接获得IOC容器:ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_hello/applicationContext.xml");
- //2. (方便)直接得到IOC容器对象
- @Test
- public void testAc() throws Exception {
- // 得到IOC容器对象
- ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_hello/applicationContext.xml");
- // 从容器中获取bean
- User user = (User) ac.getBean("user");
- System.out.println(user);
- }
3.专业术语
1)侵入式设计:引入框架对现有类结构产生影响struts框架;非侵入式框架:引入框架对现有类结构没有影响
2)控制反转(Inversion on Control IOC),依赖注入( dependency injection DI)
区别:IOC解决对象创建问题;DI:对象创建完后对对象属性赋值,对象间关系依赖的处理【通过set方法依赖注入】
3)AOP:面向切面编程:切面简单来说就是由很多重复代码组成,如:事务,日志,权限
4.Spring提供的一站式解决方法
1) Spring Core spring的核心功能: IOC容器, 解决对象创建及依赖关系
2) Spring Web Spring对web模块的支持。
1. 可以与struts整合,让struts的action创建交给spring
2. spring mvc模式
3) Spring DAO Spring 对jdbc操作的支持 【JdbcTemplate模板工具类】
4) Spring ORM spring对orm的支持:
1. 既可以与hibernate整合,【session】
2. 也可以使用spring的对hibernate操作的封装
5)Spring AOP 切面编程
6)SpringEE spring 对javaEE其他模块的支持
5.与applicationContext.xml配置文件有关的配置
1)配置创建对象的三种方式:
调用无参数构造器;带参数构造器constructor-arg;工厂创建对象factory-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"
- 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">
- <!-- ###############对象创建############### -->
- <!-- . 默认无参数构造器
- <bean id="user1" class="cn.itcast.b_create_obj.User"></bean>
- -->
- <!-- . 带参数构造器 -->
- <bean id="user2" class="cn.itcast.b_create_obj.User">
- <constructor-arg index="" type="int" value=""></constructor-arg>
- <constructor-arg index="" 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.itcast.b_create_obj.User">
- <constructor-arg index="" type="int" value=""></constructor-arg>
- <constructor-arg index="" type="java.lang.String" ref="str"></constructor-arg>
- </bean>
- <!-- . 工厂类创建对象 -->
- <!-- # 3.1 工厂类,实例方法 -->
- <!-- 先创建工厂 -->
- <bean id="factory" class="cn.itcast.b_create_obj.ObjectFactory"></bean>
- <!-- 在创建user对象,用factory方的实例方法 -->
- <bean id="user4" factory-bean="factory" factory-method="getInstance"></bean>
- <!-- # 3.2 工厂类: 静态方法 -->
- <!--
- class 指定的就是工厂类型
- factory-method 一定是工厂里面的“静态方法”
- -->
- <bean id="user" class="cn.itcast.b_create_obj.ObjectFactory" factory-method="getStaticInstance"></bean>
- </beans>
2)给对象属性赋值(DI 依赖注入)
1.通过构造方法;2.通过set方式;3.p名称空间;4.自动装配;5.注解
1.通过set方式:bean中加入<property name="userDao" ref="userDao">
内部bean方式:
- <!-- ##############内部bean############## -->
- <bean id="userAction" class="cn.itcast.c_property.UserAction">
- <property name="userService">
- <bean class="cn.itcast.c_property.UserService">
- <property name="userDao">
- <bean class="cn.itcast.c_property.UserDao"></bean>
- </property>
- </bean>
- </property>
- </bean>
2.p名称空间:p:userDao-ref=""代替了<property>set配置
- <?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: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">
- <!-- ###############对象属性赋值############### -->
- <!--
- 给对象属性注入值:
- # p 名称空间给对象的属性注入值
- (spring3.0以上版本才支持)
- -->
- <bean id="userDao" class="cn.itcast.c_property.UserDao"></bean>
- <bean id="userService" class="cn.itcast.c_property.UserService" p:userDao-ref="userDao"></bean>
- <bean id="userAction" class="cn.itcast.c_property.UserAction" p:userService-ref="userService"></bean>
- <!-- 传统的注入:
- <bean id="user" class="cn.itcast.c_property.User" >
- <property name="name" value="xxx"></property>
- </bean>
- -->
- <!-- p名称空间优化后 -->
- <bean id="user" class="cn.itcast.c_property.User" p:name="Jack0001"></bean>
- </beans>
3.自动装配:autowire="byName";autowire="byType"可以在<bean>属性上设置也可以在全局配置在头部default-autowire="byName"> 根据名称自动装配(全局)
- <!-- ###############自动装配############### -->
- 自动去IOC容器中找与属性名同名的引用的对象,并自动注入
- <bean id="userDao" class="cn.itcast.d_auto.UserDao"></bean>
- <bean id="userService" class="cn.itcast.d_auto.UserService" autowire="byName"></bean>
- <!-- 根据“名称”自动装配: userAction注入的属性,会去ioc容器中自动查找与属性同名的对象 -->
- <bean id="userAction"
- class="cn.itcast.d_auto.UserAction" autowire="byName"></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"
- 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" default-autowire="byName"> 根据名称自动装配(全局)
- <!-- ###############自动装配############### -->
- <bean id="userDao" class="cn.itcast.d_auto.UserDao"></bean>
- <bean id="userService" class="cn.itcast.d_auto.UserService"></bean>
- <bean id="userAction" class="cn.itcast.d_auto.UserAction"></bean>
- </beans>
- 根据类型byType
- <?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: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" default-autowire="byType">
- <!-- ###############自动装配############### -->
- <bean id="userDao" class="cn.itcast.d_auto.UserDao"></bean>
- <bean id="userService" class="cn.itcast.d_auto.UserService"></bean>
- <!-- 如果根据类型自动装配: 必须确保IOC容器中只有一个该类型的对象 -->
- <bean id="userAction" class="cn.itcast.d_auto.UserAction"></bean>
- <!-- 报错: 因为上面已经有一个该类型的对象,且使用了根据类型自动装配
- <bean id="userService_test" class="cn.itcast.d_auto.UserService" autowire="byType"></bean>
- -->
- </beans>
总结:pring提供的自动装配主要是为了简化配置; 但是不利于后期的维护
4.注解:
使用步骤:
1.先引入context名称空间
xmlns:context="http://www.springframework.org/schema/context"
2.开始扫描:
<context:component-scan base-package="cn.itcast.e_anno2"></context:component-scan>
3.使用注解:通过注解的方式,把对象加入ioc容器
@Component 指定把一个对象加入IOC容器
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
@Resource 属性注入
例子:
- bean.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"
- 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">
- <!-- 开启注解扫描 -->
- <context:component-scan base-package="cn.itcast.e_anno2"></context:component-scan>
- <bean id="userDao" class="cn.itcast.e_anno2.UserDao" scope="prototype">
- </bean>
- </beans>
- Dao
- // 把当前对象加入ioc容器
- //@Component("userDao") // 相当于bean.xml 【<bean id=userDao class=".." />】
- //@Component // 加入ioc容器的UserDao对象的引用名称, 默认与类名一样, 且第一个字母小写
- //@Repository // 在持久层可以选择用这个注解
- public class UserDao {
- public UserDao(){
- System.out.println("UserDao.UserDao()");
- }
- public UserDao(int id){
- System.out.println("UserDao.UserDao(int id)" + id);
- }
- public void save() {
- System.out.println("DB:保存用户!!!");
- }
- }
- Service
- //@Component("userService") // userService加入ioc容器
- //@Component
- @Service // 表示业务逻辑层的组件
- public class UserService {
- // @Resource // 根据类型查找 【在容器中要确保该类型只有一个变量】
- @Resource(name = "userDao") // 根据名称查找
- private UserDao userDao; // 去容器中招UserDao类型的变量,找到后就赋值
- public void save() {
- userDao.save();
- }
- }
- Action
- //@Component("userAction") // 加入IOC容器
- //@Component
- @Controller // 控制层的组件
- public class UserAction {
- @Resource
- private UserService userService;
- public String execute() {
- userService.save();
- return null;
- }
- }
6.Spring与Struts结合
关键点:struts的action创建交给spring
导入jar包
配置xml:Struts.xml;bean.xml;web.xml
struts.xml:struts路径与action映射配置
bean.xml:spring ioc 配置
web.xml:核心过滤器,初始化spring ioc容器
将Spring配置到web.xml中
- <!-- 2. spring 配置 -->
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/classes/bean-*.xml</param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
-----------------------------------------------------------
1.代理模式
1)理解:代理(Proxy)是一种设计模式,想在目标对象上实现功能扩展可用代理,是用户访问目标对象另一种访问方式
举例:明星《--经纪人<--用户:另一种方式访问对象给对象添加新功能
2)静态代理
1.原理:代理对象实现目标对象一样的接口也可以添加额外功能
2.优缺点:可以在不改变目标对象功能前提下,对目标对象功能扩展;但是可能会有很多代理的对象,且代理对象和目标对象都要维护
3.实现方式:与目标对象实现相同接口,在代理对象中添加自己的功能写上目标对象功能--------与装饰者设计模式类似
4.例子:保存用户(模拟)-》Dao(直接保存)-》DaoProxy(给保存添加事务处理)
- IUserDao
- package 代理.a_static;
- public interface IUserDao {
- void save();
- }
- UserDao
- package 代理.a_static;
- public class UserDao implements IUserDao{
- @Override
- public void save() {
- System.out.println("用户保存对象");
- }
- }
- UserDaoProxy
- package 代理.a_static;
- public class UserDaoProxy implements IUserDao{
- private IUserDao target;
- public UserDaoProxy(IUserDao target){
- this.target=target;
- }
- @Override
- public void save() {
- System.out.println("事务开始");
- target.save();
- System.out.println("事务结束");
- }
- }
- 测试APP
- package 代理.a_static;
- public class App {
- public static void main(String[] args){
- //目标对象
- IUserDao target=new UserDao();
- //代理对象
- IUserDao proxy=new UserDaoProxy(target);
- proxy.save();
- }
- }
3)动态代理
1.原理:代理对象不需要实现接口,而是动态的在内存中构建代理对象(需要我们提供代理对象/目标对象 实现接口的类型)
2.核心API:Proxy代理对象工具类
static Object newProxyInstance(
ClassLoader loader, 指定当前目标对象使用类加载器
Class<?>[] interfaces, 目标对象实现的接口的类型
InvocationHandler h 事件处理器
3.动态代理总结:代理对象不需要实现接口,但是目标对象必须实现接口,但是遇到目标对象没有实现接口就要用到新技术Cglib代理
4.例子:
- IUserDao
- package 代理.b_dynamic;
- public interface IUserDao {
- void save();
- }
- UserDao
- package 代理.b_dynamic;
- public class UserDao implements IUserDao{
- @Override
- public void save() {
- System.out.println("-------用户已保存-------");
- }
- }
- 代理对象动态创建,需要提供目标对象
- package 代理.b_dynamic;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /**
- * 给所有的到创建代理对象【动态代理】
- *
- * 代理对象不需要实现接口,内存内部自己自动生成
- * @author Administrator
- *
- */
- public class ProxyFactory {
- private Object target;
- public ProxyFactory(Object target){
- this.target=target;
- }
- //内存自动生成的
- public Object getProxyInstance(){
- return Proxy.newProxyInstance(
- //目标对象类加载器
- target.getClass().getClassLoader(),
- //目标对象实现的接口类型
- target.getClass().getInterfaces(),
- //核心事务处理器
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("事务开始");
- //执行目标对象方法
- Object returnValue=method.invoke(target, args);//调用目标对象的方法
- System.out.println("事务结束");
- return returnValue;
- }
- }
- );
- }
- }
- 测试App
- package 代理.b_dynamic;
- public class App {
- public static void main(String[] args){
- //目的对象
- IUserDao target=new UserDao();
- //动态代理对象创建
- IUserDao proxy=(IUserDao) new ProxyFactory(target).getProxyInstance();
- //内存中动态代理对象就是$Proxy0
- System.out.println(proxy.getClass());
- //执行方法
- proxy.save();
- }
- }
4)Cglib代理:子类代理
1.原理:在内存中构建一个子类对象从而实现对目标对象功能扩展;
底层原理:通过小儿快的字节码处理框架ASM,来转换字节码生产新类
2.引入:普通jdk动态代理必须目标对象有接口实现,当遇到没有接口的就需要用CGLIB了
3.使用步骤:
1)引入cglib-jar,spring核心包中有了
2)开始动态在内存中构建子类
3)代理的类不能为final,否则报错;目标对象的方法如果为final/staic,那么就不会被拦截,不会执行目标对象额外的业务方法
总结:在Spring的AOP编程中,如果容器的目标对象有实现接口,用JDK代理,没有实现接口可以用cglib子类代理
4.例子:
实现MethodInterceptor接口实现逻辑代码-》写获得子代理对象getProxyInsance()->通过Enhancer工具类赋值父类,创建子类代理对象
- UserDao
- package h_cglib;
- public class UserDao {
- public void save(){
- System.out.println("User保存");
- }
- }
- Proxy
- package h_cglib;
- import java.lang.reflect.Method;
- import org.springframework.cglib.proxy.Enhancer;
- import org.springframework.cglib.proxy.MethodInterceptor;
- import org.springframework.cglib.proxy.MethodProxy;
- public class ProxyFactory implements MethodInterceptor{
- private Object target;
- public ProxyFactory(Object target){
- this.target=target;
- }
- //给目标创建代理自对象
- public Object getProxyInsance(){
- //1.工具类
- Enhancer en=new Enhancer();
- //2.设置父类
- en.setSuperclass(target.getClass());
- //3.设置回调函数
- en.setCallback(this);
- //4.创建子类(代理对象)
- return en.create();
- }
- @Override
- public Object intercept(Object obj, Method method, Object[] args,
- MethodProxy arg3) throws Throwable {
- // TODO Auto-generated method stub
- System.out.println("开始事务。。。");
- Object returnValue=method.invoke(target, args);
- System.out.println("提交事务。。。");
- return returnValue;
- }
- }
- 测试类
- package h_cglib;
- import g_dynamic.IUserDao;
- public class App {
- public static void main(String[] args) {
- //目标对象
- UserDao target=new UserDao();
- System.out.println(target.getClass());
- //代理子对象
- UserDao proxy=(UserDao) new ProxyFactory(target).getProxyInsance();
- proxy.save();
- }
- }
2.手动实现AOP编程【代码模式】面向切面编程
1)理解:切片编程,就是将重复代码拿出来放在一个切边类中,之后再和核心逻辑代码组合叫AOP编程
2)代码例子:都时抽象出重复代码放在AOP切片类中
- IUserDao
- package e_AOP.myAOP2;
- public interface IUserDao {
- void save();
- }
- UserDao
- package e_AOP.myAOP2;
- import org.springframework.stereotype.Component;
- @Component
- public class UserDao implements IUserDao{
- @Override
- public void save() {
- System.out.println("User保存");
- }
- }
- ProxyFactory
- package e_AOP.myAOP2;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- public class ProxyFactory {
- private static Object target;
- private static Aop aop;
- public static Object getProxyInstance(Object target_,Aop aop_){
- target=target_;
- aop=aop_;
- return Proxy.newProxyInstance(
- target.getClass().getClassLoader(),
- target.getClass().getInterfaces(),
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- aop.begin();
- Object returnValue=method.invoke(target, args);
- aop.end();
- return returnValue;
- }
- });
- }
- }
- Aop
- package e_AOP.myAOP2;
- import org.springframework.stereotype.Component;
- /**
- * 切片代码,与逻辑代码分离
- * @author Administrator
- *
- */
- @Component
- public class Aop {
- public void begin(){
- System.out.println("开始事务。。。");
- }
- public void end(){
- System.out.println("结束事务。。。");
- }
- }
- App
- package e_AOP.myAOP2;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class App {
- ApplicationContext ac=new ClassPathXmlApplicationContext("e_AOP/myAOP2/bean.xml");
- @Test
- public void test(){
- IUserDao proxy=(IUserDao) ac.getBean("userDao_proxy");
- proxy.save();
- }
- }
- bean.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"
- 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">
- <!-- 开启注解扫描 -->
- <context:component-scan base-package="e_AOP.myAOP2.ProxyFactory" ></context:component-scan>
- <!-- 调用工厂类静态方法放回UserDao 代理后的对象 -->
- <bean id="userDao_proxy" class="e_AOP.myAOP2.ProxyFactory" factory-method="getProxyInstance">
- <constructor-arg index="" ref="userDao"></constructor-arg>
- <constructor-arg index="" ref="aop"></constructor-arg>
- </bean>
- </beans>
3.AOP编程
1)关键字
AOP: aspect object programming 面向切面编程,关注点代码与业务代码分离!
关注点:重复代码
切面:关注点组成的类
切入点:执行目标对象方法,动态植入切面代码
可以通过切入点表达式,指定拦截哪些类的哪些方法,给指定的类在运行时候植入切面类代码
2)步骤
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】
2.bean.xml中引入aop名称空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
3.开始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:p="http://www.springframework.org/schema/p"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- 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
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd">
- <!-- 开启注解扫描 -->
- <context:component-scan base-package="cn.itcast.e_aop_anno"></context:component-scan>
- <!-- 开启aop注解方式 -->
- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- </beans>
4.使用注解
- 切入点表达式:返回类型+包名+访问的类+类的方法(* cn.itcast.e_aop_anno.*.*(..))
- )
- @Aspect 指定一个类为切面类
- @Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入点表达式
- @Before("pointCut_()") 前置通知: 目标方法之前执行
- @After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
- @AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
- @AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
- @Around("pointCut_()") 环绕通知: 环绕目标方法执行
5.例子:
- package e_AOP.myAOPanno1;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.AfterThrowing;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- import org.springframework.stereotype.Component;
- @Component
- @Aspect //指定当前面为切面类
- public class Aop {
- //指定切入点表单式:拦截表达式,返回类型+包+哪一类+类方法(有参数可以写参数没有..)
- @Pointcut("execution(* e_AOP.myAOPanno1.*.*(..))")
- public void pointCut_(){
- }
- //前置通知:在执行目标方法之前执行
- @Before("pointCut_()")
- public void begin(){
- System.out.println("开始事务/异常");
- }
- //后置通知:在执行目标方法之后执行
- @After("pointCut_()")
- public void after(){
- System.out.println("提交事务/关闭");
- }
- //返回后通知:在调用目标方法之后执行
- @AfterReturning("pointCut_()")
- public void afterRunning(){
- System.out.println("afterRunning()");
- }
- //异常执行
- @AfterThrowing("pointCut_()")
- public void afterThrowing(){
- System.out.println("afterThrowing()");
- }
- //环绕执行
- @Around("pointCut_()")
- public void around(ProceedingJoinPoint pjp) throws Throwable{
- System.out.println("环绕前...");
- pjp.proceed();//执行目标方法
- System.out.println("环绕后...");
- }
- }
测试类
- package e_AOP.myAOPanno1;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class App {
- ApplicationContext ac =
- new ClassPathXmlApplicationContext("e_AOP/myAOPanno1/bean.xml");
- // 目标对象有实现接口,spring会自动选择“JDK代理”
- @Test
- public void testApp() {
- IUserDao userDao = (IUserDao) ac.getBean("userDao");
- System.out.println(userDao.getClass());//$Proxy001
- userDao.save();
- }
- //目标对象没有实现接口,spring会用“cglib代理”
- @Test
- public void testCglib(){
- OrderDao orderDao=(OrderDao) ac.getBean("orderDao");
- System.out.println(orderDao.getClass());
- orderDao.save();
- }
- }
全部配置在bean.xml中
- <!-- 配置OrderDao -->
- <bean id="userDao" class="e_AOP.myAOXml.UserDao"></bean>
- <!-- 配置UserDao -->
- <bean id="orderDao" class="e_AOP.myAOXml.OrderDao"></bean>
- <!-- 配置Aop -->
- <bean id="aop" class="e_AOP.myAOXml.Aop"></bean>
- <!-- Aop配置-->
- <aop:config>
- <!-- 定义一个切入点表达式:拦截哪些方法 -->
- <aop:pointcut expression="execution(* e_AOP.myAOXml.*.*(..))" 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>
切面类的所有配置
- <!-- 切面类 -->
- <bean id="aop" class="cn.itcast.g_pointcut.Aop"></bean>
- <!-- Aop配置 -->
- <aop:config>
- <!-- 定义一个切入点表达式: 拦截哪些方法 -->
- <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.*.*(..))" id="pt"/>-->
- <!-- 【拦截所有public方法】 -->
- <!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>-->
- <!-- 【拦截所有save开头的方法 】 -->
- <!--<aop:pointcut expression="execution(* save*(..))" id="pt"/>-->
- <!-- 【拦截指定类的指定方法, 拦截时候一定要定位到方法】 -->
- <!--<aop:pointcut expression="execution(public * cn.itcast.g_pointcut.OrderDao.save(..))" id="pt"/>-->
- <!-- 【拦截指定类的所有方法】 -->
- <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.*(..))" id="pt"/>-->
- <!-- 【拦截指定包,以及其自包下所有类的所有方法】 -->
- <!--<aop:pointcut expression="execution(* cn..*.*(..))" id="pt"/>-->
- <!-- 【多个表达式】 -->
- <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) || execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
- <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) or execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
- <!-- 下面2个且关系的,没有意义 -->
- <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) && execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
- <!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) and execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
- <!-- 【取非值】 -->
- <!--<aop:pointcut expression="!execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
- <aop:pointcut expression=" not execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>
- <!-- 切面 -->
- <aop:aspect ref="aop">
- <!-- 环绕通知 -->
- <aop:around method="around" pointcut-ref="pt"/>
- </aop:aspect>
- </aop:config>
4.Spring DAO
类似于DbUtil
1)配置xml导入JdbcTemplate对象
- <!-- 1. 数据源对象: 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>
- <!-- 2. 创建JdbcTemplate对象 -->
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <!-- dao 实例 -->
- <bean id="userDao" class="cn.itcast.h_jdbc.UserDao">
- <property name="jdbcTemplate" ref="jdbcTemplate"></property>
- </bean>
2)使用这个JdbcTemplate对象
- private JdbcTemplate jdbcTemplate;
- public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
- public void save() {
- String sql = "insert into t_dept(deptName) values('test');";
- jdbcTemplate.update(sql);
- }
- public Dept findById(int id) {
- String sql = "select * from t_dept where deptId=?";
- List<Dept> list = jdbcTemplate.query(sql,new MyResult(), id);
- return (list!=null && list.size()>0) ? list.get(0) : null;
- }
- public List<Dept> getAll() {
- String sql = "select * from t_dept";
- List<Dept> list = jdbcTemplate.query(sql, new MyResult());
- return list;
- }
- class MyResult implements RowMapper<Dept>{
- // 如何封装一行记录
- @Override
- public Dept mapRow(ResultSet rs, int index) throws SQLException {
- Dept dept = new Dept();
- dept.setDeptId(rs.getInt("deptId"));
- dept.setDeptName(rs.getString("deptName"));
- return dept;
- }
- }
5.Spring事务管理
1).事务管理分类
1.编程式事务管理:是jdbc中conn.setAutoCommite(false)
Hibernate中是session.beginTransaction()
细粒度的事务控制
2.声明式事务管理:只需在配置文件中配置,实现了对事务控制最大解耦
Jdbc:DataSourceTransactionManager
Hibernate技术:HibernateTransactionManager
粗粒度事务控制:只能给整个方法应用事务,因为aop拦截的是方法
2)配置事务管理
1.引入spring-aop相关4个jar文件;2.引入aop名称空间3.引入tx名称空间
2.spring声明式事务管理配置:
1)配置事务管理器类2)配置事务增强如何管理事务3)AOP配置拦截哪些方法应用上面的增强
- <!-- #############5. Spring声明式事务管理配置############### -->
- <!-- 5.1 配置事务管理器类 -->
- <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <!-- 5.2 配置事务增强(如果管理事务?) -->
- <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>
- <!-- 5.3 Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 -->
- <aop:config>
- <aop:pointcut expression="execution(* cn.itcast.a_tx.DeptService.*())" id="pt"/>
- <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
- </aop:config>
3)完整例子
- 1. DeptDao.java
- public class DeptDao {
- // 容器注入JdbcTemplate对象
- private JdbcTemplate jdbcTemplate;
- public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
- public void save(Dept dept){
- String sql = "insert into t_dept (deptName) values(?)";
- jdbcTemplate.update(sql,dept.getDeptName());
- }
- }
- 2. DeptService
- public class DeptService {
- // 容器注入dao对象
- private DeptDao deptDao;
- public void setDeptDao(DeptDao deptDao) {
- this.deptDao = deptDao;
- }
- /*
- * 事务控制?
- */
- public void save(Dept dept){
- // 第一次调用
- deptDao.save(dept);
- int i = 1/0; // 异常: 整个Service.save()执行成功的要回滚
- // 第二次调用
- deptDao.save(dept);
- }
- }
- 3. App 测试类
- @Test
- public void testApp() throws Exception {
- //容器对象
- ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_tx/bean.xml");
- // 模拟数据
- Dept dept = new Dept();
- dept.setDeptName("测试: 开发部");
- DeptService deptService = (DeptService) ac.getBean("deptService");
- deptService.save(dept);
- }
- 4. bean.xml (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:p="http://www.springframework.org/schema/p"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- 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
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx.xsd">
- <!-- 1. 数据源对象: 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>
- <!-- 2. JdbcTemplate工具类实例 -->
- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <!-- 3. dao实例 -->
- <bean id="deptDao" class="cn.itcast.a_tx.DeptDao">
- <property name="jdbcTemplate" ref="jdbcTemplate"></property>
- </bean>
- <!-- 4. service实例 -->
- <bean id="deptService" class="cn.itcast.a_tx.DeptService">
- <property name="deptDao" ref="deptDao"></property>
- </bean>
- <!-- #############5. Spring声明式事务管理配置############### -->
- <!-- 5.1 配置事务管理器类 -->
- <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <!-- 5.2 配置事务增强(如果管理事务?) -->
- <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>
- <!-- 5.3 Aop配置: 拦截哪些方法(切入点表表达式) + 应用上面的事务增强配置 -->
- <aop:config>
- <aop:pointcut expression="execution(* cn.itcast.a_tx.DeptService.*())" id="pt"/>
- <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
- </aop:config>
- </beans>
3.注解方式实现事务管理
注解声明讲解:
- 事物传播行为介绍:
- @Transactional(propagation=Propagation.REQUIRED)
- 如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
- @Transactional(propagation=Propagation.NOT_SUPPORTED)
- 容器不为这个方法开启事务
- @Transactional(propagation=Propagation.REQUIRES_NEW)
- 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
- @Transactional(propagation=Propagation.MANDATORY)
- 必须在一个已有的事务中执行,否则抛出异常
- @Transactional(propagation=Propagation.NEVER)
- 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
- @Transactional(propagation=Propagation.SUPPORTS)
- 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
- 事物超时设置:
- @Transactional(timeout=) //默认是30秒
- 事务隔离级别:
- @Transactional(isolation = Isolation.READ_UNCOMMITTED)
- 读取未提交数据(会出现脏读, 不可重复读) 基本不使用
- @Transactional(isolation = Isolation.READ_COMMITTED)
- 读取已提交数据(会出现不可重复读和幻读)
- @Transactional(isolation = Isolation.REPEATABLE_READ)
- 可重复读(会出现幻读)
- @Transactional(isolation = Isolation.SERIALIZABLE)
- 串行化
- MYSQL: 默认为REPEATABLE_READ级别
- SQLSERVER: 默认为READ_COMMITTED
- 脏读 : 一个事务读取到另一事务未提交的更新数据
- 不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
- 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
- 读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
- 幻读 : 一个事务读到另一个事务已提交的insert数据
- @Transactional注解中常用参数说明
- 参 数 名 称
- 功 能 描 述
- readOnly
- 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
- rollbackFor
- 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:
- 指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
- 指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
- 续表)
- 参 数 名 称
- 功 能 描 述
- rollbackForClassName
- 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:
- 指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")
- 指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})
- noRollbackFor
- 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:
- 指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)
- 指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
- noRollbackForClassName
- 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:
- 指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")
- 指定多个异常类名称:
- @Transactional(noRollbackForClassName={"RuntimeException","Exception"})
- propagation
- 该属性用于设置事务的传播行为,具体取值可参考表6-。
- 例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
- isolation
- 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
- timeout
- 该属性用于设置事务的超时秒数,默认值为-1表示永不超时
- 注意的几点:
- @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
- 2用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
- 如下:
- @Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
- public void methodName() {
- throw new Exception("注释");
- }
- @Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
- public ItimDaoImpl getItemDaoImpl() {
- throw new RuntimeException("注释");
- }
- 、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
- 、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。
- 、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因 此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。
配置文件关于事务管理部分的改为
- <!-- 事务管理器类 -->
- <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"></property>
- </bean>
- <!-- 开启注解扫描 -->
- <context:component-scan base-package="cn.itcast.b_anno"></context:component-scan>
- <!-- 注解方式实现事务: 指定注解方式实现事务 -->
- <tx:annotation-driven transaction-manager="txManager"/>
调用事务的方法使用注解的用法
- @Transactional(
- readOnly=false,
- timeout=-1,
- isolation=Isolation.DEFAULT,
- propagation=Propagation.REQUIRED
- )
- public void save(Dept dept){
- //第一次调用
- deptDao.save(dept);
- int i = 1/0; // 异常: 整个Service.save()执行成功的要回滚
- // 第二次调用
- deptDao.save(dept);
- }
4.事务属性
- @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
- 指定当前的方法必须在事务的环境下执行;
- 如果当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后; 刚才挂起的事务才继续运行
java深入探究12-框架之Spring的更多相关文章
- 【转】Java十大常用框架介绍(spring系+dubbo+RabbitMQ+Ehcache+redis)
一.SpringMVC Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动 ...
- atititt.java定时任务框架选型Spring Quartz 注解总结
atititt.java定时任务框架选型Spring Quartz 总结 1. .Spring Quartz (ati recomm) 1 2. Spring Quartz具体配置 2 2.1. 增 ...
- java框架篇---spring AOP 实现原理
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...
- Java后端框架之Spring Boot详解,文末有Java分布式实战项目视频可取
在 Java 后端框架繁荣的今天,Spring 框架无疑是最最火热,也是必不可少的开源框架,更是稳坐 Java 后端框架的龙头老大. 用过 Spring 框架的都知道 Spring 能流行是因为它的两 ...
- java框架之Spring(2)-注解配置IOC&AOP配置
注解配置IoC 准备 1.要使用注解方式配置 IoC,除了之前引入的基础 jar 包,还需要引入 spring-aop 支持包,如下: 2.在 applicationContext.xml 中引入 c ...
- Java开发工程师(Web方向) - 04.Spring框架 - 第1章.Spring概述
第1章.Spring概述 Spring概述 The Spring Framework is a lightweight solution and a potential one-stop-shop f ...
- Java匹马行天下之J2EE框架开发——Spring—>Spring框架知多少
————也许我注定成不了一个伟大的人,但是至少我可以做一个很棒的自己.我想我现在应该做的不是瞻前顾后,而是活在当下,正确认知自己,做好自己现在的工作,努力提升自己的能力,踏踏实实地做一个程序员 一.思 ...
- Java - 框架之 Spring
一. IOC 和 DI IOC : 控制反转,将对象的创建权反转给了 Spring.DI : 依赖注入,前提是必须要有 IOC 的环境,Spring 管理这个类的时候将类的依赖的属性注入(设置)进来 ...
- 深入理解java:4.2. 框架编程之Spring框架的设计理念
什么是Spring呢? Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. Spring优点 简单了解Spring之后,我们看一下Spri ...
随机推荐
- 表变量、临时表(with as ,create table)
1.declare @t table(CountryRegionCode nvarchar(3))insert into @t(CountryRegionCode) (select CountryR ...
- class 中构造函数与析构函数
import pymysql class My_sql(): def __init__(self, host, user, passwd, db, port=3306, charset='utf8') ...
- ViewPager页面切换特效
ViewPager页面切换特效如下效果 看效果: 效果1: 效果2: 下面就开始讲解如何实现这两个页面翻转效果 1.首先你得会ViewPager控件的使用(废话!现在还有人不会使用吗???!!) 2. ...
- NoSQL-redis with python
首先,先去看了一下NoSQL的概念: Wiki中参考的NoSQL终极指南(nosql-database.org)中说: NoSQL DEFINITION: Next Generation Databa ...
- 【BZOJ4825】[Hnoi2017]单旋 线段树+set
[BZOJ4825][Hnoi2017]单旋 Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能 ...
- Xamarin.Forms学习之Page Navigation(一)
在最初接触Xamarin.Forms的时候,我是跟着Xamarin官方的名为“learning-xamarin-ebook”的pdf文档进行学习的,我在成功运行Hello world程序之后,我开始跟 ...
- Date、Calendar、DateFormat、SimpleDateFormat、Timer、TimerTask类
类 Date 在 JDK 1.1 之前,类 Date 有两个其他的函数.它允许把日期解释为年.月.日.小时.分钟和秒值. 它也允许格式化和解析日期字符串.不过,这些函数的 API 不易于实现国际化.从 ...
- CSS3 Flex布局(容器)
一.flex-direction属性 row(默认值):主轴为水平方向,起点在左端. row-reverse:主轴为水平方向,起点在右端. column:主轴为垂直方向,起点在上沿. column-r ...
- Hibernate 框架入门(一)
1. SSH Web 层: Struts2 业务层: Spring 持久层: Hibernate 2. Hibernate 概述 概述 Hibernate 是一个对象关系映射框架(ORM 框架); 对 ...
- MariaDB数据库主从复制实现步骤
一.MariaDB简介 MariaDB数据库的主从复制方案,是其自带的功能,并且主从复制并不是复制磁盘上的数据库文件,而是通过binlog日志复制到需要同步的从服务器上. MariaDB数据库支持单向 ...