Spring5

概述

​ Spring是开发java程序的另一种框架

​ 它结合了轻量级的容器和依赖注入功能,提供了一种使用 POJO 进行容器配置和面向切面的编程的简单方法,以及一组用于AOP的模块。

​ 它还提供了对事务管理、对象/关系映射、JavaBeans、JDBC、JMS 和其他技术的支持,从而确保高效开发。

​ Spring主要分为七个模块

  • Spring Core:Spring的核心模块
  • Spring AOP:Spring提供了面向方面编程的功能

​ 面向方面编程(Aspect Orient Programming):实现在不修改源代码的情况下给程序动态统一添加额外功能

  • Spring ORM:对象关系映射,spring除了有自己的jdbc应用之外,还提供了对其他一些orm框架的支持。
  • Spring DAO:提供简单有效的JDBC应用
  • Spring Web:Web程序支持
  • Spring WebMVC:JSP,Servlet支持
  • Spring context:

Spring的Maven依赖如下

<!--spring-webmvc-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!--spring-jdbc-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!--spring注解-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

SpringIoC

控制反转

​ IoC,控制翻转思想,原型可以理解为降低程序主动创建对象的能力,转为被动的接收对象

​

​ 多态性允许你一个接口的方法有多个实现类,例如UserDao接口,可以有若干个UserDaoImpl实现类

​ 然后对于UserServiceImpl,通过创建不同的UserDaoImpl类对象来调用不同的方法

public class UserServiceImpl implements UserService{
    @Override
    public void usermethod() {
        //UserDaoImpl类,还有UserDaoImpl2,UserDaoImpl3......
        UserDao userDao = new UserDaoImpl();
        userDao.UserMethod();
    }
}

​ 想要调用UserDaoImpl2的方法就去实现UserDaoImpl2类,但这样必定要修改源代码,修改源代码就违背了开闭原则,这样做是高耦合的

​ 所以在Service层提供一个set方法,用于设置UserDao为哪个类,以避免程序主动创建对象,这就是IoC的基础思想

public class UserServiceImpl implements UserService{
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void usermethod() {
        userDao.UserMethod();
    }
}

​ 然后对于用户,先调用setUserDao方法确定使用哪个实现类,再去调用该类的执行方法

​ 也就是说,传统的面向对象思想将对象的操作交给服务端,而IoC交给用户

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

IoC容器

​ 控制反转的目的是通过第三方去生成对象,抛弃传统的违背开闭原则的new生成对象

​ 在Spring中,生成对象的是XML文件或注解,从中获取对象的是IoC容器

​ Spring提供的ApplicationContext接口代表Spring IoC容器,接口的实现类通过读取XML文件或注解以获取其中生成的对象

​ 首先先创建一个用于生成对象的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: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">


    <bean id="hello" class="pojo.Hello">
        <property name="str" value="Helloworld"/>
    </bean>

</beans>

​ 在该文件中,每个bean标签代表一个对象,id用于标识对象,class为对象的类

​ property标签用于设置对象的属性,name对应属性名,value为该属性的值

​ 如果该属性为引用类型,value替换为ref,值为另外一个bean的id,代表引用该bean对象

​ 通过这两个标签,就生成了一个简单对象

 Spring通过读取文件创建对象的过程:
1. 配置文件被加载,开始初始化对象
2. 根据class的路径,使用无参构造函数创建该类对象,如果没有无参构造函数会报错
3. 读取property标签,通过该类的set方法来为对象赋值,如果该类没有set方法会报错

​ 如果一定要使用有参构造函数,可以使用constructor-arg标签

    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg  index="0" value="1"/>
        <constructor-arg  index="1" ref="anotherbean"/>
    </bean>

    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg  name="number" value="1"/>
        <constructor-arg  name="AnOtherBean" ref="anotherbean"/>
    </bean>
  • index为参数序号,name为参数名
  • value和ref为该参数值

