欢迎来到小房子杂记 返回顶部

JavaEE之Spring框架

Spring 学习笔记

一、Spring 简介

二、Spring 体系结构

三、Spring 环境配置

四、Spring IOC(控制反转)

五、Spring DI(依赖注入)

六、Spring AOP(面向方面的编程)

七、Spring 基于注解的配置

八、Spring JDBC

九、Spring 事务管理

 

一、Spring 简介

  1. 简介

  • Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。

  • Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。

  • Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。

  • Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。

   

 

 

  1. 三层架构

  • A 表现层 web层 MVC是表现层的一个设计模型

  • B 业务层 service层

  • C 持久层 dao层

 

二、Spring 体系结构

Spring 是模块化的,Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。  

  

 

核心容器

核心容器由spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

  • spring-core模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。

  • context模块建立在由corebeans 模块的基础上建立起来的,它以一种类似于JNDI注册的方式访问对象。Context模块继承自Bean模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过Servelet容器)等功能。Context模块也支持Java EE的功能,比如EJB、JMX和远程调用等。ApplicationContext接口是Context模块的焦点。spring-context-support提供了对第三方库集成到Spring上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

  • spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。

它们的完整依赖关系如下图所示:

  

 

数据访问/集成

数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

  • JDBC 模块提供了JDBC抽象层,它消除了冗长的JDBC编码和对数据库供应商特定错误代码的解析。

  • ORM 模块提供了对流行的对象关系映射API的集成,包括JPA、JDO和Hibernate等。通过此模块可以让这些ORM框架和spring的其它功能整合,比如前面提及的事务管理。

  • OXM 模块提供了对OXM实现的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等。

  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从Spring 4.1开始,集成了spring-messaging模块。。

  • 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写beginTransaction()、commit()、rollback()等事务管理方法,声明式事务是通过注解或配置由spring自动处理,编程式事务粒度更细)

     

Web

Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

  • Web 模块提供面向web的基本功能和面向web的应用上下文,比如多部分(multipart)文件上传功能、使用Servlet监听器初始化IoC容器等。它还包括HTTP客户端以及Spring远程调用中与web相关的部分。。

  • Web-MVC 模块为web应用提供了模型视图控制(MVC)和REST Web服务的实现。Spring的MVC框架可以使领域模型代码和web表单完全地分离,且可以与Spring框架的其它所有功能进行集成。

  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。

  • Web-Portlet 模块提供了用于Portlet环境的MVC实现,并反映了spring-webmvc模块的功能。

     

其他

还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

  • AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

  • Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

  • Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

  • 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

 

