Spring入门学习十二:Spring常用知识点总结

19 篇文章 0 订阅
8 篇文章 0 订阅

Spring总结

1. 关于Spring

官网:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html

Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。目的是为了解决企业开发的复杂性。

1.1 Spring环境搭建

maven中导入依赖,maven仓库地址:https://mvnrepository.com/。这里我们直接导入spring-webmvc的jar,它会自动将一些其他依赖的jar包导入,比如core,context,AOP,beans,expression,等。如果IDEA没有自动导包,则右击项目执行一下maven的Reload Project。

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
    </dependencies>

2. IOC

在没有IOC的程序中,对象的创建与对象间的依赖关系完全在硬编码中,对象的创建由程序自己控制,控制反转之后将对象的创建转移给第三方Spring容器,在程序需要某个对象的地方,这个SpringIOC容器将根据我们的需求自动注入所依赖的对象,程序获取依赖对象的方式反转了。

IOC是Spring框架的核心内容,在实际开发中,我们可以通过XML配置,也可以通过注解,甚至可以零配置实现IOC。我们写完POJO,接口等代码之后,通过XML配置,或者注解,然后SpringIOC容器去读取配置文件或者解析注解,从而将这些类的对象组织存入到IOC容器中,程序要用的时候,IOC容器根据需求自动注入所需的对象。

IOC其实是一种思想的体现,将Bean之间进行解耦。举个例子,我们现在有一个UserDao的接口,然后有好几个实现类,我们在Service层调用Dao的实现类,如果不采用注入的方式,则需要在UserService的实现类里面直接写死调用哪个UserDao的实现类比如

private UserDao UserDaoImpl = new UserDaoImpl3();

每次需求更改的时候,都需要修改代码,违反了开闭原则(对修改关闭,对扩展开放),现在我们换一种方式,部在UserService里面去写死这个实现类,修改代码

private UserDao UserDaoImpl;
public void setUserDaoImpl(UserDao UserDaoImpl){
    this.UserDaoImpl = UserDaoImpl;
}

采用set注入的方式,在需要调用UserDaoImpl的时候,直接通过set方法,注入一个我们需要的UserDao的实现类对象即可。这样,代码耦合性,维护成本将大大降低。

简单点说说一下IOC,就好比我们要炒菜请客,已经买好了食材(类),然后请一个第三方餐厅(IOC)来帮我们做,把我们的食材跟列出来的菜单交给这个餐厅就好了(进行配置)并且把菜做好了(单例模式Singleton),等待客人过来吃饭。客人来了之后,要吃什么菜,直接根据菜单去点菜就行(使用IOC的对象)

3. 依赖注入DI

Dependency Injection。这是SpingIOC容器(Bean的容器,装配了我们所配置的Bean,在我们需要的时候交给我们。)的实现方式。依赖注入的方式主要分为:

3.1 构造器注入
<constructor-arg index="0" ref="sqlSessionFactory"/>
<!-- index:下标注入,name:名字注入(常用), type:类型注入 -->
3.2 set注入【重点掌握】

set注入的前提是配置的Bean当中,每个属性都应该有对应的set方法。下面是每种类型的set注入方式演示

<?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">

    <bean id="address" class="com.pojo.Address">
        <property name="address" value="address"/>
    </bean>
    <!--  各种setter注入演示  -->
    <bean id="student" class="com.pojo.Student">
        <!-- 基本类型注入-->
        <property name="name" value="Clay"/>

        <!-- 引用类型注入,引用其它已经配置好了的bean ref-->
        <property name="address" ref="address"/>

        <!-- 数组 array -->
        <property name="strings">
            <array>
                <value>stringArray1</value>
                <value>stringArray2</value>
                <value>stringArray3</value>
            </array>
        </property>

        <!-- List集合 list -->
        <property name="stringList">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>

        <!-- Set集合 set -->
        <property name="stringSet">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>

        <!-- 空指针 null -->
        <property name="nullPoint">
            <null></null>
        </property>

        <!-- Properties -->
        <property name="properties">
            <null></null>
        </property>

        <!-- Map map -->
        <property name="map">
            <map>
                <entry key="mapKey1" value="mapValue1"></entry>
                <entry key="mapKey2" value="mapValue2"></entry>
                <entry key="mapKey3" value="mapValue3"></entry>
            </map>
        </property>
    </bean>
