文章目录

  • 1 Spring
  • 1.1 简介
  • 1.2 优点
  • 1.3 组成
  • 1.4 拓展
  • 2 IOC理论推导
  • 3 HelloSpring
  • 4 IOC创建对象的方式
  • 5 Spring配置
  • 6 依赖注入(DI,Dependency Injection)
  • 6.1 构造器注入
  • 6.2 Set方式注入【重点】
  • 6.3 拓展方式注入
  • 6.4 bean的作用域
  • 7 Bean的自动装配
  • 8 使用注解开发
  • 9 用java方式配置Spring
  • 10 代理模式
  • 11 面向切面编程AOP
  • 12 整合MyBatis
  • 13 Spring中的事务管理


1 Spring

1.1 简介

Spring:春天

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。2002年,首次推出了Spring框架的雏形:interface 21框架;2004年2月24号发布Spring1.0

Rod Johnson:Spring Framework创始人,著名作者。他是悉尼大学的博士,他的专业是音乐学,“轮子理论”,也即“不要重复发明轮子”

Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架

SSH:Struct2 + Spring + Hibernate

SSM:SpringMVC + Spring + Mybatis

官网:https://spring.io/

官方下载地址:https://repo.spring.io/release/org/springframework/spring/

github:https://github.com/spring-projects/spring-framework

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

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

1.2 优点

  • Spring是一个开源的免费的框架(容器)!
  • Spring是一个轻量级的,非入侵式的框架
  • 控制反转(IOC),面向切面编程(AOP)
  • 支持事务的处理,对框架整合的支持

总结一个句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编(AOP)的框架

1.3 组成

spring ioc本质分析探究 狂神说 狂神说java spring笔记_xml

1.4 拓展

在Spring的官网有介绍:现代化的Java开发!就是基于Spring的开发

spring ioc本质分析探究 狂神说 狂神说java spring笔记_spring_02

  • Spring Boot
  • 一个快速开发的脚手架
  • 基于SpringBoot可以快速的开发的单个微服务
  • 约定大于配置
  • SpringCloud
  • SpringCloud是基于SpringBoot实现的

大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!

Spring弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称:”配置地狱“!

2 IOC理论推导

  1. UserDao接口
  2. UserDaoImpl实现类
  3. UserService业务接口
  4. UserServiceImpl业务实现类

在之前的业务中,用户的需求可能会影响原来的代码,需要根据用户的需求去修改原代码。如果程序代码量十分大,修改一次的成本代价十分昂贵

原先:

public class UserServiceImpl implements UserService{

    //需要随着调用功能的变化,改变new的对象
    private UserDao userDao = new UserDaoMysqlImpl();

    @Override
    public void getUser() {
        userDao.getUser();
    }
}

现在(使用一个Set接口实现,发生了革命性的变化):

public class UserServiceImpl implements UserService{

    //接口的思想
    private UserDao userDao;

    //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        userDao.getUser();
    }
}
  • 之前,程序是主动创建对象!控制权在程序猿手上!
  • 使用了set注入后,程序不再具有主动性,而是变成了被动创建。

这种思想,从本质上解决了问题,程序猿不用在去管理对象的创建了。系统的耦合性大大降低。可以专注扩展业务。这是IOC的原型!

  • IOC本质

spring ioc本质分析探究 狂神说 狂神说java spring笔记_spring_03

控制反转IOC(Inversion of Control),是一种设计思想,DI(Dependnecy Injection)依赖注入是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中,我们使用面向对象变成,对象的创建与对象间的依赖关系完全是硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方。个人认为所谓的控制反转就是:获得依赖对象的方式反转了。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以吧两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

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

3 HelloSpring

package com.markby.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 + '\'' +
                '}';
    }
}
<?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来创建对象,在Spring中,这些都称为Bean
        bean = 对象,这个标签的意思相当于 new Hello();
        类型 变量 = new 类型();
        Hello hello = new Hello();
        id = 变量名
        class = new 的对象
        property相当于给对象中的属性设置值
    -->
    <bean id="hello" class="com.kuang.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>

</beans>
@Test
    public void test() {
        // 解析beans.xml,生成管理相应的Bean对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        
        // getBean:参数即为spring配置文件中的bean的id。
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }

思考题:

  • Hello对象是谁创建的?
    是由Spring创建的
  • Hello对象的属性是怎么设置的?
    是由Spring容器设置的

这个过程就叫控制反转:

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建、

反转:程序本身不创建对象,而变成被动的接收对象。

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

IOC是一个编程思想,由主动编程变成被动的接收。