​ 下面来使用对象

public class Test {
    public static void main(String[] args) {
        //ClassPathXMLApplicationContext对象
        ApplicationContext context = new ClassPathXMLApplicationContext("beans.XML");
        Hello hello=(Hello)context.getBean("hello");
        System.out.println(hello.toString());
    }
}

​ ApplicationContext的实现类ClassPathXMLApplicationContext,读取指定的XML文件,通过getBean方法获取对象。getBean方法传入一个String,值应该为XML文件中配置对象的id

​ 返回的对象类型为Object,XML文件中已知对象的类型,进行强制转换即可

​

SpringXML配置文件

别名标签alias
<bean id="userdaoimpl1" class="Dao.User.UserDaoImpl"/>
<alias name="userdaoimpl1" alias="asdasd"/>

​ 给一个bean起一个别名,调用别名也能调用该bean

  • name:某个bean的id
  • alias:给该bean起的别名
bean
<bean id="userservice" class="Service.User.UserServiceImpl" name="US1,S1">
    <property name="userDao" ref="userdaoimpl1"></property>
</bean>
  • id:bean的唯一标识符
  • class:bean的对象所对应的全限定名,格式为包名+类名
  • name:别名,效果等同于alias,可以取多个别名
import
<import resource="ApplicationContext.XML"></import>

​ 导入其他XML文件,将其中的配置导入到本XML文件中

​ 可以设置一个总XML文件,用于引用其他XML文件,其他XML文件去实现具体业务(类似于策略模式)

依赖注入

​ 依赖注入(DI)是控制反转的一种实现方案,实际上体现为给创建好的对象赋值的方式

  • 依赖:对象的创建依赖于IoC容器

  • 注入:对象的所有属性由IoC容器赋值(注入)

​

依赖注入有以下几种实现方式

基于构造器的依赖注入

​ 就是上面说过的使用constructor-arg标签,通过构造函数来为属性赋值

    <bean id="hello" class="pojo.Hello">
        <!--基础数据类型-->
        <constructor-arg index="0" value="helloworld"></constructor-arg>
        <!--数组-->
        <constructor-arg index="1">
            <array>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </array>
        </constructor-arg>
        <!--引用类型-->
        <constructor-arg index="2" ref="hello2"></constructor-arg>
    </bean>
public class Hello {

    private String str;
    private int[] nums;
    private Hello2 otherhello;
    
	//需要有岑构造函数
    public Hello(int[] nums, String str,Hello2 otherhello) {
        this.nums = nums;
        this.str = str;
        this.otherhello = otherhello;
    }
}
不同数据类型的注入方式

​ 除array标签外,还可以用map标签传入map值,set标签传入set值

<property name="mymap">
    <map>
        <entry key="" value=""></entry>
        <entry key-ref="" value-ref=""></entry>
    </map>
</property>

<property name="myset">
    <set>
        <value>1</value>
        <value>2</value>
    </set>
</property>

​

​ 对于空值,使用null标签

<property name="ThisisaNull">
    <null/>
</property>

​

​ 可以设置properties文件格式

​ 一个props标签为一个properties,prop设置用key获取,值为标签内内容

​ 一般是给对象的Properties类属性赋值

<property name="properties">
    <props>
        <prop key="username">root</prop>
        <prop key="passworld">123456</prop>
    </props>
</property>

基于Setter的依赖注入

​ 也是上面所说的,通过property标签为属性赋值,需要用到set方法

<bean id="hello" class="pojo.Hello">
    <property name="str" value="hellow"></property>
    <property name="nums" >
        <array>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </array>
    </property>
    <property name="otherhello" ref="hello2"></property>
</bean>
package pojo;

public class Hello {
    private String str;
	//get方法可有可无
    public String getStr() {
        return str;
    }
	//set方法一定要有
    public void setStr(String str) {
        this.str = str;//str值为hellow
    }
    //...其余的Get,Set方法省略
}