三、Spring 环境配置

  1. spring相关jar包

 

  1. spring 核心配置文件(applicationContext.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
           "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

    <beans>

       <!--告诉spring帮我们创建对象-->
       <bean name="user" class="cn.edu.dgut.pojo.User"></bean>

    </beans>

     

  2. 测试类(SpringDemo01)

    public class SpringDemo01 {

       @Test
       public void fun1() {
           // 使用框架 API ClassPathXmlApplicationContext() 来创建应用程序的上下文
           ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
           // 使用已创建的上下文的 getBean() 方法来获得所需的 bean
           Object object = applicationContext.getBean("user");
           System.out.println(object);
      }

       @Test
       public void fun2() {
           // 利用框架提供的 XmlBeanFactory() API 去生成工厂 bean 以及利用 ClassPathResource() API 去加载在路径 CLASSPATH 下可用的 bean 配置文件
           BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext02.xml"));
           // 利用第一步生成的 bean 工厂对象的 getBean() 方法得到所需要的 bean
           User user = beanFactory.getBean(User.class);
           System.out.println(user);
      }

       @Test
       public void fun3() {
           // 使用框架 API ClassPathXmlApplicationContext() 来创建应用程序的上下文
           ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext02.xml");
           // 使用已创建的上下文的 getBean() 方法来获得所需的 bean
           Object user = applicationContext.getBean(User.class);
           System.out.println(user);
      }

    }

 

四、Spring IOC(控制反转)

  • Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans。

  • IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。

  1. Spring 的 BeanFactory 容器

    这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。BeanFactory 和相关的接口,比如BeanFactoryAware、DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。

 

  1. Spring ApplicationContext 容器

    Application Context 是 BeanFactory 的子接口,也被成为 Spring 上下文。

    Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。这个容器在 org.springframework.context.ApplicationContext interface 接口中定义。

    ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

 

  1. Bean

    被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。

  • Bean 的作用域

    当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 singleton

    作用域描述
    singleton 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
    prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
    request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
    session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
    global-session 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境

 

五、Spring DI(依赖注入)

Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。

  • 依赖注入(常用的为构造函数和set方法注入)

每个基于应用程序的 java 都有几个对象,由这些对象一起工作来呈现出终端用户所看到的工作的应用程序。当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能独立于其他 Java 类来增加这些类重用的可能性,并且在做单元测试时,测试独立于其他类的独立性。依赖注入(或有时称为布线)有助于把这些类粘合在一起,同时保持他们独立。

  1. Spring 基于构造函数的依赖注入

    当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。

  2. Spring 基于设值函数的依赖注入

    当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。

  3. P名称空间注入

    P名称空间注入走的也是set方法, 官方目的是简化set注入的property标签的写法。

  4. Spel注入

    Spring Expression Language(简称 SpEL)是一种功能强大的表达式语言、用于在运行时查询和操作对象图;语法上类似于 Unified EL,但提供了更多的特性,特别是方法调用和基本字符串模板函数。SpEL 的诞生是为了给 Spring 社区提供一种能够与 Spring 生态系统所有产品无缝对接,能提供一站式支持的表达式语言。

  5. 注入集合

    你已经看到了如何使用 value 属性来配置基本数据类型和在你的 bean 配置文件中使用<property>标签的 ref 属性来配置对象引用。

<?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"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   <!--set方法注入-->
   <bean name="user" class="cn.edu.dgut.pojo.User">
       <property name="id" value="1"></property>
       <property name="username" value="房子"></property>
       <property name="myPojo" ref="mypojo"></property>

       <!--注入数组-->
       <property name="arr">
           <array>
               <value>张三</value>
               <value>李四</value>
               <value>王五</value>
           </array>
       </property>

       <!--注入list集合-->
       <property name="list">
           <list>
               <value>张三</value>
               <value>李四</value>
               <value>王五</value>
               <ref bean="mypojo"></ref>
           </list>
       </property>

       <!--注入map集合-->
       <property name="map">
           <map>
               <entry key="name" value="张三"></entry>
               <entry key="username" value="李四"></entry>
               <entry key="uname" value="王五"></entry>
               <entry key="mypojo" value-ref="mypojo"></entry>
           </map>
       </property>
   </bean>

   <!--set方法注入-->
   <bean name="mypojo" class="cn.edu.dgut.pojo.MyPojo">
       <property name="id" value="1"></property>
       <property name="name" value="花花"></property>
       <property name="status" value="哗哗哗"></property>
   </bean>

   <!--构造方法注入-->
   <!--<bean name="user" class="cn.edu.dgut.pojo.User">
       <constructor-arg name="id" value="1"></constructor-arg>
       <constructor-arg name="username" value="sss"></constructor-arg>
       <constructor-arg name="myPojo" ref="mypojo"></constructor-arg>
   </bean>-->

   <!--P名称空间注入-->
   <!--<bean name="user" class="cn.edu.dgut.pojo.User" p:id="1" p:username="aa" p:myPojo-ref="mypojo">
   </bean>-->

   <!--Spel注入-->
   <!--<bean name="user" class="cn.edu.dgut.pojo.User">
       <property name="id" value="1"></property>
       <property name="username" value="#{'fff'}"></property>
       <property name="myPojo" ref="mypojo"></property>
   </bean>-->

</beans>

 

六、Spring AOP(面向方面的编程)

  • Spring 框架的一个关键组件是面向方面的编程(AOP)框架。面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样的常见的很好的方面的例子,如日志记录、审计、声明式事务、安全性和缓存等。

  • 在 OOP 中,关键单元模块度是类,而在 AOP 中单元模块度是方面。依赖注入帮助你对应用程序对象相互解耦和 AOP 可以帮助你从它们所影响的对象中对横切关注点解耦。AOP 是像编程语言的触发物,如 Perl,.NET,Java 或者其他。

  • Spring AOP 模块提供拦截器来拦截一个应用程序,例如,当执行一个方法时,你可以在方法执行之前或之后添加额外的功能。

AOP 术语

描述
Aspect 一个模块具有一组提供横切需求的 APIs。例如,一个日志模块为了记录日志将被 AOP 方面调用。应用程序可以拥有任意数量的方面,这取决于需求。
Join point 在你的应用程序中它代表一个点,你可以在插件 AOP 方面。你也能说,它是在实际的应用程序中,其中一个操作将使用 Spring AOP 框架。
Advice 这是实际行动之前或之后执行的方法。这是在程序执行期间通过 Spring AOP 框架实际被调用的代码。
Pointcut 这是一组一个或多个连接点,通知应该被执行。你可以使用表达式或模式指定切入点正如我们将在 AOP 的例子中看到的。
Introduction 引用允许你添加新方法或属性到现有的类中。
Target object 被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象。也称为被通知对象。
Weaving Weaving 把方面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时,类加载时和运行时完成。

通知的类型

Spring 方面可以使用下面提到的五种通知工作:

通知描述
前置通知 在一个方法执行之前,执行通知。
后置通知 在一个方法执行之后,不考虑其结果,执行通知。
返回后通知 在一个方法执行之后,只有在方法成功完成时,才能执行通知。
抛出异常后通知 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
环绕通知 在建议方法调用之前和之后,执行通知。

Spring 中基于 AOP 的 XML配置(applicationContext.xml)

<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
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <!--配置IOC 创建 目标类-->
   <bean name="userService" class="cn.edu.dgut.target.UserService"></bean>
   <!--配置IOC 创建 增强通知   -->
   <bean name="myAdvice" class="cn.edu.dgut.advice.MyAdvice"></bean>

   <!--配置AOP 织入过程-->
   <aop:config>
       <!--配置切点
        切入点表达式 写延伸写法:
        1.  public  void com.shop.target.UserService.addUser()
        2.  void com.shop.target.UserService.addUser() // 修饰符省略
        3.  * com.shop.target.UserService.addUser()    // 任意返回值
        4.  * com.shop.target.UserService.*User()      // 返回名前缀任意
        5.  * com.shop.target.UserService.*User(..)    // 方法中参数 个数 任意 (0~n个)
        6.  * com.shop.target.*Service.*User(..)       // service 目标类的 类名前缀任意
               UserService
               OrderService
              ....
        7.  * com.shop.target..*Service.*User(..)   // 扫描 父包以及子包下的 类

       -->

       <!--配置增强(通知)
          after  后置通知 (最终通知)

          1. 肯定在目标方法之后执行

          2.不管代码之间发生任何异常,该通知仍然会执行

          after-returning 后置通知

          1. 肯定在目标方法之后执行

          2. 如果代码发生了异常 ,该通过将不会再去执行

       -->
       <aop:pointcut id="pc" expression="execution(public void cn.edu.dgut.target.UserService.addUser())"/>
       <aop:aspect ref="myAdvice">
           <!--前置通知-->
           <aop:before method="before" pointcut-ref="pc"></aop:before>
           <!--异常拦截通知-->
           <aop:after-throwing method="after_throwing" pointcut-ref="pc"></aop:after-throwing>
           <!--后置通知 (目标方法正常运行后通知)-->
           <aop:after-returning method="after_returning" pointcut-ref="pc"></aop:after-returning>
           <!--环绕通知配置-->
           <!--<aop:around method="around" pointcut-ref="pc"></aop:around>-->
           <!--后置通知 (最终通知)-->
           <aop:after method="after" pointcut-ref="pc"></aop:after>
       </aop:aspect>
   </aop:config>

</beans>

 

七、Spring 基于注解的配置

从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。

  • IOC注解配置实现

  1. 实体类(User、MyPojo)

    @Component(value = "user")
    public class User {
       @Value("2")
       private int id;

       @Value(value = "李云龙")
       private String username;

       //   @Autowired
    //   @Qualifier("mypojo")
       @Resource(name = "mypojo2")
       private MyPojo myPojo;

       public User() {
      }

       public User(int id, String username, MyPojo myPojo) {
           this.id = id;
           this.username = username;
           this.myPojo = myPojo;
      }

       public int getId() {
           return id;
      }

       public void setId(int id) {
           this.id = id;
      }

       public String getUsername() {
           return username;
      }

       public void setUsername(String username) {
           this.username = username;
      }

       public MyPojo getMyPojo() {
           return myPojo;
      }

       public void setMyPojo(MyPojo myPojo) {
           this.myPojo = myPojo;
      }

       @Override
       public String toString() {
           return "User{" +
                   "id=" + id +
                   ", username='" + username + '\'' +
                   ", myPojo=" + myPojo +
                   '}';
      }
    }
    @Component("mypojo")
    public class MyPojo {
       @Value("3")
       private int id;
       @Value("赵刚")
       private String name;
       @Value("政委")
       private String status;

       public int getId() {
           return id;
      }

       public void setId(int id) {
           this.id = id;
      }

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public String getStatus() {
           return status;
      }

       public void setStatus(String status) {
           this.status = status;
      }

       @Override
       public String toString() {
           return "MyPojo{" +
                   "id=" + id +
                   ", name='" + name + '\'' +
                   ", status='" + status + '\'' +
                   '}';
      }
    }
  2. 配置文件

    <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
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

       <bean name="mypojo2" class="cn.edu.dgut.pojo.MyPojo">
           <property name="id" value="3"></property>
           <property name="name" value="孔捷"></property>
           <property name="status" value="团长"></property>
       </bean>

       <!--开启扫描-->
       <context:component-scan base-package="cn.edu.dgut.pojo"></context:component-scan>

    </beans>
  3. 测试类

    public class SpringDemo01 {

       @Test
       public void fun1() {
           // 使用框架 API ClassPathXmlApplicationContext() 来创建应用程序的上下文
           ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
           // 使用已创建的上下文的 getBean() 方法来获得所需的 bean
           Object object = applicationContext.getBean("user");
           System.out.println(object);
      }

    }

 

  • AOP注解配置实现

  1. 目标类(UserService)

    @Component
    public class UserService {
       public void addUser() {
           //int i = 1 / 0;
           System.out.println("添加用户");
      }

       public void update() {
           System.out.println("修改用户");
      }
    }
  2. 增强(通知类MyAdvice)

    @Component
    @Aspect
    public class MyAdvice {
       @Pointcut("execution(* cn.edu.dgut.target.*Service.*User(..))")
       public void selectAll() {
      }

       //@Before(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
       @Before("selectAll()")
       public void before() {
           System.out.println("开启事务");
      }

       //@AfterThrowing(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
       @AfterThrowing("selectAll()")
       public void after_throwing() {
           System.out.println("出现异常,程序中断");
      }

       //@AfterReturning(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
       @AfterReturning("selectAll()")
       public void after_returning() {
           System.out.println("目标方法正常运行");
      }

       //@Around(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
       public Object around(ProceedingJoinPoint pjp) throws Throwable {
           System.out.println("开启事务");
           //System.out.println("环绕通知");
           Object proceed = pjp.proceed();
           System.out.println("提交事务");
           return proceed;
      }

       //@After(value = "execution(void cn.edu.dgut.target.UserService.addUser())")
       @After("selectAll()")
       public void after() {
           System.out.println("提交事务");
      }

    }
  3. 测试类

    public class SpringDemo01 {

       @Test
       public void fun1() {
           // 使用框架 API ClassPathXmlApplicationContext() 来创建应用程序的上下文
           ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
           // 使用已创建的上下文的 getBean() 方法来获得所需的 bean
           UserService userService = (UserService) applicationContext.getBean("userService");
           userService.addUser();
      }

    }
  4. 配置文件(applicationContext.xml)

    <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
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

       <!--开启IOC 扫描-->
       <context:component-scan base-package="cn.edu.dgut"></context:component-scan>

       <!--开启AOP 扫描-->
       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    </beans>

     

八、Spring JDBC

  • 在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等。但 Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQL 语句,处理异常,处理事务,到最后关闭连接。

  • Spring JDBC 提供几种方法和数据库中相应的不同的类与接口。我将给出使用 JdbcTemplate 类框架的经典和最受欢迎的方法。这是管理所有数据库通信和异常处理的中央框架类。

JdbcTemplate 类

  • JdbcTemplate 类执行 SQL 查询、更新语句和存储过程调用,执行迭代结果集和提取返回参数值。它也捕获 JDBC 异常并转换它们到 org.springframework.dao 包中定义的通用类、更多的信息、异常层次结构。

  • JdbcTemplate 类的实例是线程安全配置的。所以你可以配置 JdbcTemplate 的单个实例,然后将这个共享的引用安全地注入到多个 DAOs 中。

  • 使用 JdbcTemplate 类时常见的做法是在你的 Spring 配置文件中配置数据源,然后共享数据源 bean 依赖注入到 DAO 类中,并在数据源的设值函数中创建了 JdbcTemplate。

环境搭建(除了前面添加的核心jar包和第三方包,还需加入以下jar包)

  

配置数据源

<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost:3306/TEST"/>
  <property name="username" value="root"/>
  <property name="password" value="password"/>
</bean>

创建jdbcTemplate

<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   <property name="dataSource" ref="dataSource"></property>
</bean>

数据访问对象(DAO)

  • DAO 代表常用的数据库交互的数据访问对象。DAOs 提供一种方法来读取数据并将数据写入到数据库中,它们应该通过一个接口显示此功能,应用程序的其余部分将访问它们。

    <bean name="userDao" class="cn.edu.dgut.dao.impl.UserDaoImpl">
       <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

执行 SQL 语句

  • 使用 SQL 和 jdbcTemplate 对象在数据库表中执行 CRUD(创建、读取、更新和删除)操作。

  1. 查询一个整数类型

String SQL = "select count(*) from Student";
int rowCount = jdbcTemplateObject.queryForInt( SQL );
  1. 查询一个 long 类型

String SQL = "select count(*) from Student";
long rowCount = jdbcTemplateObject.queryForLong( SQL );
  1. 一个使用绑定变量的简单查询

String SQL = "select age from Student where id = ?";
int age = jdbcTemplateObject.queryForInt(SQL, new Object[]{10});
  1. 查询字符串

String SQL = "select name from Student where id = ?";
String name = jdbcTemplateObject.queryForObject(SQL, new Object[]{10}, String.class);
  1. 查询并返回一个对象

String SQL = "select * from Student where id = ?";
Student student = jdbcTemplateObject.queryForObject(SQL,
                 new Object[]{10}, new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
  public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
     Student student = new Student();
     student.setID(rs.getInt("id"));
     student.setName(rs.getString("name"));
     student.setAge(rs.getInt("age"));
     return student;
  }
}
  1. 查询并返回多个对象

