目 录CONTENT

文章目录

Spring 学习笔记

Nicholas
2024-05-14 / 0 评论 / 1 点赞 / 10 阅读 / 32456 字

Spring学习笔记

Spring官网】https://spring.io/

Github链接】https://github.com/spring-projects/spring-framework

Spring官方文档】https://docs.spring.io/spring-framework/reference/

Spring官方API文档】https://docs.spring.io/spring-framework/docs/current/javadoc-api/

【中文文档】https://springdoc.cn/spring/index.html

一、Spring简介

1.1、优点

Spring的优点:

  • 开源免费
  • 轻量级、非侵入式的框架
  • 控制反转loC,面向切面Aop
  • 对事务的支持,对框架的支持

1.2、核心组成

Spring的七大模块。

20240514124400_633913.png

1.3、控制反转IoC

IoCInversion of Control,控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用。

为什么叫控制反转?

  • 控制:指的是对象创建(实例化、管理)的权力。传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。
  • 反转:控制权交给外部环境(Spring 框架、IoC 容器)。程序本身不创建对象,而变成被动的接收对象。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection,DI)。

依赖注入:就是利用set方法来进行注入的。

一句话概括IoC:对象由 Spring 来创建,管理,装配!

20240514124400_667942.png

二、第一个Spring程序

2.1、依赖导入

maven依赖导入。

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.1.4</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<!--
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>6.1.4</version>
</dependency>
-->

2.2、pojo实体类

放在src/main/java路径下。

package com.wzq.pojo;

public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

2.3、配置文件

放在src/main/resources/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
		https://www.springframework.org/schema/beans/spring-beans.xsd">
	
    <!-- 在 Spring 中,使用 Bean 代指被 IoC 容器所管理的对象 -->
    <bean id="hello" class="com.wzq.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>

</beans>

2.4、测试类

放在src/test/java路径下。

import com.wzq.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    public static void main(String[] args) {
        // 获取 Spring 的上下文对象(此时容器中管理的所有对象被创建出来)
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        
        // 对象现在都在 Spring 中管理了,使用时直接取出来即可
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());   // Hello{str='Spring'}
    }
}

OK,到了现在,我们就不用再在程序中改动了,要实现不同的操作,只需要在xml配置文件中进行修改。

例如,想要输出Hello{str='Little'},只需要将xml中修改为<property name="str" value="Spring"/>

三、Spring配置

3.1、别名

使用以下语法配置别名(和<bean>标签同级)。

<!-- 别名(如果添加了别名,我们也可以使用别名获取到这个对象) -->
<alias name="user" a1ias="userNew" />

3.2、bean的配置

<!-- 
id: bean 的唯一标识符,相当于对象名
class: bean 对象所对应的全限定名: 包名 + 类名
name: 也是别名,而且 name 可以同时取多个别名
-->
<bean id="userT" class="com.wzq.pojo.userT" name="user2 u2 u3 u4">
	<property name="name" value="Little"/>
</bean>

3.3、import

一般用于团队开发使用,可以将多个配置文件,导入合并为一个。

假设项目中有多个人进行开发,他们负责不同的类的开发,并注册在不同的bean配置文件中。可以利用import将所有人的beans.xml合并为一个总的。

<!-- applicationContext.xml -->
<import resource="beans.xm1" />
<import resource="beans2.xml" />
<import resource="beans3.xm1" />

使用的时候,直接使用总的配置文件即可。

四、依赖注入DI(重点)

对于依赖注入的理解:

  • 依赖:bean对象的创建依赖于容器!
  • 注入:bean对象中的所有属性,由容器来注入!

4.1、基于构造器的依赖注入

IoC默认使用无参构造函数创建对象。

也可以配置使用有参构造函数创建对象 官网文档链接

<!-- 方式一 使用下标 -->
<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg index="0" value="7500000"/>
	<constructor-arg index="1" value="42"/>
</bean>

<!-- 方式二 使用参数类型 -->
<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg type="int" value="7500000"/>
	<constructor-arg type="java.lang.String" value="42"/>
</bean>