p空间命名注入和c空间命名注入

<!--p空间命名注入-->
<bean id="hello" class="pojo.Hello" p:str="123" p:otherhello-ref="hello2">
</bean>
<!--c空间命名注入-->
<bean id="hello" class="pojo.Hello" c:str="123" c:otherhello-ref="hello2">
</bean>

​ 使用p,c空间命名注入需要导入p,c命名空间XML约束

​ 通过在bean标签内配置注入,为对象属性赋值

​ 实际上p空间命名注入使用的是set方法,c空间命名注入使用构造函数,只是上面两种方式的另一种形式

Bean Scope

​ BeanScope即bean对象的作用域,这里的作用域有两个方面的意义:1是对象的作用范围,2是对象为单例或原型

​ Spring支持六种Scope

1.singleton

​ singleton为bean的默认作用域,它将对象以单例模式生成,就例如上面我们测试的一样,同一个bean里取出的两个对象是相同的

2.prototype

​ prototype将bean的Scope扩大到任何数量的对象实例,即以原型模式生成对象

​ 原型模式生成的对象,同一个bean里取出的对象就不相同了

3.request

​ 将单个Bean定义的Scope扩大到单个HTTP请求的生命周期。也就是说,每个HTTP请求都有自己的Bean实例,该实例是在单个Bean定义的基础上创建的。只在Web感知的Spring ApplicationContext的上下文中有效。

4.session

​ 将单个Bean定义的Scope扩大到一个HTTPSession的生命周期。只在Web感知的SpringApplicationContext的上下文中有效。

5.applicantion

​ 将单个Bean定义的 Scope 扩大到 ServletContext的生命周期中。只在Web感知的Spring ApplicationContext的上下文中有效。

6.websocket

​ 将单个Bean定义的 Scope 扩大到 WebSocket的生命周期。仅在具有Web感知的 Spring ApplicationContext的上下文中有效。

​ 使用bean标签的scope属性修改作用域

<bean id="hello2" class="pojo.Hello2" scope="prototype">
    <property name="id" value="1" ></property>
</bean>

id为hello2的bean使用prototype作为Scope,从该bean取出的两个对象不相等

Bean自动装配

​ Bean的装配即定义Bean,为其属性添加值

​ Spring中有三种装配方式

  • 在XML文件中显式配置
  • 在java文件中显式配置
  • 隐式的自动装配bean

​ XML文件配置即上面所介绍的,下面来介绍隐式的自动装配bean

​ 自动注入仅针对于为引用类型赋值,它不能给基本数据类型的属性赋值

​ 使用bean标签的autowire属性修改自动装配的方式,提供了三种方式:

  • byname:如果存在id与属性名相同的bean,将该bean装配给该属性

​ 如果没有同名的bean,装配null;如果有同名的bean但类型不相同,会报错

  • bytype:如果存在class与属性类型相同的bean,,将该bean装配给该属性

​ 如果没有同类型的bean,装配null;如果存在两个及以上个同类型的bean,会报错

  • constructor:类似于bytype,但适用于构造函数参数
<bean id="hello2" class="pojo.Hello2" scope="prototype">
    <constructor-arg index="0" value="1"></constructor-arg>
</bean>

<bean id="hello" class="pojo.Hello" scope="prototype" autowire="byType">
    <property name="str" value="Helloworld"/>
</bean>

​ 将id1为hello2的bean以bytype形式给id为hello的bean赋值

​ 由此看来,隐式的自动装配bean并没有显式配置灵活

注解开发

​ 在使用Servlet时,我们可以用XML文件配置映射,也可以用注解配置映射,注解和XML文件都是执行的相同功能

​ 注解和XML文件配置都各有优缺点:注解更加简洁方便;XML文件能不涉及源代码,且配置集中,不用到处去找配置

