ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring

2021-11-26 10:02:11  阅读:115  来源: 互联网

标签:事务 配置文件 对象 Spring spring 注解 public


目录

一、Spring概述

1、Spring概念

2、Spring体系结构

二、控制反转IOC

1、 了解Bean和工厂类

2、Spring实现IOC步骤

3、spring创建对象的三种方式

4、Spring中Bean对象的作用域

5、Spring中Bean对象的生命周期

三、注入DI

1、注入的方式

2、利用注解管理spring

四、面向切面AOP

1、AOP概述

2、AOP使用场景

3、AOP实现分类

4、SpringAOP

五、配置文件、注解式配置

1、纯配置文件配置

2、半注解半配置文件配置

3、纯注解式配置

六、spring事务管理

1、spring和事务有关的接口

2、事务的7个传播行为

3、事务的4个隔离级别

4、使用注解式管理事务

5、全注解管理事务


一、Spring概述

1、Spring概念

简单一句话:spring是一个容器,它是为了更好的管理对象(对象的实例化和生命周期的管理)。

它有两大核心:IOC(Inverse Of Control控制反转)和AOP(aspect oriented programing,面向切面编程)

2、Spring体系结构

Spring 是模块化的,允许你只挑选和选择适用于你的模块。

 

四大核心容器

核心容器
spring-core提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
spring-beans提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
spring-context建立在由 corebeans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。ApplicationContext 接口是 Context 模块的焦点
spring-expression提供了强大的表达式语言,用于在运行时查询和操作对象图。

二、控制反转IOC

Spring的IOC:Inverse Of Control(控制反转),让spring去创建对象,这就是控制反转的意思!spring创建dao、service对象的原理类似于我们自己写的(反射+配置文件)的方式。

它的作用就是解耦,降低程序之间的依赖程度,但是是不能完全解除这种依赖的关系。

1、 了解Bean和工厂类

1.1 Bean

Bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。 也就是说,bean并不是程序员编辑的,而是程序运行时,由spring通过反射生成的。

简单来说,Bean就是有可重用特性的组件(比如说Dao和Service),而JavaBean就是用java语言写的具备可重用特性的组件。

Bean 与 Spring 容器的关系

 

1.2 工厂类

首先要谈到工厂模式,工厂模式(Factory Pattern)就是一个创建对象的接口。不同的子类可以创建不同的对象。 工厂模式是Java的一种创建性的设计模式。

Spring有两个工厂类(容器接口),分别为BeanFactoryg(旧版本,也是顶层接口)和ApplicationContext (新版本)。他们两个的区别就是是否懒加载。BeanFactory是懒加载,当调用getBean方法的时候,才会创建对象,而ApplicationContext在加载配置文件的时候,就会将Spring管理的类实例化。

  • ApplicationContext: 配置文件加载完成,对象就创建完成了,立刻创建对象的方式,单例。 BeanFactory 的子接口,也被称为 Spring 上下文

    • ClassPathXmlApplicationContext: 加载的是类路径下的配置文件,常用

    • FileSystemXmlApplicationContext: 加载磁盘上的任意位置的配置文件, 提供给构造器 XML 文件的完整路径

    • AnnotationConfigApplicationContext: 注解

  • BeanFactory(顶层接口),延迟创建对象,当使用getBean方法获取对象时,才会创建对象,多例。常用语安卓,省内存。

    • XmlBeanFactory: 这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用

    public static void main(String[] args) {
​
        //1.ApplicationContext  即时加载 配置文件加载完成之后就创建对象了
        //创建容器,单例执行初始化
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");// 加载配置文件
        AccountService accountService = (AccountService) applicationContext.getBean("service2");// 创建对象
        System.out.println(accountService);
​
        //关闭容器,单例执行销毁  调用getBean的时候才创建对象
        ((ClassPathXmlApplicationContext)applicationContext).close();
​
        // 2.BeanFactory ---延迟加载
        Resource resource = new ClassPathResource("bean.xml");// 加载配置文件
        BeanFactory beanFactory = new XmlBeanFactory(resource);
        AccountService accountService1 = (AccountService) beanFactory.getBean("service2");// 创建对象
        System.out.println(accountService1);
​
    }