</beans>

4. Bean的作用域

ScopeDescription
singleton(默认)为每个Spring IoC容器将单个bean定义的作用域限定为单个对象实例。IOC容器的默认作用域,说白了就是,只创建一个实例,整个程序都用这个实例。不建议在多线程中使用。而且在程序解析Spring的配置文件的时候,会为每一个单例作用域Bean都准备好一个对象,即使你没有在程序中调用它
prototype将单个bean定义的作用域限定为任意数量的对象实例。即我们每次在需要这个对象的时候,IOC容器会为我们创建一个新的实例,多线程情况下比单例安全
requestScopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
sessionScopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
applicationScopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocketScopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

5. 自动装配

spring提供了满足bean依赖则自动注入的一种方式,它会在上下文中自动寻找,并给Bean装配属性。

5.1 XML显示配置

在bean标签中有一个属性 autowired,该属性可以实现xml的自动装配

  • byName:寻找上下文跟set方法后面的bean相匹配的值。声明的bean id必须全局唯一且跟自动注入属性中的名字匹配,即id唯一且匹配!
  • byType:查找IOC容器里面查找和自己对象属性类型相同的bean。每个类只能声明一个bean,即class唯一!

用法:

<bean id = "people" class="com.pojo.People" autowire="byName">

除此之外,还有构造器自动装配,但我们重点需要掌握的还是下面的自动装配方法,它也是开发中常用的方式。

5.2 @Autowired

使用注解之前需要导入约束,context,配置注解支持

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation

<?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/>
</beans>

一般在配置文件中注册了的类在其他类的属性需要注入的时候,(@Autowired引用类型的注入)都可以用这个注解,所以这种注解一般是引用类型的注入。如果显示定义了@Autowired的required 属性为false(默认为true),说明这个对象可以为null,通过类型名字 自动装配,当情况复杂的时候,可以用@Qualifier(value = “beanid”)指定唯一一个bean注入。在Spring5之后,多了一个注解@Nullable。某个属性被标记了这个注解,说明这个字段可以被注册为空,类似的。

类似用法:

    @Autowired(required = false)
    Phone phone;//自动注入phone,用在属性上面
  
    Computer computer;
    @Autowired//自动注入Computer,用在set方法上面
    public void setComputer(Computer computer) {
        this.computer = computer;
    }
    @Autowired
    @Qualifier(value = "computer1")//显示的指定我们要取IOC容器里面的bean
    Computer computer1;//	

    @Nullable
    private String name;	

6. 使用注解开发Spring

在Spring4之后,要使用注解开发,必须要保证AOP的包导入了。使用注解开发需要在配置文件里面导入context约束,增加注解支持,并开启注解。关于约束导入以及注解开启参考上面小节的内容

xml比较万能,维护简单方便,使用于很多复杂的场景。

注解(annotation),减少繁琐的xml配置,有一定的局限性,维护相对复杂。

6.1 @Component

使用该注解之前,需要在配置文件中开启组件扫描。

<!--开启组件扫描。扫描指定包下面的所有类,只要有被@Component以及其衍生注解标注的类,都会被注册到IOC容器里面-->
    <context:component-scan base-package="com"/>

被该注解标注的类,将自动装配到SpringIOC容器当中,配合@Autowired,将减少大量的XML配置,实际开发中也大都是这种形式。

实际开发中基本上都是采用MVC模式,所以@Component也多出了几个衍生注解。

  • dao 【@Repository】
  • service【@Service】
  • controller【@Controller】

类似的

/**
 * 这个注解用在Controller层上面。类似与@Component,不过在Controller习惯用这个注解
 */
@Controller
public class UserController {
}
6.2 @Value(“值”)

这个注解用在类的属性或者set方法上,表示该属性被自动注入某个值,作用优点类似@Autowired,只不过@Autowired是引用类型的注入,@Value是基本类型的注入。类似:

    @Value("Clay")
    private String name;
6.3 @Scope