​ Spring注解和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"
       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/>

    <bean id="hello" class="pojo.Hello"/>
    <bean id="hello2" class="pojo.Hello2"/>
    <bean id="hello234" class="pojo.Hello2"/>

</beans>

​ 并且需要导入Spring-aop包,一般是随着Spring一起导入的。如果注解无法使用,可以看一下是不是少了AOP包

注解形式配置bean

​ 使用注解装配bean并不是使用注解来创建对象,而是类似于自动装配,为bean赋值

​ 我们仍需要在XML文件中配置bean,注解只是为bean赋值

​ 在此之后,我们就可以在具体类中使用注解为bean赋值

@Autowired

​ 给属性或属性对应的set方法加上@Autowired注解,会自动从bean里找出class与属性类相同的对象并为其赋值

public class Hello {
    @Autowired
    private Hello2 hello2;
//    @Autowired 加在这里也一样
    public void setHello2(Hello2 hello2) {
        this.hello2 = hello2;
    }

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

​ 比如上面有class为Hello2的bean,就会把该bean对象赋值给@Autowired下的对象

​ 如果没有会报错

​ 如果有两个以上,会根据byname查找属性名和id相同的bean,有则赋值,没有会报错

​ @Autowired有一个属性required,其代表该属性是否为非空,默认为true

​ @Autowired(required = false)可以修改为false,代表该属性可以为null

@Nullable

​ 携带该注解的属性可以为null

@Qualifier

​ 对于有两个以上,且没有id与属性名相同的情况,可以用@Qualifier来指定使用哪个bean

public class Hello {
    @Autowired
    @Qualifier(value = "hello23")
    private Hello2 hello2;
//    @Autowired 加在这里也一样
    public void setHello2(Hello2 hello2) {
        this.hello2 = hello2;
    }

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

​ value为bean的id

​ 如果输入的id不存在对应的bean,会赋值null

注解创建bean

​ 可以通过@Component,@Scope,@Value几个注解来配置一个bean,不用在XML文件里配置

//@Component注解,将该类标记为一个bean,即<bean id="user" class="pojo.User"/>
//隐式的配置,没有在xml文件里直接配置

//@Scope注解,配置该bean的scope,即<bean id="user" class="pojo.User" scope="prototype"/>
@Component
@Scope("prototype")
public class User {

    //@Value注解,为属性赋值,相当于<property name="name" value="zhangsan"/>
    @Value("zhangsan")
    private String username;

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