2、Spring实现IOC步骤

  • 加入依赖,spring-context

  • 写dao、service层,功能层

  • 创建spring配置文件,将所需要实例化的类配置在配置文件中

  • 从spring容器中利用反射创建对象并获取对象

3、spring创建对象的三种方式

  • 用默认的构造方法创建对象

  • 实例工厂负责创建对象

  • 静态工厂负责创建对象

​
    <!--1.使用默认的构造方法创建对象,在bean标签中只配置id(自己起的名字)和class(类的全限定名)属性
      最常用的方式,适用于自己定义的类-->
    <bean id="accountService" class="ioc.com.service.impl.AccountServiceImpl"></bean>
​
    <!--2实例工厂负责创建对象,如何得到工厂创建的对象
        1.创建工厂的对象
        2.调用工厂对象的方法,即可得到工厂创建的对象-->
    <bean id="factory" class="ioc.com.factory.InstanceFactory"></bean>
    <bean id="accountService2" factory-bean="factory" factory-method="getInstance"></bean>
​
    <!--3静态工厂负责创建对象  可通过类名调用,不需要创建对象了-->
    <bean id="accountService3" class="ioc.com.factory.StaticFactory" factory-method="getInstance" scope="prototype"></bean>

4、Spring中Bean对象的作用域

scope说明
singleton单例(默认)
prototype多例,每次调用都返回一个新的对象,相当于new一个新的对象。
request请求范围内有效
session会话范围内有效
global-session集群环境下的范围,如果没有集群,则等价于session

5、Spring中Bean对象的生命周期

生命周期
单例实例化:容器创建时就创建了对象
活着:只要容器不关闭,就一直活着
销毁:容器关闭了,对象就销毁了
多例实例化:当使用getBean方法获取对象时,对象就产生了
活着:只要一直使用,就一直活着
销毁:当长时间没有使用该对象,且没有其他引用时,才等待垃圾回收器回收
    <bean id="accountService4" class="ioc.com.service.impl.AccountServiceImpl" init-method="init" destroy-method="destroy"></bean>

三、注入DI

Dependency Injection 依赖注入,一个类中定义的成员变量,都是该类所依赖的,给成员变量赋值,就是注入,因为对象是spring创建的,所以给成员变量赋值也是spring进行注入的。 依赖注入仅仅是控制反转的一个具体的例子。

1、注入的方式

  • 用构造器注入

  • 用setXXX方法注入

  • 用注解实现注入

  • p命名空间(了解即可)

    <!--1.用构造方法:基本数据类型和String可以直接指定值,引用数据类型在外面创建对象,再用ref引用-->
    <bean id="service1" class="ioc.com.service.impl.AccountServiceImpl">
        <!--给属性注入-->
        <constructor-arg name="name" value="张三"></constructor-arg>
        <constructor-arg name="age" value="14"></constructor-arg>
        <constructor-arg name="birthday" ref="time"></constructor-arg>
    </bean>
    <!--创建时间对象 以便其他用ref引用-->
    <bean id="time" class="java.util.Date"></bean>
​
    <!--2.用setXXX方法:基本数据类型和String可以直接指定值,引用数据类型在外面创建对象,再用ref引用-->
    <bean id="service2" class="ioc.com.service.impl.AccountServiceImpl">
        <property name="name" value="李四"></property>
        <property name="age" value="15"></property>
        <property name="birthday" ref="time"></property>
    </bean>