用在类上面。作用域注解,里面的值可以参考官方文档,常用值为单例singleton,原型prototype,类似用法

@scope("prototype")//原型
public void User{
    ...
}

7. 使用java配置Spring

在Spring4之后,推出了一种不用配置文件,而是使用java的方式来配置Spring。类似用法:

package com.utils;

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

/**
 * Configuration:声明该类为Spring的配置文件,而且这个类也被Component注解标注了,会被注册到IOC容器里面
 * Import:标签,可以引用别的配置类,类似import标签,将这写配置类弄成一个
 */
@Configuration
public class AppConfig {

    /**
     * 类似<bean id = "getUser" class = "com.pojo.User">
     *          <property name = "age" value = "16"/>
     *     </bean>
     */
    @Bean
    public User getUser() {
        User user = new User();
        user.setAge("16");
        return user;
    }
}

8. 代理模式

SpringAOP的底层就是代理模式,代理模式是必须要精通的。

代理模式分为:

  • 静态代理
  • 动态代理
    1. 基于接口====jdk动态代理
    2. 基于抽象类====cglib动态代理

关于代理模式,我们可以举一个简单的例子。在我们现实生活中,去租房子,一般是无法找到房东的,而房东也很难联系到需要租房子的人,所以出现了这么一个角色,房屋中介(代理)。房东将房子交给中介,我们直接从中介手里租房子,在我们眼里,中介就等同于房东了,我们的需求直接通过中介就可以实现。而中介跟房东都有一个共同的行为,就是出租房子(可以用一个接口约束)。我们来进行一下角色分析

  • 抽象角色:一般会使用接口或者抽象类来解决,主要用于约束一些行为
  • 真是角色:被代理的角色(房东)
  • 代理角色:代理真是角色(中介),代理真是角色后,我们一般会进行一些附属操作。***【不进行附属操作,那么代理模式将毫无意义,说白了,代理模式就是,我们想要给真实角色增加一些功能业务,但是又不好去直接修改原有代码,在公司开发中,改错了,又改不回来,那么gg了。代理模式,就是想办法,去获取真实角色的所有功能,然后增加我们想要的功能,一般在java中获取一个类的所有允许访问的功能(业务方法),常用方式就是继承,以及声明一个公开的接口,让这个接口去约束真实角色与代理角色之间的功能业务】***
  • 客户:我,访问代理角色的人。
8.1 静态代理

优点:

  • 使真实角色的操作更加纯粹,不去关注一些公共业务
  • 公共业务交给代理角色,实现业务的分工
  • 公共业务发生扩展的时候,方便管理

缺点:

  • 一个真实角色便会产生一个代理角色,代码量翻倍,开发效率变低。
8.2 动态代理

动态代理说白了,就是为了解决静态代理的缺点:一个真实角色便会产生一个代理角色,代码量翻倍,开发效率变低。而弄出来的一种东西,我们写好一个生成代理对象的模板程序,想要什么真实角色对应的代理角色,直接将真实角色丢给这个模板(模板中可以添加相应的业务代码),然后这么模板自动丢给我们一个代理角色。代理模式的底层是反射

关于JDK动态代理,则不得不了解下面两个东西,这两个东西都是java反射包之下的。

8.2.1 Proxy

这个类是提供了一个获取代理角色的方法newProxyInstance,这个方法会动态生成一个代理类$Proxy,这个动态生成的类实现了真实角色的所有接口,并继承了Proxy。

public static Object newProxyInstance(
	ClassLoader loader,//真实角色的类加载器 来定义这个返回的代理类的类型,。<?>[] interfaces,//真实对象实现的了的接口
    InvocationHandler h//实现了InvocationHandler接口的类,
)
8.2.2 InvocationHandler
invoke(
    Object proxy, //动态生成的代理角色
    Method method, //真实角色所执行的方法
    Object[] args //执行方法的参数
) throws Throwable

这是一个接口,而且这个接口只有一个方法,当调用newProxyInstance获取到动态生成的代理对象之后($Proxy)之后,通过这个这个代理对象执行真实对象的方法,会自动将这个方法分配到invoke方法上执行。要了解这个类是怎么将执行的方法分配到invoke方法上执行的,我们除了需要了解反射机制之外,还需要了解一下这个动态生成的类是什么样子,这里就不赘述反射的机制了,直接来谈谈&Proxy。

