zoukankan      html  css  js  c++  java
  • 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表达式相关表

        以上是必须引入的5jar文件,在项目中可以用户库管理!

      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>   
    View Code

    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();
        }
    View Code

      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");
    View Code

        直接获得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);
        }
    View Code 

    3.专业术语

      1)侵入式设计:引入框架对现有类结构产生影响struts框架;非侵入式框架:引入框架对现有类结构没有影响

      2)控制反转(Inversion on Control  IOC),依赖注入( dependency injection   DI)

        区别:IOC解决对象创建问题;DI:对象创建完后对对象属性赋值,对象间关系依赖的处理【通过set方法依赖注入】

      3)AOP:面向切面编程:切面简单来说就是由很多重复代码组成,如:事务,日志,权限

    4.Spring提供的一站式解决方法

      1Spring Core  spring的核心功能: IOC容器, 解决对象创建及依赖关系

      2Spring Web  Springweb模块的支持。

        1. 可以与struts整合,strutsaction创建交给spring

            2. spring mvc模式

      3Spring DAO  Spring jdbc操作的支持  【JdbcTemplate模板工具类】

      4Spring ORM  springorm的支持:

        1. 既可以与hibernate整合,【session

        2. 也可以使用spring的对hibernate操作的封装

      5Spring AOP  切面编程

      6SpringEE   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">
        
        <!-- ###############对象创建############### -->
        
        <!-- 1. 默认无参数构造器 
        <bean id="user1" class="cn.itcast.b_create_obj.User"></bean>
        -->
        
        <!-- 2. 带参数构造器 -->
        <bean id="user2" class="cn.itcast.b_create_obj.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.itcast.b_create_obj.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.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>      
    
    
    
      
    View Code

      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>
    View Code

        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>   
    View Code

        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>  
    View Code

        总结: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;
        }
    }
    View Code

     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>
    View Code

     -----------------------------------------------------------

    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();
        }
    }
    View Code

      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();
        }
        
    }
    View Code

      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();
        }
    }
    View Code

    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="0" ref="userDao"></constructor-arg>
            <constructor-arg index="1" ref="aop"></constructor-arg>
        </bean>
        
    </beans>      
    View Code

    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.2lib】

          aspectjrt.jar   spring2.5源码/lib/aspectj】或【aspectj-1.8.2lib】

        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>      
    
      
    View Code

        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("环绕后...");
            
        }
    }
    View Code

    测试类

    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();
        }
    }
    View Code

    全部配置在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>
    View Code

    切面类的所有配置

    <!-- 切面类 -->
        <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()) &amp;&amp; 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>
    View Code

    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>
    View Code

      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;
            }
            
        }
    View Code

     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>
    View Code

        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>     
    View Code

            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) //默认是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-7。
    
    例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
    
    isolation
    
    该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
    
    timeout
    
    该属性用于设置事务的超时秒数,默认值为-1表示永不超时
    
    注意的几点:
    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("注释");
    }
    
    3、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protectedprivate 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
    
    
    4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。
    
    
    5、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因 此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。
    View Code

    配置文件关于事务管理部分的改为

    <!-- 事务管理器类 -->
        <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"/>
    View Code

    调用事务的方法使用注解的用法

    @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);
        }
    View Code

          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
            指定当前的方法必须在事务的环境下执行;
            如果当前运行的方法,已经存在事务:  事务会挂起; 会始终开启一个新的事务,执行完后;  刚才挂起的事务才继续运行
    View Code
  • 相关阅读:
    分布式与云计算有什么区别?
    多线程学习笔记
    docker解决报错WARNING: IPv4 forwarding is disabled. Networking will not work.
    Docker问题解决:Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io: no such host
    docker学习笔记
    linux命令学习
    Xftp5提示要继续使用此程序,您必须应用最新的更新的解决方案
    Springboot学习笔记
    maven学习笔记
    Spring学习笔记(6)
  • 原文地址:https://www.cnblogs.com/xiaoping1993/p/6922814.html
Copyright © 2011-2022 走看看