​
    <bean id="collection" class="di_3.MyCollection">
        <property name="bookname">
            <!--数组-->
            <array>
                <value>西游记</value>
                <value>红楼梦</value>
                <value>水浒传</value>
                <value>三国演义</value>
            </array>
        </property>
        <property name="classname">
            <!--list-->
            <list>
                <value>1班</value>
                <value>2班</value>
                <value>3班</value>
            </list>
        </property>
        <property name="hobbies">
            <!--set-->
            <set>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>打豆豆</value>
            </set>
        </property>
        <property name="info">
            <!--map-->
            <map>
                <entry key="name" value="张三"></entry>
                <entry key="age" value="15"></entry>
                <entry>
                    <key><value>address</value></key>
                    <value>北京</value>
                </entry>
            </map>
        </property>
        <property name="properties">
            <!--properties键值对-->
            <props>
                <prop key="hobby">打球</prop>
                <prop key="体重">99</prop>
            </props>
        </property>
    </bean>
​
注解实现注入说明
@Autowired按照类型注入,如果同种类型对象超过一个,会根据变量名是否等于id去找对象
@Qualifier根据id实现注入,这个注解不能单独使用,需要和@Autowired一起使用
@Resource按照id注入,name=""

p命名空间

<!--加入p命名空间: xmlns:p="http://www.springframework.org/schema/p"-->
    <bean id="worker" class="di_4.Worker" p:name="小李" p:age="14" p:homeAddress-ref="homeAddress" p:workAddress-ref="workAddress"></bean>
    <bean id="homeAddress" class="di_4.Address" p:province="北京" p:city="北京市" p:county="海淀区"></bean>
    <bean id="workAddress" class="di_4.Address" p:province="天津" p:city="天津市" p:county="西青区"></bean>

2、利用注解管理spring

2.1 注解实现注入(见上)

2.2 注解创建对象

    <!--使用了注解需要让spring扫描注解,被扫描到的类,spring容器才会创建其对象
        扫描的基础包会扫描指定包及其子包base-package中定义包名
    -->
    <context:component-scan base-package="annotation.com"></context:component-scan>
注解说明
@Component通用注解,了解即可。可以创建任何类型的对象,等价于之前用标签创建对象的方式,使用注解创建的对象的id默认是类名的首字母小写,自己指定id:@Component([value=]"accountService")
一般用以下三种使用注解创建的对象的id默认是类名的首字母小写,自己指定id([value=]"accountService")
Controller控制层
Service业务层
Repositorydao层

2.3 注解控住对象的作用域

@Scope: 默认是单例:@Scope("singleton")

多例:@Scope("prototype")

2.4 注解控制对象的生命周期

@PostConstruct:初始化方法使用的注解

@PreDestroy:销毁方法使用的注解

四、面向切面AOP

在 OOP(object oriented programing,面向对象编程) 中模块化的关键单元是类,而在 AOP中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。 所谓切面,相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块。

 

1、AOP概述

AOP:aspect oriented programing,面向切面编程, 通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 AOP 要达到的效果是,保证开发者不修改源代码的前提下,去为系统中的业务组件添加某种通用功能。AOP 的本质是由 AOP 框架修改业务组件的多个方法的源代码

  1. 定义目标类target:需要被写入功能的类 需要切入的方法叫切入点pointcut

  2. 定义切面类aspect:该类中定义的是需要切入的功能 方法叫通知advice

  3. 把切面类中的通知切入到目标类中的切入点(织入)weaving--动态代理

 

2、AOP使用场景

Authentication 权限 Caching 缓存 Context passing 内容传递 Error handling 错误处理 Lazy loading 懒加载 Debugging  调试 logging, tracing, profiling and monitoring 记录跟踪 优化 校准 Performance optimization 性能优化 Persistence  持久化 Resource pooling 资源池 Synchronization 同步 Transactions 事务

3、AOP实现分类

3.1 静态代理

静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。

3.2 动态代理

AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。

3.2.1 JDK动态代理

使用JDK代理,必须有接口,基于父接口的动态代理

public class AopProxy {
    public static void main(String[] args) {
        //创建目标类对象
        UserService userService = new UserServiceImpl();
​
        //创建切面类对象
        MyAspect myAspect = new MyAspect();
​
        //利用jdk动态代理生成代理,实现织入
        UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                myAspect.before();
                Object obj = method.invoke(userService, args);
                myAspect.after();
                return obj;
            }
        });