****``$Proxy继承自Proxy,而且这类只有一个构造函数,就是给newProxyInstance的第三个参数赋值(实现了InvocationHandler接口的实例,而且是调用了它的父类,Proxy中的构造方法)赋值,由于这个这类自动实现了真实对象的所有接口,所以它自然而然就实现了这些接口的所有方法,而且它的属性形式一般为******``

  private static Method m1;//对应equals方法
  private static Method m2//对应toString()
  private static Method m3//对应真实对象的接口中的某一个方法
  //....一大堆的方法所对应的属性
  private static Method m0;//对应m0

****可以看出来,它的属性都是一些Method的对象,一般真实对象的接口中有几个方法,它就会有几个这种属性,除此之外还多了三个Method对象(hashCode(),toString(),equals())。假设在真实对象的接口中有一个方法为getAllUser();。那么这个动态生成的代理角色,则会如此实现这个方法:******``

public final String getAllUser(){
    try{
        /**这里我们不知道getAllUser()方法对应的Method属性是m几,我们假设是m3。这里就是自动将我们所执行的方法
        分配到invoke上执行的关键,我们直接将这个方法对象丢给了invoke去执行,除了执行真实对象的方法之外,还可以执行我们在invoke方法中添加的业务。在实现invoke的地方(我们继承InvocationHandler接口并实现这个方法的地方)则可以实现*/
      return (String)this.h.invoke(this, m3, null);
    }
    catch (Error|RuntimeException localError){
      throw localError;
    }
    catch (Throwable localThrowable){
      throw new UndeclaredThrowableException(localThrowable);
    }
}

这里演示一下InvocationHandler接口实现的思路:

public class ProxyInvocationHandler implements InvocationHandler {
    /**
     * 处理真实对象,并返回结果
     * @param proxy 动态生成的代理对象
     * @param method 这是一个反射对象,主要是去执行method.invoke()
     * @param args 参数集,这些参数丢入invoke里面去执行
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        /**
         * 还可以做一些其他业务比如日志
         */
        log(method.getName());
        Object invoke = method.invoke(object, args);
        return invoke;
    }

    public void log(String msg) {
        System.out.println("执行了" + msg + "方法");
    }
}

9. AOP

AOP(Aspect Oriented Programing):面向切面编程。

9.1 关于AOP

在这里插入图片描述

在我们的开发过程中,基本上都是采用的上面的纵向开发的模式,从dao一直到前端。假如,由于业务逐渐加大,程序出了bug,我们一般都是不会直接去修改原有的业务代码的,风险比较好,万一改错了,还改不会回来就gg了,比如现在bug出现在了service,我们需要用日志去打印排错,直接代理这个service就行了,**横切**进去,即可达到查看日志排错的目的。这就是AOP的基本概念。

说白了AOP还是动态代理的一种运用,AOP是OOP的延续,而不是代替。即获取原有业务类的功能,添加我们所需要的功能,减少修改的原有业务类的风险。

9.2 关于SpringAOP的一些名字概念

国外人就是喜欢搞这么一些绕口的概念。

  • 横切关注点:即与业务逻辑无关的,但是我们需要关注的部分,比如我们要给原有的业务类增加了一个日志功能,这个日志功能就是横切关注点,还有一些,比如事务,缓存,安全等等。
  • 切面(Aspect):横切关注点被模板化的一个对象。即,一个类,比如我们将所关注的日志功能,抽取出来成一个类,这个log类就是切面。
  • 通知(Advice):切面要完成的工作。即,切面类中的方法,比如,抽取出来的Log类中的log方法
  • 目标(Target):被通知的对象。即业务类
  • 代理(Proxy):向目标对象应用通知之后创建的对象,即生成的动态代理角色。
  • 切入点(PointCut):切面通知执行的地方。即你在业务类中某个方法加上日志功能,这个方法就是切入点
  • 连接点(JointPoint):与切入点匹配的执行点。即你要业务类这个方法的哪里执行,前面,后面,还是前后。