    public void show(){
        System.out.println(username);
    }
}

SpringAOP

什么是AOP

​ AOP即面向切面编程:OOP中模块化的关键单位是类,而AOP中模块化的单位是切面

​ AOP从实现形式来看是在不修改源代码的情况下给程序动态添加额外功能: 项目在刚创建完成后每个模块都是相关的,例如Dao,Service,Controller,一层一层互相关联,每层基于另外一层而实现的,可以看成一种''纵向开发''

​ 我修改了Dao层的代码,那必然会影响到其他两层;如果有一层出现了错误,会导致其他两层也无法使用

​ AOP就属于"横向开发",类似于代理模式,通过一个代理为源代码添加新功能,以预防因为修改源代码而产生的错误

QQ截图20241119080444
  • 横切关注点:与业务逻辑无关的工具模块,如日志,缓存,事务等
  • 切面:横切关注点中的具体类
  • 通知:切面中的具体方法
  • 目标:被通知对象
  • 代理:代理类
  • 切入点/连接点:在何处执行

代理模式

​ 有些情况下,客户不能或不该直接访问某个对象,而是需要一个中介来访问它,这个中介即是代理

​ 例如房东和租客,房东只想出租,租客只想租房,那么房屋中介就做了房东的代理,连接房东和租客,并且为房东添加房屋广告等功能

​ 在一个房东和一个租客的情况下可能不明显,但有100个房东和租客,每个房东对象就要放100租客属性,这显然是我们不想发生的,通过一个中介就能将他们集合起来,也更加方便管理

定义:由于某些原因,需要给某对象一个代理,以控制该对象的访问。访问对象不适合或不能直接引用目标对象,代理对象作为访问对象和目标对象的中介

代理模式的实现

​ 详见软件设计模式-结构型模式-代理模式

AOP实现

​ 首先要导入外部库

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

​ AOP的底层为代理模式,所以我们先创建两个代理类

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

​ 除了MethodBeforeAdvice接口外,还有AfterReturningAdvice,顾名思义,他们在代理的方法执行前/执行后再去执行自己的方法

​ 然后ApplicantContext.xml中进行配置

<!--被代理的类-->
<bean id="userservice" class="User.UserServiceimpl"/>
<bean id="log" class="Proxy"/>
<bean id="afterproxy" class="AfterProxy"/>

<aop:config>
    <aop:pointcut id="pointcut" expression="execution(* User.UserServiceimpl.*(..))"/>
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterproxy" pointcut-ref="pointcut"/>
</aop:config>

使用aop:config标签,需要导入aop的命名空间

<beans xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
        http://www.springframework.org/schema/aop 
        https://www.springframework.org/schema/aop/spring-aop.xsd">

​ 在该标签中,pointcut表示切入点,expression属性为切入的位置

​ User.UserServiceimpl.*(..), . *表示UserServiceimpl类中的方法,(..)表示方法的参数

​

​ advisor表示代理类,设置多个代理类的话方法也仅执行一次,并按对应的顺序执行代理类的方法

然后正常进行测试:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userservice");
        userService.adduser();
    }
}

执行结果为

Proxy:User.UserServiceimpl的adduser方法被执行 add user AfterProxy:User.UserServiceimpl的adduser方法被执行

可以看到userService对象的adduser()方法是通过两个代理类执行的

​ aop-config除了上述两个标签外,还存在一个aspect标签,该标签允许我们自定义切面

<bean id="myproxy" class="User.MyProxy"/>
<aop:aspect ref="myproxy">
    <aop:pointcut id="pointcut" expression="execution(* User.UserServiceimpl.*(..))"/>
    <aop:before method="before" pointcut-ref="pointcut"/>
    <aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>

​ 通过before和after标签,确定方法执行前后要调用的方法

public class MyProxy {
    public void before(){
        System.out.println("执行前");
    }
    public void after(){
        System.out.println("执行后");
    }
}

运行结果为

执行前 add user 执行后

注解实现AOP
//标记为切面类
@Aspect
public class MyProxy {

    //标记before
    @Before("execution(* User.UserServiceimpl.*(..))")
    public void before(){
        System.out.println("执行前");
    }

    //标记after
    @After("execution(* User.UserServiceimpl.*(..))")
    public void after(){
        System.out.println("执行后");
    }

    //环绕增强
    @Around("execution(* User.UserServiceimpl.*(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕前");
        Object proceed = pjp.proceed();
        System.out.println("环绕后");
    }
}

Spring-Mybatis

​ 连接Spring和Mybatis,需要导入二者各自的包,以及以下两个包

<!--Spring和Mybatis的连接-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>3.0.4</version>
</dependency>

<!--Spring连接数据库需要-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>6.1.12</version>
</dependency>

​ 在Mybatis官网,存在Spring-Mybatis的使用方法mybatis-spring

​ 首先要创建一个Mybatis项目,在此基础上用Spring来创建对象

​ 在MyBatis中,我们使用MyBatisUnits类来创建SqlSessionFactory和SqlSession对象

​ 在此我们使用Spring来创建这两个对象

<!--DataSource,使用Spring的数据源替换MyBatis的配置-->
<!--使用Spring提供的jdbc,即org.springframework.jdbc.datasource-->
<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?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true"/>
    <property name="username" value="root"/>
    <property name="password" value="xsgg2333"/>
</bean>