​
        proxy.addUser();
    }
}

运行结果:

 

3.2.2 cglib动态代理

没有接口的时候用这种,spring本身就支持cglib动态代理,不需要有接口,代理对象是被代理类的子类对象,基于父类的动态代理

public class CglibProxy {
    public static void main(String[] args) {
        //创建目标类对象,并没有父接口
        UserServiceImpl userServiceImpl = new UserServiceImpl();
​
        //创建切面类对象
        MyAspect myAspect = new MyAspect();
​
        //使用cglib生成代理对象
        //创建一个增强类对象
        Enhancer enhancer = new Enhancer();
​
        //指定代理对象的类型
        enhancer.setSuperclass(UserServiceImpl.class);
​
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                myAspect.before();
                Object obj = method.invoke(userServiceImpl, objects);
                myAspect.after();
                return obj;
            }
        });
​
        //生成代理对象
        UserServiceImpl proxy = (UserServiceImpl) enhancer.create();
        proxy.addUser();
    }
}

运行结果同上

4、SpringAOP

spring已经实现了aop,spring框架可以生成代理对象。

AOP联盟:制定了切面类的接口规范(接口)。

 

4.1 声明式实现(基于XML方式)

实现步骤

  1. 配置文件中配置pointcut

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    ​
        <!--创建目标类对象-->
        <bean id="userService" class="spring_aop2.com.UserServiceImpl"></bean>
    ​
        <!--创建切面类对象-->
        <bean id="myAspect" class="spring_aop2.com.MyAspect"></bean>
    ​
        <!--织入:全自动方式aop标签-->
        <aop:config>
            <!--先指定需要被切入通知的切入点,要使用切入点表达式说明,使用切入点表达式,需要加入spring-aspects依赖-->
            <aop:pointcut id="points" expression="execution(* spring_aop2.com.UserService.*(..))"/>
            <!--把切面类对象中的通知切入到指定的切入点-->
            <aop:advisor advice-ref="myAspect" pointcut-ref="points"></aop:advisor>
        </aop:config>
    </beans>

  2. 在java中用编写实际的aspect 类

    //切面类 aspect: 在目标类中的方法中要加入的功能
    //AOP联盟:制定了切面类的接口规范(接口)
    public class MyAspect implements MethodInterceptor {
    ​
        //环绕通知:在目标类中的切入点之前和之后切入功能
        //前置通知,后置通知,异常抛出通知
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            System.out.println("开启事务");
            Object obj = methodInvocation.proceed();//执行目标类对象中的方法
            System.out.println("提交事务");
            return obj;
        }
    }

  3. 针对对切入点进行相关的业务处理。

    public class UserServiceImpl implements UserService {
    ​
        @Override     //pointcut :切入点
        public void addUser() {
            System.out.println("add user...");
        }
        @Override
        public void deleteUser() {
            System.out.println("delete user...");
        }
        @Override
        public void updateUser() {
            System.out.println("update user...");
        }
    }

  4. 测试

        @Test
        public void AopTest2(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean_aop2.xml");
            UserService userService = (UserService) applicationContext.getBean("userService");
            userService.addUser();
        }

  5. 运行结果

    开启事务
    add user...
    提交事务