可以通过ClassPathXmlApplicationContext去浏览一下底层源码、

要实现同的操作,只需要在XML配置文件中修改。所谓的IOC,一句话:对象由Spring来创建,管理,装配

4 IOC创建对象的方式

  1. 使用无参构造创建对象,默认!
  2. 假设要使用有参构造创建对象。
  1. 下标赋值
<!--第一种:下标赋值-->
<bean id="user" class="com.kuang.pojo.User">
    <constructor-arg index="0" value="Test"/>
</bean>
  1. 类型
<!--第二种:通过类型创建,不建议使用!-->
<bean id="user" class="com.kuang.pojo.User">
	<constructor-arg type="java.lang.String" value="Test"/>
</bean>
  1. 参数名
<!--第三种:直接通过参数名来设置-->
<bean id="user" class="com.kuang.pojo.User">
	<constructor-arg name="name" value="Test"/>
</bean>

总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!

5 Spring配置

  • 别名
<alias name="user" alias="user2"/>
  • Bean的配置
<!--
        id:bean的唯一标识符,也就是相当于对象名
        class:bean对象所对应的全限定名:包名 + 类名
        name:也是别名,而且name可以同时取多个别名
    -->
    <bean id="user" class="com.kuang.pojo.User" name="u1, u2 u3; u4">
        <constructor-arg name="name" value="Test"/>
    </bean>
  • import

可以合并多个配置文件:直接使用总的配置文件就可以了

<import resource="beans.xml"/>
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>

6 依赖注入(DI,Dependency Injection)

6.1 构造器注入

前面已经说过了

6.2 Set方式注入【重点】

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

【环境搭建】

  1. 复杂类型
package com.markby.pojo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
  1. 真实测试对象
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String, String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
}
  1. beans.xml
<?xml version="1.0" encoding="UTF8"?>
<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.markby.pojo.Address">
        <property name="address" value="华强大道"/>
    </bean>

    <bean id="student" class="com.markby.pojo.Student">
        <!--第一种,普通值注入,value-->
        <property name="name" value="中文测试"/>

        <!--第二种,Bean注入,ref-->
        <property name="address" ref="address"/>

        <!--第三种,数组注入-->
        <property name="books" >
            <array>
                <value>红楼梦</value>
                <value>三国</value>
                <value>水浒</value>
                <value>西游记</value>
            </array>
        </property>

        <!--第四种,List注入-->
        <property name="hobbies" >
            <list>
                <value>唱歌</value>
                <value>跳舞</value>
                <value>打篮球</value>
            </list>
        </property>

        <!--第五种,Map注入-->
        <property name="card" >
            <map>
                <entry key="身份证" value="2333333333333"/>
                <entry key="银行卡" value="123456"/>
            </map>
        </property>

        <!--第六种,Set-->
        <property name="games" >
            <set>
                <value>LOL</value>
                <value>CS</value>
                <value>DDD</value>
            </set>
        </property>

        <!--第七种,设置为null-->
        <property name="wife" >
            <null/>
        </property>

        <!--第八种,-->
        <property name="info" >
            <props>
                <prop key="driver">219034</prop>
                <prop key="url">http</prop>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
        
    </bean>
</beans>
  1. 测试
import com.markby.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        Student student = context.getBean("student", Student.class);
        System.out.println(student);
    }
}

6.3 拓展方式注入

p-namespace和c-namespace(不能直接使用,需要导入xml约束)

<?xml version="1.0" encoding="UTF8"?>
<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"  // p命名空间xml约束
       xmlns:c="http://www.springframework.org/schema/c"  // c命名空间xml约束
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--p-namespace:property -->
    <bean id="s4user" class="com.markby.pojo.User" p:name="Test" p:str="haha" />

    <!--c-namespace:constructor-arg-->
    <bean id="s4user1" class="com.markby.pojo.User" c:name="s4user1" c:str="constructor-arg"/>

</beans>

6.4 bean的作用域

spring ioc本质分析探究 狂神说 狂神说java spring笔记_xml_04

  1. 单例模式(Spring默认机制):scope=“singleton”
  2. 原型模式:scope=“prototype”,每次从容器中get的时候,都会产生一个新对象
  3. 其余的,web开发中使用到

7 Bean的自动装配

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

在spring中的三种装配方式

  1. 在xml中显示的配置
  2. 在java中显示的配置
  3. 隐式的自动装配bean【重要】
  • ByName自动装配

保证所有bean的id唯一,并且需要和自动注入的属性的set方法的值一致

<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>

<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid-->
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
    <property name="name" value="小狂神"/>
</bean>
  • ByType自动装配

