Spring最佳教学教程入门笔记

一、Spring简介

Spring 是由 Rod Johnson 2004 组织和开发的一个分层的 Java SE/EE fu stack (一站式)轻量级开源框架,Spring 可以被看作是一个大型工厂,这个工厂的作用就是生产和管理 Spring 容器中的Bean。它以 loC (Inversion of Control ,控制反转)和 AOP ( Aspect Oriented Programming , 面向切面编程)为内核,Spring 致力于 Java EE 应用各层的解决方案,在表现层它提供了 Spr ng MVC 以及与 Struts 框架的整合功能;在业务逻辑层可以管理事务 记录日志等;在持久层可以整合 MyBatis Hibernate JdbcTemplate 等。在 Spring 中,认为一切 Java 类都是资源,而资源都是类的实例对象(Bean),容纳并管理这些 Bean 的是 Spring 所提供的 IoC 容器,所以 Spring 是一种基于 Bean 的编程。

1、Spring核心概念

IoC(Inversion of Control ,控制反转):当某个 Java 对象(调用者)需要调用另一个 Java 对象(被调用者,即被依赖对象)时, 在传统模式下,调用者通常会采用 "new 被调用者"的代码方式来创建对象,这种方式会导致调用者与被调用者之间的捐合性增加,不利于后期项目的升级和维。在使用 Spring 框架之后,对象的实例不再由调用者来创建,而是由 Spring 容器来创建,Spring 容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制 这样,控制权由应用代码转移到了 Spring 容器,控制权发生了反转,这就是 Spring 的控制反转。

DI(Dependency Injection ,依赖注入):与控制反转 (loC) 的含义相同,只不过这两 个称呼是从两个角度描述的同一个概念 对Spring 容器的角度来看, Spring 容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它依赖的实例,这就是 Spring 的依赖注入。依赖注入的作用就是在使用 Spring 框架创建对象时,动态地将其所依赖的对象注入Bean组件中。


AOP(Aspect Oriented Programming,面向切面编程):AOP 采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。

2、Spring IoC容器

Spring 框架的主要功能是通过其iOC容器来实现的,Spring 框架提供了两种IoC容器初始化方式,分别为 BeanFactory和AppIicationContext

**BeanFactory **,是基础类型的IoC容器,提供了完整的IoC服务支持。简单说它就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean ,并调用它们的生命周期方法。BeanFactory最常用的实现类是XmIBeanFactory,该类会加载配置文件,根据 XML 配置文件中的定义来装配 Bean。但是此方法已不推荐使用。

ApplicationContext是BeanFactory 的子接口,也被称为应用上下文,包含了BeanFactory 的所有功能,还扩展了其它功能。
ClassPathXmlAp~licationContext 会从类路径 classPath 中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作,其使用语法如下:

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

Spring IoC容器(ApplicationContext)负责创建Bean,并通过容器将功能类Bean注入到你需要的Bean中。

二、体系架构