<!-- 方式三 使用参数名(常用!) -->
<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg name="years" value="7500000"/>
	<constructor-arg name="ultimateAnswer" value="42"/>
</bean>

如果参数是引用的对象,如下情况。

package x.y;

public class ThingOne {
	public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
		// ...
	}
}

可以使用下面的方式来实现。

<beans>
	<bean id="beanOne" class="x.y.ThingOne">
		<constructor-arg ref="beanTwo"/>
		<constructor-arg ref="beanThree"/>
	</bean>

	<bean id="beanTwo" class="x.y.ThingTwo"/>
	<bean id="beanThree" class="x.y.ThingThree"/>
</beans>

4.2、基于Setter的依赖注入【重要!】

以下给出了各种类型的属性的注入方式。

<bean id="address" class="com.wzq.pojo.Address">
    <property name="address" value="西安" />
</bean>

<bean id="student" class="com.wzq.pojo.Student">
    <!-- common value DI: value -->
    <property name="name" value="WZQ"/>

    <!-- Bean DI: ref -->
    <property name="address" ref="address"/>

    <!-- array DI: array -->
    <property name="books">
        <array>
            <value>红楼梦</value>
            <value>西游记</value>
            <value>水浒传</value>
            <value>三国演义</value>
        </array>
    </property>

    <!-- List -->
    <property name="hobbys">
        <list>
            <value>听歌</value>
            <value>敲代码</value>
            <value>看电影</value>
        </list>
    </property>

    <!-- Map -->
    <property name="card">
        <map>
            <entry key="身份证" value="1112223333"/>
            <entry key="银行卡" value="1232323232"/>
        </map>
    </property>

    <!-- Set -->
    <property name="games">
        <set>
            <value>LOL</value>
            <value>COC</value>
            <value>BOB</value>
        </set>
    </property>

    <!-- null -->
    <property name="wife">
        <null/>
    </property>

    <!-- Properties  -->
    <property name="info">
        <props>
            <prop key="driver">0918</prop>
            <prop key="url">男</prop>
            <prop key="username">小明</prop>
            <prop key="password">123456</prop>
        </props>
    </property>
</bean>

4.3、P命名空间和C命名空间

这两者都是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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- p (property) namespace DI, can directly DI properties' value -->
    <bean id="user" class="com.wzq.pojo.User" p:name="WZQ" p:age="24"/>

    <!-- c (constructor) namespace DI, can DI by constructor -->
    <bean id="user2" class="com.wzq.pojo.User" c:name="QZW" c:age="23"/>
</beans>

五、Bean的作用域

官方文档链接

20240514124400_651927.png

六、Bean的自动装配

自动装配是Spring满足bean依赖一种方式。Spring会在上下文中自动寻找,并自动给bean装配属性。

<bean id="cat" class="wzq.dao.pojo.Cat"/>
<bean id="dog" class="wzq.dao.pojo.Dog"/>

<!-- 
byName: could automatically find within the container (beans.xml), which has the same Name as Set function.
byType: could automatically find within the container (beans.xml), which has the same Type as Attribute type.
-->
<bean id="people" class="wzq.dao.pojo.People" autowire="byName">
    <property name="name" value="WZQ"/>
</bean>

注意:

  • 使用byName时:需要保证所有beanid唯一,并且需要和自动注入的属性的set方法一致。
  • 使用byType的:需要保证所有beanclass唯一,并且需要和自动注入的属性的类型一致。

七、使用注解

官方文档

使用注解前,需要在xml文件中配置context的支持。

<?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
                           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:annotation-config/>
    <context:component-scan base-package="com.wzq"/>

</beans>

【注】上述的component-scan标签。配置这个标签后,spring就会去自动扫描base-package对应的路径或者该路径的子包下面的java文件,如果扫描到文件中带有@Service, @Component ,@Repository, @Controller等这些注解的类,则把这些类注册为bean

7.1、配置bean的注解

@Component注解:组件,用在类上,说明这个类被Spring管理了,就是bean。有几个衍生的注解(功能相同):

  • @Repository注解:用在dao层的类上。
  • @Service注解:用在service层的类上。
  • @Controller注解:用在controller层的类上。