4.2 注解式实现( 基于AspectJ )

  1. 配置文件

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    ​
        <context:component-scan base-package="spring_aspectj2.com"></context:component-scan>
    ​
        <!--让aop生效-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

  2. 切面类

    @Component
    @Aspect
    public class MyAspect {
    ​
        // 切入点表达式 确定在哪里生效
        /*
            (1)、execution(): 表达式主体。
            (2)、第一个*号:表示返回类型,*号表示所有的类型。
            (3)、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
            (4)、第二个*号:表示类名,*号表示所有的类。
            (5)、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
        */
        @Pointcut("execution(* spring_aspectj2.com.UserServiceImpl.*(..))")
        public void myPoint(){
        }
    ​
        //自己定义通知方法
        //前置通知
        @Before("myPoint()")
        public void myBefore(JoinPoint joinPoint){//该参数可以得到切入点方法名
            System.out.println("前置通知...切入的方法是:"+joinPoint.getSignature().getName());
        }
    ​
        //后置通知:在切入点方法之后执行的,可以获取切入点方法的返回值
        @AfterReturning(value = "myPoint()",returning = "ret")
        public void myAfter(Object ret){
            System.out.println("后置通知...返回值是:"+ret);
        }
    ​
        //环绕通知:返回值类型必须是Object,参数必须是ProceedingJoinPoint
        @Around("myPoint()")
        public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("开启事务");
            Object proceed = joinPoint.proceed();
            System.out.println("提交事务");
            return proceed;
        }
    ​
        //异常抛出通知
        @AfterThrowing(value = "myPoint()",throwing = "t")
        public void myEhrowing(Throwable t){
            System.out.println("异常抛出通知...异常是:"+t.getMessage());
        }
    ​
        //最终通知:清理资源的功能,即使异常了也会执行
        @After("myPoint()")
        public void myFinal(){
            System.out.println("最终通知...");
        }
    ​
    }

  3. 测试

        @Test
        public void AspectJTest(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean_aspectj2.xml");
            UserService userService = applicationContext.getBean("userServiceImpl", UserService.class);
            userService.deleteUser();
        }
    ​

  4. 运行结果

    开启事务
    前置通知...切入的方法是:deleteUser
    delete user...
    后置通知...返回值是:hello
    最终通知...
    提交事务

五、配置文件、注解式配置

1、纯配置文件配置

  • 配置文件bean.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    ​
        <!--加载配置文件-->
        <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
        <!--创建连接池对象-->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="${jdbc.driver}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.pwd}"></property>
        </bean>
    ​
        <!--创建jdbcTemplate的对象-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
        <!--创建userDao的对象-->
        <bean id="userDao" class="jdbc2.dao.impl.UserDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
        
        <!--创建userService对象-->
        <bean id="userService" class="jdbc2.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"></property>
        </bean>
    </beans>

  • db.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/test
    jdbc.username=root
    jdbc.pwd=123456

  • 测试类

        @Test
        public void test(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    ​
            UserService userService = (UserService) applicationContext.getBean("userService");
    ​
            List<User> list = userService.findAll();
            for (User user:list){
                System.out.println(user);
            }
        }

  • 测试结果

    User{id=1, name='bbb'}
    User{id=2, name='aaa'}
    User{id=3, name='333'}

2、半注解半配置文件配置

是自己写的类就加注解,不是自己写的类就用bean.xml创建对象,配置文件也用xml写配置

  • 配置文件bean2.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    ​
        <!--扫描-->
        <context:component-scan base-package="jdbc3"></context:component-scan>
    ​
        <!--加载配置文件-->
        <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
        <!--创建连接池对象-->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
            <property name="driverClassName" value="${jdbc.driver}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.pwd}"></property>
        </bean>
    ​
        <!--创建jdbcTemplate的对象-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    </beans>

  • db.properties同上

  • dao、service层

    @Repository   //dao注解
    public class UserDaoImpl implements UserDao {
    ​
        @Autowired   //根据类型创建对象,但不是自己写的类,所以还是要在bean.xml中配置
        private JdbcTemplate jdbcTemplate;
    ​
        //一定要加set方法,不然创建不了对象
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    ...
    }
    @Service("userService")
    public class UserServiceImpl implements UserService {
    ​
        @Autowired
        private UserDao userDao;
    ​
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    ​
        @Override
        public List<User> findAll() {
            return userDao.findAll();
        }
    }
    
    
  • 测试

        @Test
        public void test(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean2.xml");
    ​
            UserService userService = (UserService) applicationContext.getBean("userService");
            List<User> list = userService.findAll();
            for (User user:list){
                System.out.println(user);
            }
        }

  • 运行结果

    User{id=1, name='bbb'}
    User{id=2, name='aaa'}
    User{id=3, name='333'}