String SQL = "select * from Student";
List<Student> students = jdbcTemplateObject.query(SQL,
                        new StudentMapper());
public class StudentMapper implements RowMapper<Student> {
  public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
     Student student = new Student();
     student.setID(rs.getInt("id"));
     student.setName(rs.getString("name"));
     student.setAge(rs.getInt("age"));
     return student;
  }
}
  1. 在表中插入一行

String SQL = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 11} );
  1. 更新表中的一行

String SQL = "update Student set name = ? where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 10} );
  1. 从表中删除一行

String SQL = "delete Student where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{20} );

 

九、Spring 事务管理

  1. 一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是 ACID

  • 原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。

  • 一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。

  • 隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。

  • 持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

 

  1. 一个真正的 RDBMS 数据库系统将为每个事务保证所有的四个属性。使用 SQL 发布到数据库中的事务的简单视图如下:

  • 使用 begin transaction 命令开始事务。

  • 使用 SQL 查询语句执行各种删除、更新或插入操作。

  • 如果所有的操作都成功,则执行提交操作,否则回滚所有操作。

 

  1. Spring 支持两种类型的事务管理:

  • 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。

  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

    声明式事务管理比编程式事务管理更可取,尽管它不如编程式事务管理灵活,但它允许你通过代码控制事务。但作为一种横切关注点,声明式事务管理可以使用 AOP 方法进行模块化。Spring 支持使用 Spring AOP 框架的声明式事务管理。

 

  1. Spring 事务抽象