![image.png](https://cdn.nlark.com/yuque/0/2022/png/22419003/1641899676605-4ef3b34a-f291-4be7-8fc0-5e3e6fc8ff50.png

图中每一个最小单元,Spring都至少有一个对应的jar包

1、核心容器(Core Container)

Spring 的核心容器是其他模块建立的基础,由 Beans 、Core 、Context 和 SpEL 表达式语言组成

  • Core 核心模块:提供了 Spring 框架的基本组成部分,包括 loC 和 DI 功能 ,是其他组件的基本核心。

  • Beans 模块:它包含访问配置文件、创建和管理 Bean 以及进行IOC/DI操作相关的所有类

  • Context 上下文模块:运行时Spring容器。建立在 Core Beans 模块的基础之上,它是访问定义和配置的任 何对象的媒介 其中 ApplicationConte 接口是上下文模块的焦点

  • SpEL 模块:是 Spring 后新增的模块,它提供了 Spring Expression Language 支持,支持在xml和注解中使用表达式类似jsp的EL表达式

    2、数据访问/集成(Data Access/Integration)

  • JDBC 模块:提供了一个 JDBC 的抽象层,大幅度地减少了在开发过程中对数据库操作的编码

  • Transactions 事务模块:支持对实现特殊接口以及所有 POJO 类的编程和声明式的事 务管理

    3、web层

  • Web 模块:提供了基本的 Web 开发集成特性,例如: 多文件上传功能 使用 Servlet 听器来初始化 loC 容器以及 Web 应用上下文

  • Servlet 模块:也称为 Spring-webmvc 模块,包含了 Spring 的模型一视图一控制器(MVC) REST Web Services 实现的 Web 应用程序

    4、其它模块

  • AOP 模块:提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按照功能

进行分离,以降低搞合性

  • Aspects 模块:提供了与 AspectJ 的集成功能, AspectJ 是一个功能强大且成熟的面向切

面编程 (AOP) 框架

  • Test 模块:提供了对单元测试和集成测试的支持

    三、快如入门

    1. Maven依赖

                  <!--引入spring-context包会自动引入Spring的四个核心包-->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.3.13</version>
          </dependency> 
    
                  <!--单独引入Spring的四个核心包-->
                  <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-core</artifactId>
              <version>5.3.14</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>5.3.14</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-beans</artifactId>
              <version>5.3.14</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-expression</artifactId>
              <version>5.3.14</version>
          </dependency>
    

    2、编写Spring的配置文件

    idea在resources里创建Spring Config xml文件applicationContext.xml(或者叫beans.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"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <!--Spring管理创建的对象,在Spring里都成为Bean,需要在这里进行注册-->
      <bean id="hello" class="com.example.spring.pojo.Hello">
          <property name="name" value="Spring"/>
      </bean>
    

</beans>

## 3、初始化Spring容器、实例化bean
```java
    public static void main(String[] args) {

        // 获取ApplicationContext,拿到Spring的容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
        // 将需要Spring管理创建对象的类在配置文件中注册,然后在需要用的地方直接get
        Hello name = (Hello) context.getBean("hello");
        System.out.println(name.toString());
    }

四、详解 Spring容器初始化

1、非web项目

非web项目通常需要手工创建ApplicationContext

// 1.初始化 spring 容器,加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2.通过容器获取Hello实例
Hello name = (Hello) context.getBean("hello");

2、Web项目

  • 在 Web 项目中, ApplicationContext 容器的实例化工作会交由 Web 服务器来完成,使用基于ContextLoader Listener实现的方式,此种方式只需要在web.xml 中添加如下代码

    <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- Spring配置文件默认在WEB-INF下,改到resources下-->
    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    

    applicationContext.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"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <!--将指定类配置给 Spring ,让 Spring 创建其对象的实例-->
      <bean id="hello" class="com.example.spring.pojo.Hello">
          <property name="name" value="Spring"/>
      </bean>
    

</beans>

# 五、详解 Bean
## 1、Bean的配置文件

- 如果在 bean中未指定id和name,Spring将会将class 值当作 id 使用。

- 在配置文件中,通常一个普通的 Bean 只需要定义 id (或 name) class 两个属性即可。

- applicationContext.xml
  
  ```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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  
    <!--将指定类配置给 Spring ,让 Spring 创建其对象的实例-->
    <bean id="hello" class="com.example.spring.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>

</beans>

## 2、Bean的实例化
在 Spring 中,要想使用容器中的 Bean ,需要实例化 Bean,实例化 Bean 有三种方式,分别为:构造器实例化、静态工厂方式实例化、实例工厂方式实例化(其中最常用的是构造器实例化)。
### (1)构造器实例化
构造器实例化是指 Spring 容器通过 Bean 对应类中默认的无参构造方法来实例化 Bean。
```java
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
        Hello name = (Hello) context.getBean("hello");
        System.out.println(name);
    }

(2) 静态工厂实例化

使用静态工厂实例化Bean要求开发者创建一个静态工厂的方法来创建 Bean 的实例,其 Bean 配置中的 class 属性所指定的不再是 Bean 实例的实现类,而是静态工厂类,同时还需要使用 factory-method 属性来指定所创建的静态工厂方法。

(3)实例工厂实例化

不再使用静态方法创建 Bean 实例,而是采用直接创建 Bean 实例的方式 同时,在配置文件中,需要实例化的 Bean也不是通过 class 属性直接指向的实例化类,而是通过 factory - bean 属性指向配置的实例工厂,然后使用 factory - method 属性确定使用工厂中的哪个方法。

3、Bean的作用域

bean有七种作用域,常用的是singleton和prototype。Spring 配置文件中, Bean 的作用域是通过<bean> 元素的 scope 属性来指定的,该属性值可以设置为 singleton、prototype、request、session、globalSession、application、websocket七个值。

  • singleton(单例)

使用 singleton 定义的 Bean 在Spring 容器中将只有一个实例,也就是说,无论有多少个 Bean引用它,始终将指向同一个对象,这也是 Spring 容器默认的作用域。

  • prototype(原型)

每次通过 Spring 容器获取的 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例。

<bean id="userDao" class="com.example.spring.pojo.UserDao" scope="singleton"/>

4、Bean的生命周期

Spring 容器可以管理 singleton 作用域的 Bean 的生命周期,在此作用域下, Spring 能够精确地知道该Bean 何时被创建,何时初始化完成以及何时被销毁。对于 prototype 作用域的Bean,Spring 只负责创建,当容器创建了 Bean 实例后, Bean 的实例就交给客户端代码来管理,Spring 容器将不再跟踪其生命周期 每次客户端请求 prototype 作用域的 Bean 时, Spring 容器都会创建一个新的实例,并且不会管那些被配置成 prototype 作用域的 Bean 的生命周期。

5、Bean的装配方式/Bean 依赖注入的方式

Bean 的装配可以理解为依赖关系注入Bean 的装配方式即 Bean 依赖注入的方式。Spring 容器支持多种形式的 Bean 的装配方式,如基于 XML 的装配、基于注解( Annotation )的装配、自动装配等。最常用的是基于注解的装配

(1)基于 XML 的装配

Spring 提供了两种基于 XML 的装配方式:设值注入( Setter Injection )和构造注入 (Constructor Injection)。
使用设值注入时,在 Spring 配置文件中,需要使用 <bean> 元素的子元素<property> 来为每个属性注入值;而使用构造注入时,在配置文件里,需要使用 <bean> 元素的子元素<constructor -arg> 来定义构造方法的参数,可以使用其 value 属性(或子元素)来设置该参数的值。
1.1 设值注入

  • Bean 类必须提供一个默认的无参构造方法

  • Bean 类必须为需要注入的属性提供对应的 setter 方法

      <bean id="hello" class="com.example.spring.pojo.Hello" >
          <property name="name" value="Spring"/>
          <property name="list">
              <list>
                  <value>"setlistvalue1"</value>
                  <value>"setlistvalue2"</value>
              </list>
          </property>
      </bean>
    

    1.2 构造注入

  • Bean提供带所有参数的有参构造方法。

      <bean id="hello" class="com.example.spring.pojo.Hello" >
          <constructor-arg index="0" name="name"/>
          <constructor-arg index="1">
              <list>
                  <value>"constructorvalue1"</value>
                  <value>"constructorvalue2"</value>
              </list>
          </constructor-arg>
      </bean>
    

    <constructor -arg >元素用于定义构造 参数 其属性 index 表示其索 引从0开始 ,value 属性用于设置注入 值,其子元素<Iist> 来为 User 类中对应的 list集合属性注入值 然后又使用了设值注入方式装 User 类的实 ,其中 <property> 元素用于调bean 实例中的 setter 方法完成属性赋值,从 依赖注入, 其子元素 Ii st> 同样是为 User类中对应 lis 集合属性注入值

(2)基于Annotation(注解)的装配

  1. 使用注解方式一

    <context:annotation-config/>
    

<bean id="myService" class="com.example.spring.service.MyServiceImpl"/>

> 上述 Spring 配置文件中的注解方式虽然较大程度简化了XML 文件中 Bean 的配置,但仍需要在 Spring 配置文件中一一配置相应的 Bean,比较麻烦。



2. **使用注解方式二**
- 项目必须要导入spring-aop依赖

- 配置文件中增加如下内容
  
  ```xml
  <!--使用context命名空间,通知Spring扫描指定包下所有Bean,进行注解解析-->
  <context:component-scan base-packaqe="com.example.spring"/>

使用注解装配,在需要配置为bean的类上增加上述Spring注解即可

  • 以下两个是完全等价的

    @Service
    public class MyServiceImpl {
    
      ...
    }
    
```xml
<bean id="myService" class="com.example.spring.service.MyServiceImpl"/>
  1. Spring的注解:

@Component 把这个注解放到类上,这个类被Spring管理了,它就成了一个bean,可以作用在任何层次。`
此注解有三个衍生注解分别用在MVC的三层架构上,但是功能都是一样的,把类注册到Spring中变成bean。

@Controller 用在控制层(Controller)
@Service用在业务层(Service)
@Repository用在数据访问层(DAO)

@Autowired用于对 Bean 的属性变量、属性的 setter 方法及构造方法进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。

@Qualifier与@Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为接Bean的实例名称装配, Bean 的实例名称由 @Qualifier 注解的参数指定。

@Resource其作用与 Autowired 一样,其区别在于@Autowired 默认按照 Bean 类型装配,而@Resource 默认按照 Bean 实例名称进行装配 @Resource 中有两个重要属性: name、type,Spring name 属性解析为 Bean 实例名称, type 属性解析为 Bean 实例类型 如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配;如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,再按照 Bean 类型进行装自己;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。

(3)自动装配

所谓自动装配,就是将一个 Bean 自动地注入到其他 Bean的Property中。Spring <bean> 元素中包含一个 autowire 属性,我们可以通过设置 autowire 的属性值,autowire=no/byType/byName/constructor,来自动装配 Bean。

  • autowire针对每个bean进行装配:

    <bean id="hello" class="com.example.spring.pojo.Hello" autowire="byType"/>
    
    <bean id="hello" class="com.example.spring.pojo.Hello" autowire="byName"/>
    

    byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id
    byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean id

六、AOP

1、AOP简介

(1)什么是AOP

AOP 的全称是 Aspect-Oriented Programming ,即面向切面编程(也称面向方面编程),) 是面向对象编程 (OOP) 的一种补充。
AOP 采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
AOP 框架有两个,分别为 Spring AOP、AspectJ。

(2)AOP术语

  • Aspect (切面):切面通常是指封装的用于横向插入系统功能(如事务、曰志等)的类

  • Joinpoint (连接点):连接点就是指方法的调用

  • Pointcut (切入点):通常指的是类或者方法名,如某个通知要应用到所有以 add开头的方法中,那么所有以 add开头的方法都是切入点****

  • Advice( 通知):AOP 框架在特定的切入点执行的增强处理,即在定义好的切入点处所要执行的程序代码。可以将其理解为切面类中的方法,它是切面的具体实现

  • Target Object (目标对象):是指所有被通知的对象

  • Proxy (代理):将通知应用到目标对象之后,被动态创建的对象

  • Weaving (织入):将切面代码插入到目标对象上,从而生成代理对象的过程

    2、动态代理

    (1)JDK动态代理

    待补充。。。

    (2)CGLIB代理

    待补充。。。

    3、AspectJ

    依赖包

  • spring-aspects:Spring AspectJ 提供的实现, Spring 的包中已经提供

  • aspectjweaver:: AspectJ 框架所提供的规范

    (1)基于XML的声明式AspectJ

    待补充。。。

    (2)基于注解的声明式AspectJ

  1. 注解
  • @Aspect
  • @Pointcut
  • @Before
  • @AfterReturning
  • @Around
  • @@AfterThrowing
  • @After
  • @DeclareParents
  1. 案例

    @Aspect
    @Component
    public class MyAspect {
    
     private Logger logger = LoggerFactory.getLogger(MyAspect.class);
    
     // 定义切入点表达式
     @Pointcut(value = "execution( * com.example.spring.controller.*.*(..))")
     public void myPoinCut(){}
    
     // 前置通知
     @Before("myPoinCut()")
     public void myBefore(JoinPoint joinPoint) {
         System.out.println("前置通知:模拟检查....");
         System.out.println("目标类是:"+joinPoint.getTarget());
         System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
     }
    
     // 后置通知
     @AfterReturning("myPoinCut()")
     public void myAfterReturning(JoinPoint joinPoint) {
         System.out.println("后置通知:模拟记录日志....");
         System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
     }
    
       // 环绕通知
     @Around("myPoinCut()")
     public Object myLogger(ProceedingJoinPoint pjp) throws Throwable {
         String className = pjp.getTarget().getClass().toString();
         String methodName = pjp.getSignature().getName();
         Object[] array = pjp.getArgs();
    
         ObjectMapper mapper = new ObjectMapper();
    
         logger.info("调用前:"+className+":"+methodName+"传递的参数为:"+mapper.writeValueAsString(array));
    
           // 执行当前目标方法
         Object obj = pjp.proceed();
    
         logger.info("调用后:"+className+":"+methodName+"返回值:"+mapper.writeValueAsString(obj));
    
         return obj;
     }
    
     // 异常通知
     public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
         System.out.println("异常通知:出错了," + e.getMessage());
     }
    
     // 最终通知
     @After("myPoinCut()")
     public void myAfter(){
         System.out.println("最终通知:结束了...");
     }
    }
    

    首先使用 @Aspect 注解定义了 切面 ,由于该类在Spring中是作为组件使用的,所以还需要添加@Component 注解才能生效,然后使@Poincut 注解来配置切入点表达式,并通过定义方法来表示切入点名称,接下来在每个通知对应的方法上添加了相应的注解,并将切入点名称 "myPointCut" 作为参数传递给需要执行增强的通知方法。如果需要其他参数,如异常通知的异常参数 ,可以根据代码提示传递相应的属性值。
    参考:https://www.bilibili.com/video/BV1yK411M7hb?p=2

    七、Spring JDBC

    Spring JDBC 模块负责数据库资源管理,JdbcTemplate 类是 Spring JDBC 的核心类

    1、添加依赖

         <!--spring-jdbc依赖-->
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-jdbc</artifactId>
             <version>5.3.13</version>
         </dependency>
         <!--mysql驱动依赖-->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>8.0.27</version>
         </dependency>
    

    2、添加JDBC配置

    <?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: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 https://www.springframework.org/schema/context/spring-context.xsd">
    

    <context:property-placeholder location="classpath:db.properties"/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="{jdbc.driverClass}"/> <property name="url" value="{jdbc.jdbcUrl}"/>
    <property name="username" value="{jdbc.username}"/> <property name="password" value="{jdbc.password}"/>
    </bean>

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