保证所有bean的Class唯一,并且需要和自动注入的属性的类型一致

<!--byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean-->
<bean id="people" class="com.kuang.pojo.People" autowire="byType">
    <property name="name" value="小狂神"/>
</bean>
  • 使用注解实现自动装配
  1. 导入约束:context约束
  2. 配置注解的支持:context:annotation-config/
<?xml version="1.0" encoding="UTF8"?>
<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="cat" class="com.markby.pojo.Cat"/>
    <bean id="dog" class="com.markby.pojo.Dog"/>

    <bean id="person" class="com.markby.pojo.Person">
        <property name="name" value="youxiu"/>
    </bean>

</beans>

@Autowired

直接在属性上使用,也可以在set方式上使用;可以不用编写set方法(IOC容器内的属性符合byName)

使用@Qualifier(“名称”):配合@Autowired使用,指定自动注入的id名称

@Nullable

字段标记了这个注解,说明这个字段可以为null

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired默认通过byType的方式实现,如果找不到名字,则通过byName实现,而且必须要求这个对象存在!【常用】
  • @Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下,就报错!【常用】

8 使用注解开发

在Spring4之后,要使用注解开发,必须保证aop的包导入另外

spring ioc本质分析探究 狂神说 狂神说java spring笔记_spring_05

使用注解需要导入context约束,增加注解的支持

  1. bean
  2. 属性如何注入
package com.markby.pojo;

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

// 等价于<bean id="user" class="com.kuang.pojo.User"></bean>
// @Component组件
@Component
public class User {
    // 等价于<property name="name" value="name"/>
    @Value("ValueTest")
    public String name;

    @Value("ValueTest")
    public void setName(String name) {
        this.name = name;
    }
}
  1. 衍生的注解
    @Component衍生的三个注解,我们在web开发中,会按照mvc三层架构分层
  • @Repository(“名称”):dao层
  • @Service(“名称”):service层
  • @Controller(“名称”):web层

这四个注解功能都是一样的,都是代表将某个类型注册到Spring中,装配Bean

  1. 自动装配
  2. 作用域
@Component
@Scope("prototype")
public class User {
    @Value("ValueTest")
    public String name;

    @Value("ValueTest")
    public void setName(String name) {
        this.name = name;
    }
}
  1. 小结
    xml 与注解:
  • xml更加万能,适用于任何场合!维护简单方便
  • 注解在自己类上使用,维护相对复杂

xml 与注解最佳实践:

  • xml来用管理bean
  • 注解只负责完成属性的注入
  • 注意:必须让注解生效,需要开启注解的支持
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.kuang.pojo"/>
<context:annotation-config/>

9 用java方式配置Spring

不使用Spring的xml配置,完全使用Java;javaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能

  • 实体类
package com.markby.pojo;

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

//这个注解说明这个类被Spring注册到了容器中
@Component
public class User {
    @Value("Test")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • 配置类
package com.markby.config;

import com.markby.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;

// 这个也会被Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration代表这是一个配置类,就是和之前的beans.xml
@Configuration
@ComponentScan("com.kuang.pojo")
//@Import(XX.class)
public class KuangConfig {
    //相当于一个bean标签,方法名字相当于id,方法返回值相当于class
    @Bean
    public User user() {
        return new User();
    }
}
  • 测试类
import com.markby.config.MarkBYConfig;
import com.markby.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MarkBYConfig.class);
        User user = (User) context.getBean("user");
        System.out.println(user.getName());
    }
}

这种纯java的配置方式,在SpringBoot中随处可见

10 代理模式

为什么学习代理模式?因为这是SpringAOP的底层【SpringAOP 和 SpringMVC】

  • 角色分析
  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,一般会做一些附属操作
  • 客户:访问代理对象的人
  • 静态代理
  • 动态代理

https://www.runoob.com/design-pattern/proxy-pattern.html

代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不用关注一些公共的业务
  • 公告业务交给代理角色,实现了业务的分工
  • 公共业务扩展时,方便几种管理

缺点:

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

静态代理:对应spring-08→demo02

spring ioc本质分析探究 狂神说 狂神说java spring笔记_xml_06

动态代理(解决静态代理的缺点)

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
  • 基于接口:JDK动态代理
  • 基于类:CGlib
  • java字节码实现:javasist

需要了解两个类:Proxy 代理、InvocationHandler 调用处理器