3、纯注解式配置

  • 配置子类(数据库),配置文件db.properties同上

    @Configuration // 说明这是一个配置类
    public class JdbcConfig {
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.pwd}")
        private String pwd;
    ​
        //spring创建的对象会放在容器中,每个对象有id,但是自己创建的对象不会放在容器中,所以要加bean注解
        @Bean(name = "jdbcTemplate")  //默认的id是方法名字
        public JdbcTemplate getJdbcTemplate(@Qualifier("dataSource1") DataSource dataSource) {
            return new org.springframework.jdbc.core.JdbcTemplate(dataSource);
        }
    ​
        @Bean(name = "dataSource1")//Bean注解可以把方法返回的对象放入Spring容器中,name属性用来指定对象的id
        public DataSource getDataSource(){
            BasicDataSource basicDataSource = new BasicDataSource();
            basicDataSource.setDriverClassName(driver);
            basicDataSource.setUrl(url);
            basicDataSource.setUsername(username);
            basicDataSource.setPassword(pwd);
            return basicDataSource;
        }
    }

  • 总配置类

    @Configuration//指明这是一个配置类
    @ComponentScan({"jdbc3"})//扫描包
    @Import(JdbcConfig.class)// 子类配置类 若多个用,隔开即可
    @PropertySource("classpath:db.properties")// 配置文件
    public class SpringConfig {
    }

  • 测试

        @Test
        public void test(){
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
    ​
            UserService userService = (UserService) applicationContext.getBean("userService");
            List<User> list = userService.findAll();
            for (User user:list){
                System.out.println(user);
            }
        }

  • 运行结果

    User{id=1, name='bbb'}
    User{id=2, name='aaa'}
    User{id=3, name='333'}

六、spring事务管理

spring实现了AOP,事务可以使用AOP来处理,所以spring负责管理事务

1、spring和事务有关的接口

接口说明
切面类:PlatformTransactionManager平台事务管理器,spring要管理事务,必须使用事务管理器,进行事务配置时,必须配置事务管理器。
-->DataSourceTransactionManager:jdbc方式操作数据库的事务管理器
TransactionStatus事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成
TransactionDefinition事务详情(事务定义、事务属性),spring用于确定事务具体详情,例如:传播行为,隔离级别、是否只读、超时时间 等。进行事务配置时,必须配置详情。

2、事务的7个传播行为

事务传播行为说明
PROPAGATION_REQUIRED , required,必须 【默认值】 用于增删改支持当前事务,A如果有事务,B将使用该事务。 如果A没有事务,B将创建一个新的事务。
PROPAGATION_SUPPORTS ,supports ,支持 用于查询 也设置只读支持当前事务,A如果有事务,B将使用该事务。 如果A没有事务,B将以非事务执行。
PROPAGATION_MANDATORY,mandatory ,强制支持当前事务,A如果有事务,B将使用该事务。 如果A没有事务,B将抛异常。
PROPAGATION_REQUIRES_NEW , requires_new ,必须新的如果A有事务,将A的事务挂起,B创建一个新的事务 如果A没有事务,B创建一个新的事务
PROPAGATION_NOT_SUPPORTED ,not_supported ,不支持如果A有事务,将A的事务挂起,B将以非事务执行 如果A没有事务,B将以非事务执行
PROPAGATION_NEVER ,never,从不如果A有事务,B将抛异常 如果A没有事务,B将以非事务执行
PROPAGATION_NESTED ,nested ,嵌套A和B底层采用保存点机制,形成嵌套事务。

3、事务的4个隔离级别

int ISOLATION_READ_UNCOMMITTED = 1;// 读未提交
int ISOLATION_READ_COMMITTED = 2;// 读提交
int ISOLATION_REPEATABLE_READ = 4;// 可重复读
int ISOLATION_SERIALIZABLE = 8;// 可序列化

4、使用注解式管理事务

4.1 编程式事务

使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。

TransactionProxyFactoryBean

  • 代理对象接口

  • 目标类对象

  • 切面类对象

  • 配置事务详情

    <!--切面类对象,事务来自Connection,Connection来自于连接池-->
    <bean id="txManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