</beans>

> 定义 jdbcTemplate 时,需要将 dataSource 注入到 jdbcTemplate 中,而其他需要使用jdbcTemplate的Bean ,也需要将 jdbcTemplate 注入到该 Bean 中(通常注入到 Dao 类中,在Dao 类中进行与数据库的相关操作)。

## 3、使用Spring JdbcTemplate

```java
    @Test
    public void createTest() {
        // 获取Spring容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 获得JdbcTemplate实例
        JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");

        // 创建表
        jdbcTemplate.execute("CREATE TABLE `student` (\n" +
                "  `id` int(11) NOT NULL,\n" +
                "  `name` varchar(255) DEFAULT NULL,\n" +
                "  `age` int(11) DEFAULT NULL,\n" +
                "  PRIMARY KEY (`id`)\n" +
                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;");
    }

4、jdbcTemplate的常用方法

  • 创建Student POJO

  • 创建Student增、删、改、查的Service接口,这里直接创建了类

    public class StudentServiceImpl {
      private JdbcTemplate jdbcTemplate;
    
      public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
          this.jdbcTemplate = jdbcTemplate;
      }
    
      // 增加
      public int addStudent(Student student) {
    
          String sql = "insert into student(age,name) values(?,?)";
    
          // 定义个数组存储sql语句中的参数
          // sql语句里的参数顺序必须和传进去的参数顺序一致
          Object[] obj = new Object[]{
    
                  student.getAge(),
                  student.getName()
          };
    
          int num = this.jdbcTemplate.update(sql, obj);
          return num;
      }
    
      // 更新
    
      public int updateStudent(Student student) {
          // sql语句里的参数顺序必须和传进去的参数顺序一致
          String sql = "update student set name=?,age=? where id=?";
          Object[] params = new Object[]{
                  student.getName(), student.getAge(), student.getId()
          };
    
          int num = this.jdbcTemplate.update(sql, params);
          return num;
      }
    
      // 删除
      public int deleteStudent(int id) {
          String sql = "delete from Student where id = ?";
          int num = this.jdbcTemplate.update(sql, id);
          return num;
      }
    
      // 查询一个
      public Student findStudentById(int id) {
          String sql = "select * from student where id = ?";
          BeanPropertyRowMapper<Student> rowMapper = new BeanPropertyRowMapper<Student>(Student.class);
          return this.jdbcTemplate.queryForObject(sql, rowMapper, id);
      }
    
      // 查询所有
      public List<Student> findAllStudent() {
          String sql = "select * from student";
          BeanPropertyRowMapper<Student> rowMapper = new BeanPropertyRowMapper<Student>(Student.class);
          return this.jdbcTemplate.query(sql, rowMapper);
      }
    }
    
  • 在appcliationContext.xml里定义一个id为studentService的Bean,用于将jdbcTemplate注入到StudentService实例中。

  • 在单元测试类中测试增、删、改、查。

      @Test
      public void addStudentTest() {
          // 获取Spring容器
          ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
          StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService");
    
          Student student = new Student();
    
          student.setAge(19);
          student.setName("xie");
    
          int num = studentService.addStudent(student);
    
          if (num > 0) {
              System.out.println("成功插入了" + num + "条数据");
          } else {
              System.out.println("插入失败!");
          }
      }
    
      @Test
      public void updateStudentTest() {
          ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
          StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService");
    
          Student student = new Student();
          student.setId(1);
          student.setName("谢");
          student.setAge(28);
    
          int num = studentService.updateStudent(student);
          System.out.println(num);
      }
    
      @Test
      public void deleteStudentTest() {
          ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
          StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService");
          int num = studentService.deleteStudent(1);
          System.out.println(num);
      }
    
      @Test
      public void findByIdTest() {
          ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
          StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService");
    
          Student student = studentService.findStudentById(1);
          System.out.println(student);
      }
    
      @Test
      public void findAll() {
          ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
          StudentServiceImpl studentService = (StudentServiceImpl) applicationContext.getBean("studentService");
    
          List<Student> student = studentService.findAllStudent();
          System.out.println(student);
      }
    

    八、Spring 事务

    jar包spring-tx是Spring 提供的用于事务管理的依赖包。Spring 中的事务管理分为两种方式:一种是传统的编程式事务管理,另一种是声明式事务管理。

  • 编程式事务管理:是通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚 。

  • 声明式事务管理:是通过 AOP 技术实现的事务管理,其主要思想是将事务管理作为一个切面代码单独编写,然后通过 AOP 技术将事务管理的切面代码织入到业务目标类中。

Spring 的声明式事务管理可以通过两种方式来实现,一种是基于 XML 的方式,另一种是基 Annotation 的方式。

1、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: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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- 导入资源文件 读取db.properties文件中的数据 -->
    <context:property-placeholder location="classpath:db.properties"/>

    <!-- 配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.jdbcUrl}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 配置Spring的jdbcTemplate 并注入dataSource数据源-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置注入类-->
    <bean id="studentService" class="com.example.spring.service.StudentServiceImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

    <!--事务管理器,依赖于数据源-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:advice id="txAdvice"
               transaction-manager="transactionManager">
        <!-- 配置这个事务建议的属性 -->
        <tx:attributes>
            <!-- 指定所有get开头的方法执行在只读事务上下文中 -->
            <tx:method name="get*" read-only="true"/>
            <!-- 其余方法执行在默认的读写上下文中 -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <!-- <aop:pointcut/>元素定义AspectJ的切面表示法,这里是表示x.y.service.FooService包下的任意方法。 -->
        <aop:pointcut id="txPointCut" expression="execution(* com.example.spring.service.*.*(..))"/>
        <!-- 然后我们用一个通知器:<aop:advisor/>把这个切面和tx:advice绑定在一起,表示当这个切面:fooServiceOperation执行时tx:advice定义的通知逻辑将被执行 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>

2、注解方式

在Spring 容器中注册事务注解驱动。

<tx:annotation-driven transaction-manager="transactionManager"/>

在需要使用事务的 Spring Bean 类或者 Bean 类的方法上添加注解@Transactional如果将注解添加在 Bean 类上,则表示事务的设置对整个 Bean 类的所有方法都起作用;如果将注解添加在 Bean 类中的某个方法上,则表示事务的设置只对该方法有效。
默认情况下,在遇到运行时异常和Error,Spring事务会进行回滚,而遇到非运行时异常Exception则不会回滚。

九、Spring Test单元测试

在利用JUnit4做单元测试的时候,通常要在Before方法中,初始化Spring容器,导致容器被初始化多次。并且通过context.getBean()方法从Spirng容器中获取需要测试的目标Bean,并且还要进行强制类型转换的造型操作,操作繁琐。

@Before  
 public void init() {  
      ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      baseDao = (IBaseDao) context.getBean("baseDao");  
      assertNotNull(baseDao);  
 } 
  • 依赖

          <!--单元测试-->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-test</artifactId>
              <version>5.3.15</version>
          </dependency>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.11</version>
              <scope>test</scope>
          </dependency>
    
  • 使用spring-test后做junit单元测试

    //指定单元测试环境
    @RunWith(SpringJUnit4ClassRunner.class)
    //指定配置文件路径
    @ContextConfiguration(locations = {"/applicationContext.xml","*.xml"})
    public class MaxTest {
      // 自动注入
      @Autowired
      private Max max;
    
      @Test
      public void getMax() throws Exception {
          assertEquals(5,max.getMax());
      }
    

}

# 十、计划任务
applicationContext.xml增加如下配置
```xml
    <!--定时任务注解-->
    <task:annotation-driven/>