9.3 Spring中5种通知类型
  1. 前置通知:方法前。
  2. 后置通知:方法后。
  3. 环绕通知:方法前后。
  4. 异常抛出通知:方法抛出异常
  5. 引介通知:类中增加新的方法属性
9.4 实现AOP所需要导入的依赖

除了上面已经导入的AOP,等依赖之外,还需要导入一个新的依赖

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
9.5 AOP所需要导入的约束
<?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">
    <!--开启注解-->
    <context:annotation-config/>
    <!--开启组件扫描。扫描指定包下面的所有类,只要有被@Component以及其衍生注解标注的类,都会被注册到IOC容器里面
        注解注册的bean都是小写开头。
    -->
    <context:component-scan base-package="com"/>


    <!--配置AOP,需要导入AOP的约束-->
    <!-- 方式一 -->
    <aop:config>
        <!--切入点 expression:表达式。execution:需要执行的位置!
 		第一个*:返回类型,com.service.impl.UserServiceImpl.。 *(..):方法跟参数-->
        <aop:pointcut id="pointCut" expression="execution(* com.service.impl.UserServiceImpl.*(..))"/>       
        <!--执行增强-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointCut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut"/>
    </aop:config>
    
    
    <!-- 方式二 -->
    <aop:config>
<!--        自定义的切面。ref 要引用的类-->
        <aop:aspect ref="diyPointCut">
            <!--        切入点-->
            <aop:pointcut id="point" expression="execution(* com.service.impl.UserServiceImpl.*(..))"/>
            <!--        通知 method:切面类中的方法 pointcut-ref:切入点 -->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
    
        <!--    方式三:开启AOP的注解支持 。默认采用JDK动态代理。proxy-target-class="true":采用cglib -->
        <aop:aspectj-autoproxy />
</beans>
9.5 AOP实现方式一,使用Spring的AOP接口
  • 后置通知:实现AfterReturningAdvice,配置方式参考9.4 advice-ref="beforeLog"这个是实现AfterReturningAdvice的类名,这个类需要注入到SpringIOC容器里面
  • 前置通知:实现MethodBeforeAdvice。
  • 其他通知方法类似
9.6 自定义一个切面类。

实现方式参考9.4

9.7 注解实现AOP

注意注解实现需要开启aop的注解支持

 <!--    方式三:开启AOP的注解支持 。默认采用JDK动态代理。proxy-target-class="true":采用cglib -->
        <aop:aspectj-autoproxy />

类似用法:

package com.div;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//方式三:使用注解的方式来实现AOP功能
@Component
@Aspect//标注这个类是一个切面
public class AnnoPointCut {

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

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

    /**
     * 在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
     */
    @Around(value= "execution(* com.service.impl.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前");

        //执行方法
        Object proceed = proceedingJoinPoint.proceed();

        System.out.println("环绕后");
    }
}

10. Spring整合Mybatis

10.1 需要导入的依赖

除了Spring跟Mybatis相关jar包之外,还需要导入

<!-- spring整合mybatis的包 -->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.1</version>
        </dependency>
        
		<!-- spring连接jdbc的包 -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
10.2 整合方式一
<?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">

<!--    类似这种配置基本是死的,要用直接拷贝,然后修改一下数据源,注册的mapper等即可-->
    <!--DataSource:数据源,使用Spring数据源替换Mybaits的配置。
    我们这里使用Spring的JDBC
    这个bean就相当于Mybaits配置文件中的environments中的配置-->
    <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=UTF-8&amp;serverTimezone=GMT%2B8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--        因为获取sqlSessionFactory对象,需要sqlSessionFactoryBuilder获取。注入数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--绑定mybatis配置文件,-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>


    <!--配置sqlSession 这里即是我们使用的myabtis-spring包中的SqlSessionTemplate
    方式二中,这里可以省略,直接通过继承一个SqlSessionDaoSupport类
    通过这个类的getSession()方法就能获得一个SqlSessionTemplate实例(SqlSession),
    但是SqlSessionDaoSupport需要注入一个sqlSessionFactory,直接注入到它的子类即可-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能使用构造器注入,因为它没有set方法,
        因为获得SqlSession需要通过sqlSessionFactory.openSqlSession(),
        所以我们在这里注入一个sqlSessionFactory对象-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