​
    <!--实现,spring的半自动方式aop-->
    <bean id="proxyObj" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!--设置代理对象的接口-->
        <property name="proxyInterfaces" value="com.service.AccountService"></property>
​
        <!--设置目标类对象-->
        <property name="target" ref="accountService"></property>
​
        <!--设置切面类对象-->
        <property name="transactionManager" ref="txManger"></property>
​
        <!--设置事务详情-->
        <property name="transactionAttributes">
            <props>
                <prop key="zhuanZhang">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
            </props>
        </property>
    </bean>

测试

    @Test
    public void tests()
    {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService =  applicationContext.getBean("proxyObj",AccountService.class);
​
        accountService.zhuanZhang();
    }

4.2 声明式事务

建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

基于xml文件的声明式事务

配置:applicationContext2.xml

    <!--切面类对象,事务来自Connection,Connection来自于连接池-->
    <bean id="txManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
​
    <!--实现,spring的全自动方式aop-->
    <tx:advice transaction-manager="txManger" id="aspects">
        <!--设置事务详情-->
        <tx:attributes>
            <tx:method name="zhuanZhang" propagation="REQUIRED" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>
​
    <aop:config>
        <aop:advisor advice-ref="aspects" pointcut="execution(* com.service.impl.AccountServiceImpl.*(..))"></aop:advisor>
    </aop:config>

测试:

   @Test
    public void tests2()
    {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
        AccountService accountService = (AccountService) applicationContext.getBean("accountService");
​
        accountService.zhuanZhang();
    }

基于注解的声明式事务

  • 配置applicationContext3.xml

        <!--让事务注解生效,半注解半配置文件配置-->
        <tx:annotation-driven transaction-manager="txManger"></tx:annotation-driven>

  • 任务类加注解

    //事务注解
    @Transactional(propagation = Propagation.REQUIRED)
    @Service("accountService")
    public class AccountServiceImpl implements AccountService {。。。}

  • 测试

    //spring整合junit
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext3.xml")// 加载配置文件
    public class AccountTest2 {
    ​
        @Autowired
        private AccountService accountService;
        @Test
        public void tests() {
            accountService.zhuanZhang();
        }
    }

5、全注解管理事务

  • 配置类(两个子配置类,导入到配置类中即可生效)

    public class TransactionConfig {
    ​
        @Bean(name = "txManger")
        public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }
    public class JdbcConfig {
    ​
        // 取配置文件中的值
        @Value("${jdbc.driver}")
        private String driver;
    ​
        @Value("${jdbc.url}")
        private String url;
    ​
        @Value("${jdbc.username}")
        private String username;
    ​
        @Value("${jdbc.pwd}")
        private String password;
    ​
        // 把方法返回的对象放入Spring容器中,name属性用来指定对象的id
        @Bean(name = "jdbcTemplate")
        public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
            return new JdbcTemplate(dataSource);
        }
    ​
        @Bean(name = "dataSource")
        public BasicDataSource getBasicDataSource() {
            BasicDataSource basicDataSource = new BasicDataSource();
            basicDataSource.setDriverClassName(driver);
            basicDataSource.setUrl(url);
            basicDataSource.setUsername(username);
            basicDataSource.setPassword(password);
            return basicDataSource;
        }
    }
    @Configuration  //说明这是一个配置类
    @ComponentScan(basePackages = "annocom")  //扫描的包
    @Import({JdbcConfig.class,TransactionConfig.class})  //导入配置类
    @PropertySource("db.properties")   //加载配置文件
    @EnableTransactionManagement//开启事务管理
    public class SpringConfig {
    }

  • 测试

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class)
    public class Tests {
    ​
        @Autowired
        private AccountService accountService;
    ​
        @Test
        public void test() {
            accountService.zhuanZhang();
        }
    }

标签:事务,配置文件,对象,Spring,spring,注解,public
来源: https://blog.csdn.net/hello222333444/article/details/121552579

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有