@Component
public class xxxTask {
    @Scheduled(cron = "0/5 * * * * ? ") // 间隔5秒执行
    public void xxx() {
        System.out.println("----定时任务执行中-----");
    }
}

十一、Spring工具类

待补充......

十二、Spring与Mybatis整合

  1. pom.xml

     <dependencies>
         <!--Spring核心依赖-->
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
             <version>5.3.14</version>
         </dependency>
         <!--Spring事务依赖-->
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-jdbc</artifactId>
             <version>5.3.14</version>
         </dependency>
         <!--Mybatis依赖-->
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.5.9</version>
         </dependency>
         <!--Mybatis与Spring结合的依赖-->
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis-spring</artifactId>
             <version>2.0.3</version>
         </dependency>
         <!--Mysql驱动依赖-->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>8.0.27</version>
         </dependency>
         <!--druid连接池依赖-->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid</artifactId>
             <version>1.2.4</version>
         </dependency>
    
         <!--单元测试依赖-->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
    
  2. applicationContext.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:context="http://www.springframework.org/schema/context" 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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    
     <!--读取db.properties-->
     <context:property-placeholder location="classpath:db.properties"/>
     <!--配置数据源-->
     <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
         <property name="driverClassName" value="${jdbc.driver}"/>
         <property name="url" value="${jdbc.url}"/>
         <property name="username" value="${jdbc.username}"/>
         <property name="password" value="${jdbc.password}"/>
     </bean>
     <!--事务管理器,依赖于数据源-->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="dataSource"/>
     </bean>
     <!--开启事务注解-->
     <tx:annotation-driven transaction-manager="transactionManager"/>
     <!--配置MyBatis工厂-->
     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
         <!--引用数据源-->
         <property name="dataSource" ref="dataSource"/>
         <!--指定配置文件路径、xml文件目录-->
         <property name="configLocation" value="classpath:mybatis-config.xml"/>
         <property name="mapperLocations" value="classpath:mapper/*.xml"/>
     </bean>
     <!--配置扫描Mybatis的接口所在目录-->
     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
         <property name="basePackage" value="com.example.spring.mapper"/>
     </bean>
    
       <!-- druid -->
     <bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter">
         <property name="slowSqlMillis" value="3000" />
         <property name="logSlowSql" value="true" />
         <property name="mergeSql" value="true" />
     </bean>
     <bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter">
         <property name="dbType" value="mysql" />
     </bean>
    
     <!--自动扫描包下的注解,注册为Spring Bean-->
     <context:component-scan base-package="com.example.spring"/>
    </beans>
    
  3. mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    

    <settings>

    <setting name="logImpl" value="STDOUT_LOGGING"/>

    <setting name="mapUnderscoreToCamelCase" value="true"/>

    <setting name="safeRowBoundsEnabled" value="true"/>

    <setting name="cacheEnabled" value="false" />
    </settings>

    <typeAliases>
    <package name="com.example.model"/>
    </typeAliases>

</configuration>


4. db.properties
   
   ```xml
   jdbc.driver=com.mysql.cj.jdbc.Driver
   jdbc.url=dbc:mysql://localhost:3306/test?characterEncoding=UTF-8
   jdbc.username=root
   jdbc.password=root
  1. 测试

     @Test
     public void testSpring() {
         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
         StudentService studentService = (StudentService) applicationContext.getBean("studentService");
    
         studentService.Student();
    
         System.out.println("hhh");
         System.out.println("test");
     }
    

@Service
public class StudentService {

public void Student() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    StudentMapper studentMapper = (StudentMapper) applicationContext.getBean("studentMapper");

    List<Student> allStudent = studentMapper.findAllStudent();
    System.out.println(allStudent);
}

}

```java
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d518b32] will not be managed by Spring
==>  Preparing: select * from test.student;
==> Parameters: 
<==    Columns: id, name, age
<==        Row: 1, x, 1
<==        Row: 2, f, 2
<==      Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@723e88f9]
[com.example.spring.pojo.Student@7d3d101b, com.example.spring.pojo.Student@30c8681]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容