Spring事务管理的五大属性:隔离级别传播行为是否只读事务超时回滚规则

  • 隔离级别的可能值

    序号隔离 & 描述
    1 TransactionDefinition.ISOLATION_DEFAULT这是默认的隔离级别。
    2 TransactionDefinition.ISOLATION_READ_COMMITTED表明能够阻止误读;可以发生不可重复读和虚读。
    3 TransactionDefinition.ISOLATION_READ_UNCOMMITTED表明可以发生误读、不可重复读和虚读。
    4 TransactionDefinition.ISOLATION_REPEATABLE_READ表明能够阻止误读和不可重复读;可以发生虚读。
    5 TransactionDefinition.ISOLATION_SERIALIZABLE表明能够阻止误读、不可重复读和虚读。
  • 传播类型的可能值

    序号传播 & 描述
    1 TransactionDefinition.PROPAGATION_MANDATORY支持当前事务;如果不存在当前事务,则抛出一个异常。
    2 TransactionDefinition.PROPAGATION_NESTED如果存在当前事务,则在一个嵌套的事务中执行。
    3 TransactionDefinition.PROPAGATION_NEVER不支持当前事务;如果存在当前事务,则抛出一个异常。
    4 TransactionDefinition.PROPAGATION_NOT_SUPPORTED不支持当前事务;而总是执行非事务性。
    5 TransactionDefinition.PROPAGATION_REQUIRED支持当前事务;如果不存在事务,则创建一个新的事务。
    6 TransactionDefinition.PROPAGATION_REQUIRES_NEW创建一个新事务,如果存在一个事务,则把当前事务挂起。
    7 TransactionDefinition.PROPAGATION_SUPPORTS支持当前事务;如果不存在,则执行非事务性。
    8 TransactionDefinition.TIMEOUT_DEFAULT使用默认超时的底层事务系统,或者如果不支持超时则没有。

 

  1. 配置事务核心管理者