@Value注解:用在属性或相应的setter方法上,用于注入值。

@Scope注解:用在类上,标识作用域。

package com.wzq.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

// @Component 等价于 <bean id="user" class="com.wzq.pojo.User" />
@Component
@Scope("singleton")
public class User {
    @Value("wzq")
    public String name;
}

7.2、自动装配的注解

官方文档

@Autowired注解:实现自动装配。可以在属性上使用,也可以在相应的setter方法上使用。

【注】使用@Autowired注解在属性上后,甚至可以不需要写setter方法。

package wzq.dao.pojo;
import org.springframework.beans.factory.annotation.Autowired;

public class People {

    private String name;
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;

	......
}

【注】采用注解实现自动装配时,先采取byType的策略(@Autowired),如果找到多个再通过byName的方式最终确定其中一个(@Qualifier)。

7.3、配置相关注解

官方文档

package com.wzq.config;

import com.wzq.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration  // 配置
@ComponentScan("com.wzq.pojo")   // 扫描包
@Import(WzqConfig2.class)        // 导入其他配置类
public class WzqConfig {

    @Bean
    public User user(){
        return new User();
    }
}

测试类代码如下:

import com.wzq.config.WzqConfig;
import com.wzq.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        // 使用 AnnotationConfigApplicationContext 进行加载s
        ApplicationContext context = new AnnotationConfigApplicationContext(WzqConfig.class);
        User getUser = (User) context.getBean("user");
        System.out.println(getUser.getName());
    }
}

八、AOP

8.1、动态代理模式(重点)

接口方法。

package com.wzq.demo03;

public interface Rent {
    public void rent();
}

需要被代理的类。

package com.wzq.demo03;

public class Host implements Rent {

    public void rent() {
        System.out.println("房东要出租房子!");
    }
}

代理调用处理程序。

package com.wzq.demo03;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 这个类用于自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {

    // 被代理的接口
    private Rent rent;
    public void setRent(Rent rent) {
        this.rent = rent;
    }

    // 生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                rent.getClass().getInterfaces(), this);
    }

    // 处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        // 动态代理的本质,就是使用反射机制实现
        Object result = method.invoke(rent, args);
        fee();
        return result;
    }

    public void seeHouse(){
        System.out.println("中介带你看房子");
    }

    public void fee(){
        System.out.println("收中介费");
    }
}

调用代理的类。

package com.wzq.demo03;

public class Client {
    public static void main(String[] args) {
        // 真实角色
        Host host = new Host();

        // 代理角色,通过处理类生成
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        // 通过调用程序处理角色来处理我们要调用的接口对象
        pih.setRent(host);
        // proxy 是动态生成的代理
        Rent proxy = (Rent) pih.getProxy();

        proxy.rent();
    }
}

8.2、AOP概述

AOPAspect Oriented Programming,面向切面编程),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOPOOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

20240514124400_698429.png

8.3、AOPSpring中的作用

提供声明式事务;允许用户自定义切面。

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等....
  • 切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知执行的“地点"的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。
20240514124400_713653.png

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice

20240514124400_745118.png

AOP在不改变原有代码的情况下,去增加新的功能。

8.4、使用Spring实现AOP

首先需要导入一个织入包。

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

8.4.1、环境搭建

配置文件。

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

    <!-- register bean -->
    <bean id="userService" class="com.wzq.service.UserServiceImpl"/>

    <!-- Method_01 : Use Origin Spring API Interface -->
    <bean id="log" class="com.wzq.log.Log"/>
    <bean id="afterLog" class="com.wzq.log.AfterLog"/>
    <!-- config aop -->
    <aop:config>
        <!--  PointCut expression execution(the position you want to execute) -->
        <aop:pointcut id="pointcut" expression="execution(* com.wzq.service.UserServiceImpl.*(..))"/>

        <!-- Execute advisor add -->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>-->

    <!-- Method_02 : Use DIY Class -->
    <bean id="diy" class="com.wzq.diy.DiyPointCut"/>
    <aop:config>
        <!-- diy aspect, ref: the class needs to be used -->
        <aop:aspect ref="diy">
            <!-- pointcut -->
            <aop:pointcut id="point" expression="execution(* com.wzq.service.UserServiceImpl.*(..))"/>
            <!-- advice -->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

    <!-- Method_03 : Use DIY Class -->
    <bean id="annotationPointCut" class="com.wzq.diy.AnnotationPointCut"/>
    <!-- open annotation support -->
    <aop:aspectj-autoproxy/>