//用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

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

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

    public void log(String msg){
        System.out.println("【Debug】执行了" + msg + "方法");
    }
}
public class Client {
  public static void main(String[] args) {
      //真实角色
      UserServiceImpl userService = new UserServiceImpl();

      //代理角色
      ProxyInvocationHandler pih = new ProxyInvocationHandler();
      pih.setTarget(userService);   //设置要代理的对象

      //动态生成代理类
      UserService proxy = (UserService) pih.getProxy();
      proxy.query();
  }
}

动态代理的好处:

  • 可以使真实角色的操作更加纯粹,不用关注一些公共的业务
  • 公告业务交给代理角色,实现了业务的分工
  • 公共业务扩展时,方便几种管理
  • 一个动态代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可。

11 面向切面编程AOP

Aop(Aspect Oriented Programming)是通过预编译方式喝运行期运行期动态代理实现程序功能的统一维护的一种技术,是函数式编程的一种衍生泛型。利用Aop可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。

使用spring实现AOP

【重点】使用AOP织入,需要导入一个依赖包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
	<groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>
  1. 使用Spring的API接口【主要是SpringAOP接口实现】
public class Log implements MethodBeforeAdvice {
    //method:要执行的目标对象的方法
    //objects:参数
    //target:目标对象
    @Override
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
    }
}
public class AfterLog implements AfterReturningAdvice {
    //returnValue:返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了" + method.getName() + "返回结果为:" + returnValue);
    }
}
<?xml version="1.0" encoding="UTF8"?>
<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">

    <bean id="userService" class="com.kuang.service.UserServiceImpl"/>
    <bean id="log" class="com.kuang.log.Log"/>
    <bean id="afterLog" class="com.kuang.log.AfterLog"/>

    <!--方式一:使用原生Spring API接口-->
    <!--配置aop:需要导入aop的约束-->
    <aop:config>
        <!--切入点:expression(要执行的位置)-->
        <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>

        <!--执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>
  1. 自动以来实现AOP【主要是切面定义】
<!--方式二:自定义类-->
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
	<!--自定义切面,ref:要引用的类-->
    <aop:aspect ref="diy">
    	<!--切入点-->
        <aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
        <!--通知-->
        <aop:before method="before" pointcut-ref="point"/>
        <aop:after method="after" pointcut-ref="point"/>
    </aop:aspect>
</aop:config>
  1. 注解实现
//方式三:使用注解方式实现Aop,标注这个类是一个切面
@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("=====方法执行前=====");
    }

    @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("=====方法执行后=====");
    }
    
    //在环绕增强中,我们可以定义一个参数,代表我们要获取处理切入的点
    @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        //执行方法
        Object proceed = jp.proceed();
        System.out.println("环绕后");
    }
}
<!--方式三-->
<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut"/>
<!--开启注解支持, JDK(默认):proxy-target-class="false", cglib:proxy-target-class="true"-->
<aop:aspectj-autoproxy proxy-target-class="true"/>

12 整合MyBatis

步骤:

  1. 导入相关jar包
  • Junit
  • mybatis
  • mysql数据库
  • spring相关
  • aop织入
  • mybatis-spring【新的】
  1. 编写配置文件
  2. 测试
  • 回忆mybatis
  1. 编写实体类
  2. 编写核心配置文件
  3. 编写接口
  4. 编写Mapper.xml
  5. 测试
  • MyBatis-spring
  1. 编写数据源
  2. sqlSessionFactory
  3. sqlSessionTemplate
<?xml version="1.0" encoding="UTF8"?>
<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">

    <!--DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid-->
    <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&useUnicode=true&characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--绑定Mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
    </bean>

    <!--SqlSessionTemplate:就是我们使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能使用构造器注入sqlSessionFactory,因为他没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

</beans>
  1. 需要给接口加实现类
public class UserMapperImpl implements UserMapper{
    //之前我们的所有操作都使用sqlSession来执行,现在都使用SqlSessionTemplate
    private SqlSessionTemplate sqlSession;

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

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}
  1. 将自己写的实现类,注入到Spring中
<?xml version="1.0" encoding="UTF8"?>
<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">

    <import resource="ApplicationContext.xml"/>

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

</beans>
  1. 测试
public class MyTest {
    @Test
    public void test() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User user: userMapper.selectUser()){
            System.out.println(user);
        }
    }
}
  • 第二种方法
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> selectUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}
<bean id="userMapper2" class="com.kuang.mapper.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

13 Spring中的事务管理

Spring中的事务管理(同时成功、失败)

  • 声明式事务:AOP
  • 编程式事务:需要在代码中,进行事务管理

思考:

为什么需要事务

  • 如果不配置事务,可能存在数据提交不一致的情况
  • 如果不在Spring中配置声明式事务,需要在代码中手动配置事务