<bean name="dataSourceTransactionManager"
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"></property>
</bean>

 

  1. 配置事务通知

<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
   <tx:attributes>
       <tx:method name="transferAccount" isolation="READ_UNCOMMITTED" propagation="REQUIRED" read-only="false"/>
   </tx:attributes>
</tx:advice>

 

  1. 配置AOP 织入

<aop:config>
   <!--配置切点表达式-->
   <aop:pointcut id="pc"
                 expression="execution(* cn.edu.dgut.service.impl.AccountServiceImpl.transferAccount(..))"/>
   <!-- 配置切面 -->
   <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"></aop:advisor>
</aop:config>

 

  1. 注解实现事务

  • 开启事务扫描

    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation>
  • service

    public class AccountServiceImpl implements AccountService {
       private AccountDao accountDao;

       public void setAccountDao(AccountDao accountDao) {
           this.accountDao = accountDao;
      }

       // 转账
       @Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED, readOnly = false)
       @Override
       public void transferAccount(double money, int from_id, int to_id) {
           // 转账方减钱
           accountDao.reduceMoney(money, from_id);

           //int i = 1 / 0;

           // 收款方加钱
           accountDao.addMoney(money, to_id);
      }
    }

     

 

本文是学习spring的笔记总结,欢迎大家批评指正,有什么问题可以评论区交流。

参考链接:https://www.w3cschool.cn/wkspring/

 

posted @ 2020-08-08 19:38  小房子杂记  阅读(378)  评论(0)    收藏  举报