</beans>

测试类。

import com.wzq.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 动态代理代理的是接口
        UserService userService = (UserService) context.getBean("userService");
        userService.delete();
    }
}

8.4.1、通过Spring API实现

Log类,用于在方法执行前输出日志。

package com.wzq.log;

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {

    // method: 要执行的目标对象的方法
    // args: 参数
    // target: 目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
    }
}

AfterLog类,用于在方法执行后输出日志。

package com.wzq.log;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {

    // returnValue: 返回值
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了" + method.getName() + "方法,返回结果为: " + returnValue);
    }
}

8.4.2、自定义类实现AOP

自定义类,在方法执行前和执行后输出日志。

package com.wzq.diy;

public class DiyPointCut {

    public void before(){
        System.out.println("=================方法执行前================");
    }

    public void after(){
        System.out.println("=================方法执行后================");
    }
}

8.4.3、注解实现AOP

使用注解标注。

package com.wzq.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect   // 标注这个类是一个切面
public class AnnotationPointCut {

    @Before("execution(* com.wzq.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("=============方法执行前============");
    }

    @After("execution(* com.wzq.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("=============方法执行后============");
    }

    @Around("execution(* com.wzq.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");

        Signature signature = jp.getSignature();
        System.out.println("signature: " + signature);

        Object proceed = jp.proceed();
        System.out.println("环绕后");

        System.out.println(proceed);
    }
}

九、整合Mybatis(重点)

Mybatis-Spring Github链接】https://github.com/mybatis/spring

9.1、导入相关依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

<!-- use Spring to connect database, need Spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.13</version>
</dependency>

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.2</version>
</dependency>

9.2、配置文件

mybatis配置文件(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>
    <typeAliases>
        <package name="com.wzq.pojo"/>
    </typeAliases>

</configuration>

spring用于连接mybatis的配置文件(spring-dao.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: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">

    <!-- DataSource: using Spring's datasource to replace Mybatis's Configuration c3p0 dbcp druid
        Here we use JDBC which is supplied by Spring -->
    <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/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="132402"/>
    </bean>

    <!-- sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <!-- bound Mybatis configuration file -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/wzq/mapper/*.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- can only use constructor to DI, because it has no Set Method -->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

</beans>

spring总体配置文件(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: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">

    <import resource="spring-dao.xml"/>

    <bean id="userMapper" class="com.wzq.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

    <bean id="userMapper2" class="com.wzq.mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

9.3、实现类

实现类(UserMapperImpl.java)。

package com.wzq.mapper;

import com.wzq.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper{

    // 原来所有操作都通过 sqlSession 来执行,现在都使用 sqlSessionTemplate
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

// 【注】也可以简化为如下版本
package com.wzq.mapper;

import com.wzq.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    public List<User> selectUser() {
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}

9.4、测试类

测试类。

import com.wzq.mapper.UserMapper;
import com.wzq.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

public class MyTest {

    @Test
    public void test() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }
    }
}

十、声明式事务

spring-dao.xml文件中,新增事务的配置(利用AOP的特性)。

<!-- http://www.springframework.org/schema/tx
     https://www.springframework.org/schema/tx/spring-tx.xsd
-->
 
<!-- Config announced Transaction -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- <constructor-arg ref="dataSource" />-->
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- Combine AOP to realize Transaction's import -->
<!-- Config Transaction's advice -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!-- config transactions for which method -->
    <!-- config transactions' propagation feature -->
    <tx:attributes>
        <tx:method name="add" propagation="REQUIRED"/>
        <tx:method name="delete"/>
        <tx:method name="update"/>
        <tx:method name="query" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!-- Config transactions' pointCut -->
<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* com.wzq.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
1

评论区