</beans>

在上面的配中,

我们首先配置了一个数据源的Bean。org.springframework.jdbc.datasource.DriverManagerDataSource。

这里面取代了Mybatis的配置文件中的environments中的设置,即配置了数据库连接地址,密码,驱动等。然后将这个Bean注入到了一个org.mybatis.spring.SqlSessionFactoryBean的Bean中,这个Bean中我们还通过classpath:的方式绑定了Mybatis的原生配置文件(这个配置文件将省去environments的配置,除此之外,想省去的配置的都可以在这个Bean中配置,比如映射器的绑定,别名等等,但一般可以不用这么做,然后Mybatis的配置文件看起来更像一个配置文件),然后将org.mybatis.spring.SqlSessionFactoryBean注入到一个org.mybatis.spring.SqlSessionTemplate,这个东西就相当于Mybatis中的sqlSession,同过这个东西可以获取相应的映射器,执行我们的sql。

注意,由于是Spring整合Mybatis,为了然后IOC容器更加方便管理我们的DAO接口,一般需要为DAO接口添加一个实现类,在这个实现类中注入org.mybatis.spring.SqlSessionTemplate,通过这个获取映射器执行sql。

10.3 整合方式二

在DAO接口的实现类上,我们可以继承一个SqlSessionDaoSupport,这个类提供了一个getSqlSession()方法,可以获取sqlSession。因为,这个SqlSessionDaoSupport要获取SqlSession,所以我们需要为这个类注入一个SqlSessionFactory或者SqlSession实例(不然它从鬼地方去获取sqlSession),常常采用的方式,是直接注入到这个Dao接口的实现类中。类似用法:

package com.dao;

import com.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 将这个类配置到SpringIOC,
 */
public class UserDaoImpl2 extends SqlSessionDaoSupport implements UserDao {


    public List<User> getAllUser() {
        SqlSession sqlSession = getSqlSession();
        return sqlSession.getMapper(UserDao.class).getAllUser();
    }
}

11. Spring声明式事务

11.1 什么是事务
  • 把一组业务当成一个业务来执行,要么都成功,要么都失败,如果执行到一半遇到失败,那么事务将会回滚
  • 事务及其重要,不容马虎,设计到数据一致性问题。
  • 确保数据的完整性跟一致性
  • 事务的的ACID原则
    1. 原子性
    2. 一致性
    3. 隔离性:多个业务可能操作同一个资源,防止数据损坏。
    4. 持久性:事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中。
11.2 类似配置方法
<?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--   
 这
里
整
合
Mybatis
-->

<!--    配置声明式事务,然后注入到sqlSessionFactory-->
    <bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    结合AOP,实现事务的织入 需要导入tx 和aop的约束-->
    <!--配置事务的类-->
    <tx:advice id="txAdvice" transaction-manager="transaction">
        <!--给那些方法配置事务
        配置事务的传播特性 propagation,默认REQUIRED ,也是最常见的选择
        支持当前事务,如果当前没有,则新建一个,-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="update"/>
            <tx:method name="delete"/>
            <tx:method name="query" read-only="true"/>
            <!-- 所有方法 -->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--    配置事务切入-->
    <aop:config>
        <!-- 切入点为Dao下面的所有类的所有方法, 即dao包下面的所有方法都会被织入上面的事务 -->
        <aop:pointcut id="txPointCut" expression="execution(* com.dao.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>

声明式事务利用了SpringAOP,将事务横切到我们所需要添加的地方,需要导入tx和aop的约束

  • 先采用官方的方式,声明一个org.springframework.jdbc.datasource.DataSourceTransactionManager的Bean,
  • 然后在这里Bean里面注入一个dataSource
  • 然后使用tx:advice去配置事务的传播方式, transaction-manager=“transaction”。事务的管理方式就是上面声明好的Bean
  • 然后将配置好的事务横切到需要添加事务的地方。比如Dao下面的所有方法。默认事务是REQUIRED
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值