<!--SqlSessionFactory对象-->
<bean id="SqlSessionFactory"  class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="datasource"/>
    <property name="configLocation" value="mybatis-config.xml"/>
    <property name="mapperLocations" value="mapper/*.xml"/>
</bean>

<!--SqlSessionTemplate类实际上就是Spring提供的SqlSession对象-->
<bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!--由于SqlSessionTemplate类没有SqlSessionFactory的set方法,所以只能通过构造函数注入-->
    <constructor-arg index="0" ref="SqlSessionFactory"/>
</bean>

常规的MyBatis测试如下

public class UserMapperTest {
    @Test
    public void test() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        System.out.println(userList.get(0));
    }
}

UserMapper由SqlSession来创建,这一步我们还可以通过Spring来替换对象的生成

创建一个UserMapper接口的实现类,该类有一个SqlSessionTemplate对象

public class UserMapperimpl implements UserMapper {
    private SqlSessionTemplate sqlSession;
    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }
    @Override
    public List<User> getUserList() {
        UserMapper mapper=sqlSession.getMapper(UserMapper.class);
        return mapper.getUserList();
    }
}

​ 该类重写了getUserList()方法,在此处完成UserMapper的创建,使得调用者只需完成一步创建,降低耦合度

​ 在Spring中创建一个该类对象即可

<bean id="UserMapper" class="mapper.UserMapperimpl">
    <property name="sqlSession" ref="SqlSession"/>
</bean>

然后测试

@Test
public void test(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper mapper=(UserMapper) context.getBean("UserMapper");
    List<User> userList = mapper.getUserList();

    for (User user : userList) {
        System.out.println(user.toString());
    }

}

​ 总结来看,我们消除了MyBatis中所有主动创建对象的行为,最终我们只需要获取UserMapper对象即可

​ 我们还可以将创建SqlSessionFactory和SqlSession的部分和创建Mapper的部分作为两个文件来分开

​ 创建SqlSessionFactory和SqlSession的部分作为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: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">

        <!--DataSource,使用Spring的数据源替换MyBatis的配置-->
        <!--使用Spring提供的jdbc,即org.springframework.jdbc.datasource-->
        <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?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true"/>
            <property name="username" value="root"/>
            <property name="password" value="xsgg2333"/>
        </bean>

        <!--SqlSessionFactory对象-->
        <bean id="SqlSessionFactory"  class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="datasource"/>
            <property name="configLocation" value="mybatis-config.xml"/>
            <property name="mapperLocations" value="mapper/*.xml"/>
        </bean>

        <!--SqlSessionTemplate类实际上就是Spring提供的SqlSession对象-->
        <bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <!--由于SqlSessionTemplate类没有SqlSessionFactory的set方法,所以只能通过构造函数注入-->
            <constructor-arg index="0" ref="SqlSessionFactory"/>
        </bean>
</beans>

​ 创建Mapper的部分作为ApplicantContext.xml文件,使用import来导入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: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">

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

    <bean id="UserMapper" class="mapper.UserMapperimpl">
        <property name="sqlSession" ref="SqlSession"/>
    </bean>

</beans>

​ Spring-MyBatis相比于MyBatis多了一个接口的实现类,因为MyBatis无法自动创建对象,所以通过该实现类,创建一个SqlSession的set方法,使Spring彻底接管MyBatis的对象创建

​ 如果出现SqlSessionbean创建失败错误,请根据错误日志(一般具体错误在最下面)进行排查,一般是XML文件配置错误导致的

failed to parse config resource: class path xxx.xml问题()

PS:↑治标不治本

​ 新版本允许继承SqlSessionDaoSupport抽象类,向对象改为注入SqlSessionFactory对象,通过getSession()方法获取SqlSession对象,这是另外一种创建UserMapperimpl类的方法

声明式事务

mybatis-spring事务

posted @ 2024-12-11 08:37  顾巧  阅读(24)  评论(0)    收藏  举报