狂神说Java --- 记录Spring学习笔记

传送门 ==>B站遇见狂神说—Spring5教程

感谢狂神,学习视频真的是通俗易懂♥♥♥

笔记和练习只是跟着视频整理的;有的知识点并没有整理进来


ml

  • 1.Spring概述
  • 2. 控制反转IOC
  • 3.试试Spring
    • 3.1 IOC创建对象的方式
    • 3.2 Spring配置说明
    • 3.3 DI (依赖注入)
      • 3.3.1 set注入
      • 3.3.2 (扩展) p命名set注入 ; c命名构造注入
    • 3.4 Bean的作用域
    • 3.5 自动装配Bean
      • 3.5.1 byName,byType自动装配
      • 3.5.2 使用注解实现装配
        • Spring注解开发
      • 3.5.3 使用JavaConfig实现配置
  • 4. 静态代理模式
  • 5. 动态代理模式
  • 6.面向切面 AOP
    • 方式1:使用原生的Spring API接口
    • 方式 2;使用自定义 实现
    • 方式3: 使用注解实现
  • 7. 整合Mybatis
    • 7.1Spring整合 Mybatis的方式一
    • 7.2 Spring整合 Mybatis的方式二
  • 8.声明式事务


Spring 官网==>https://spring.io
Spring官方文档==>https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html

本次使用的是Spring Web MVC


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-webmvcartifactId>
    <version>5.3.9version>
dependency>

之后还可能用到spring jdbc


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-jdbcartifactId>
    <version>5.3.9version>
dependency>

1.Spring概述

Spring是开源免费的轻量级的控制反转(IOC)和面向切面(AOP)的容器框架;支持事务处理.

由7个模块组成,

狂神说Java --- 记录Spring学习笔记_第1张图片

(Spring Boot) 构建一切,(Sprint Cloud)协调一切,(Spring Cloud Data Flow)连接一切

(Spring Boot)就像脚手架,可实现快速开发单个微服务;而学习它的前提是学习Spring和SpringMVC.


2. 控制反转IOC

IOC理论推导

创建一个空的maven项目,删除src目录;作为父级项目;

还是和之前一样,先去检查maven地址;

狂神说Java --- 记录Spring学习笔记_第2张图片

pom.xml导包

<dependencies>
    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-webmvcartifactId>
        <version>5.3.9version>
    dependency>
    
    <dependency>
    <groupId>junitgroupId>
    <artifactId>junitartifactId>
    <version>4.12version>
dependency>
dependencies>

可看到,下载结束后,出现了好几个资源包

狂神说Java --- 记录Spring学习笔记_第3张图片

创建一个子级maven工程;

在这里插入图片描述

狂神说Java --- 记录Spring学习笔记_第4张图片


就用一个基础的项目构建来说吧;
持久层接口UserDao;

public interface UserDao {
    //查询用户;
    void findUser();
}

持久层实现类UserDaoImpl;

public class UserDaoImpl implements UserDao{
    public void findUser() {
        System.out.println("默认调用的方法");
    }
}

业务层接口UserService;

public interface UserService {
    //查询用户;
    void findUser();
}

业务层接口的实现类UserServiceImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserDaoImpl();

    public void findUser() {
      //在业务层调用持久层的方法;
        userDao.findUser();
    }
}

测试调用

@Test
    public void test(){
        UserService userService=new UserServiceImpl();
        userService.findUser();
    }

这时输出

狂神说Java --- 记录Spring学习笔记_第5张图片

而如果说,这时候又来需求了,持久层新增了一个实现类UserMySqlImpl

public class UserMySqlImpl implements UserDao{
    public void findUser() {
        System.out.println("MySql的方法");
    }
}

那么如果说想要拿到这个需求的实现,就要在业务层的实现类UserServiceImpl中;去更改持久层的实现类改为UserMySqlImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserMySqlImpl();

    public void findUser() {
      //在业务层调用持久层的方法;
        userDao.findUser();
    }
}

测试调用,即可

狂神说Java --- 记录Spring学习笔记_第6张图片

如果说又有一个新的需求,创建了一个新的持久层实现类UserOracleImpl;

public class UserOracleImpl implements UserDao{
    public void findUser() {
        System.out.println("Oracle方式");
    }
}

那么就得去业务层UserServiceImpl中更改;

public class UserServiceImpl implements UserService{
    private UserDao userDao=new UserOracleImpl();

    public void findUser() {
      //在业务层调用持久层的方法;
        userDao.findUser();
    }
}

然后测试调用

狂神说Java --- 记录Spring学习笔记_第7张图片

在之前的业务中,用户的需求可能会影响原来的代码,就要根据用户的需求更改代码.

要是在UserServiceImpl中用set实现动态修改实现类;

public class UserServiceImpl implements UserService{
     private UserDao userDao;
    //控制反转的原型,在业务层提供动态的用户需求方法;
    //用set实现动态注入值;
     public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
      }

    public void findUser() {
      //在业务层调用持久层的方法;
      userDao.findUser();
    }
}

在测试执行的方法内,只需要调用setUserDao 方法,去更改里面的持久层实现类即可

public class MyTest {
    @Test
    public void test() {
        UserService userService = new UserServiceImpl();
        ((UserServiceImpl) userService).setUserDao(new UserMySqlImpl());
        userService.findUser();
    }
}

狂神说Java --- 记录Spring学习笔记_第8张图片


每使用set设置之前,程序是需要主动创建对象,控制权在开发者手中,使用了set注入后,程序不再具有主动性,变为被动的接受对象.
开发者不必管理对象的创建,系统耦合性降低,专注于业务的实现.

即控制反转 IOC 的原型.


IOC的本质

控制反转IOC 设计思想,而 DI(依赖注入)是实现IOC的一种方法,
在没有使用IOC的程序,作为面向对象编程的语言,对象的创建和对象间的依赖关系是必须硬编码在程序中,对象的创建由程序自己控制,

控制反转后将对象的创建转移到第三方, 获取依赖对象的方式反转.


3.试试Spring

ok新建一个实体类User;

public class User {
    private String name;

    public User(){
        System.out.println("User类的无参构造");
    }
    
    public User(String name){
        this.name=name;
        System.out.println("User类的有参构造");
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

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
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!--使用spring 创建对象;就是 bean-->
    <!--这时的id就是变量名;class就是new的对象-->
    <!--property: 可以为对象的属性设置值-->

    <bean id="user" class="com.lzq.pojo.User">
        <property name="name" value="xiaozhi"/>
    </bean>
</beans>

测试

public class Test01 {
    public static void main(String[] args) {
        //获取Spring得上下文对象;
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //由于创建对象就是 Spring 中的bean; 获取bean即可获取对象;
        User user = (User) context.getBean("user");

        System.out.println(user.toString());
    }
}

输出:

User类的无参构造
User{name='xiaozhi'}

可以看出,从始至终没有使用new构造方法进行创建User类的对象;
但是实际上在xml配置文件中,已经被Spring创建对象了;且设置了属性name的值;
程序本身不去创建对象,作为了被动的接收对象.

此过程就是控制反转;IOC; 由Spring 创建 管理 装配.

狂神说Java --- 记录Spring学习笔记_第9张图片

这里使用了set方法来进行注入的;若删除set方法;就无法得到属性name.
设置value是针对于基本数据;

狂神说Java --- 记录Spring学习笔记_第10张图片

设置实体类显示小叶子图标;

狂神说Java --- 记录Spring学习笔记_第11张图片


再看看刚才的UserDao,实际上,根据需要就可以直接在配置文件修改即可.

ref: 会引用 在Spring中设置创建的对象

狂神说Java --- 记录Spring学习笔记_第12张图片


3.1 IOC创建对象的方式

刚在在测执行时;注意到,输出有调用到无参构造方法;

狂神说Java --- 记录Spring学习笔记_第13张图片

那么如果将User类的无参构造方法去掉;即为User类写个显示的有参构造,默认隐式的无参构造就没有了;

狂神说Java --- 记录Spring学习笔记_第14张图片

再次执行,出现异常提示;提示初始化异常;

狂神说Java --- 记录Spring学习笔记_第15张图片

在xml配置文件中也有提示

狂神说Java --- 记录Spring学习笔记_第16张图片

IOC创建对象时默认使用无参构造方法,

那么如果说想用有参构造方法呢,有三种方式;

方式1:使用index(下标) 指定有参构造方法的参数是第几个; value 为参数赋值 ;
beans.xml 文件的bean标签下的constructor-arg标签中配置


<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-3.0.xsd">

    

    <bean id="user" class="com.lzq.pojo.User">
        <constructor-arg index="0" value="小智从零开始学Java"/>
    bean>
beans>

执行,是调用了有参构造方法的;且为参数name赋值也取到了.

狂神说Java --- 记录Spring学习笔记_第17张图片

方式2:使用type 属性 显式的指定构造函数参数的类型;value为参数赋值.

注意: 基本类型可直接写;引用类型要注明类的地址;
例如官方文档中是这么写的.

<bean id="exampleBean" class="examples.ExampleBean">
   <constructor-arg type="int" value="2001"/>
   <constructor-arg type="java.lang.String" value="Zara"/>
bean>

ok,用方式2调有参构造方法,为user类创建对象.


<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-3.0.xsd">
    
    <bean id="user" class="com.lzq.pojo.User">
        <constructor-arg type="java.lang.String" value="方式二"/>
    bean>
beans>

执行,使用成功;

狂神说Java --- 记录Spring学习笔记_第18张图片

方式 3: 直接使用 参数名name设置 ; value 参数赋值


<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-3.0.xsd">
    
    <bean id="user" class="com.lzq.pojo.User" >
        <constructor-arg name="name" value="方式3"/>
    bean>
beans>

执行,使用成功;

狂神说Java --- 记录Spring学习笔记_第19张图片


还有就是,在pojo包下,再创建一个Student类;

public class Student {
    private int age;

    public Student() {
        System.out.println("Student类的无参构造方法");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

注意;仅仅是在beans.xml为他用无参构造方法创建了对象;


<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-3.0.xsd">

    
    
    <bean id="user" class="com.lzq.pojo.User" >
        <constructor-arg name="name" value="方式3"/>
    bean>

    
    <bean id="student" class="com.lzq.pojo.Student">

    bean>

beans>

诶,这里还是执行之前测试User类的代码;

public class Test01 {
    public static void main(String[] args) {
        //获取Spring得上下文对象;
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        //由于创建对象就是 Spring 中的bean; 获取bean即可获取对象;
        User user = (User) context.getBean("user");

        System.out.println(user.toString());
    }
}

但是输出结果时,发现Student类创建对象时调用的无参构造方法也有记录;

狂神说Java --- 记录Spring学习笔记_第20张图片

实际上, Spring容器就像是一个婚介网站

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


3.2 Spring配置说明

别名
alias

比如说;为User类创建对象时的变量id user 取个别名u

<alias name="user"  alias="u"/>

狂神说Java --- 记录Spring学习笔记_第21张图片

那么,在执行测试时,使用别名也能获取到这个User类的对象;

狂神说Java --- 记录Spring学习笔记_第22张图片

Bean的配置
细细看看标签内的几个配置标签

id 就是 bean的唯一标识符 ,也就相当于对象名;

classbean 对应的全限定名==> 包名 +类型;

name别名 ;且 可以写多个别名,用逗号或者分号隔开即可

<bean id="user" class="com.lzq.pojo.User"  name="u1,u2;u3">
bean>

import标签
一般在团队开发中使用;可以将多个配置文件导入合并为一个

<import resource="beans.xml"/>
<import resource="otherbeans.xml"/>
<import resource="otherbeans2.xml"/>

3.3 DI (依赖注入)

第一个就是构造函数注入,也就是刚才在创建对象时修改调用有参无参构造方法时;就使用过了.

第二个就是set注入,这个很重要

依赖: = = > bean对象的创建依赖于Spring容器
注入: = => bean对象中的所有属性,由容器注入.

3.3.1 set注入

用一个复杂的案例看看这个set注入

新建一个Adderss

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
    
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

新建一个Student

public class Student {
    private String name;
    //这里的Address是自定义的类;
    private Address address;

    private String[] books;

    private List<String> hobby;

    private Map<String,String>  card;

    private Set<String> games;

    private String friend;

    private Properties info;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobby() {
        return hobby;
    }

    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getFriend() {
        return friend;
    }

    public void setFriend(String friend) {
        this.friend = friend;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.toString()  +
                ", books=" + Arrays.toString(books) +
                ", hobby=" + hobby +
                ", card=" + card +
                ", games=" + games +
                ", friend='" + friend + '\'' +
                ", info=" + info +
                '}';
    }
}

resources 目录下创建applicationContext.xml;


<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-3.0.xsd">

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

    
    <bean id="student" class="com.xiaozhi.pojo.Student">

        <property name="name" value="小智"/>
        
        <property name="address" ref="address"/>
        
        <property name="books">
            <array>
                <value>算法图解value>
                <value>大话数据结构value>
                <value>剑指Offervalue>
                <value>java核心技术value>
            array>
        property>
        
        <property name="hobby">
            <list>
                <value>吃饭value>
                <value>睡觉value>
                <value>学习value>
                <value>敲代码value>
            list>
        property>
        
        <property name="card">
            <map>
                <entry key="电卡" value="123456789"/>
                <entry key="水卡" value="223456789"/>
                <entry key="燃气卡" value="000000000"/>
            map>
        property>
        
        <property name="games">
            <set>
                <value>Fortnitevalue>
                <value>OverWatchvalue>
            set>
        property>
        
        <property name="friend" >
            <null/>
        property>
        
        <property name="info">
            <props>
                <prop key="性别">prop>
                <prop key="电话">123654prop>
            props>
        property>
     bean>
beans>

执行测试输出,不同类型的属性赋值均取到;

public class Test03 {
    public static void main(String[] args) {
        //读取applicationContext.xml配置文件;获取Spring的上下文对象
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取Student类的 bean;
        Student student = (Student) applicationContext.getBean("student");

        System.out.println(student.toString());
    }
}

在这里插入图片描述


3.3.2 (扩展) p命名set注入 ; c命名构造注入

p: 命名空间注入,可直接注入属性和值
注意在beans标签的头部需要导入这个xml约束

xmlns:p="http://www.springframework.org/schema/p"

实体类User

public class User {
    private String name;
    private int age;
    
    public User() {
        System.out.println("无参构造方法");
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("有参构造方法");
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

配置文件


<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    
    <bean id="user" class="com.xiaozhi.pojo.User" p:name="小智" p:age="21"/>
beans>

getBean(“对象”,类型)
若在第二个参数处指明使用的类型,就不用强制转换类型了;

public class Test04 {
    public static void main(String[] args) {
        //读取applicationContext.xml配置文件;获取Spring的上下文对象
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //获取User类的 bean;
        User user =  applicationContext.getBean("user",User.class);

        System.out.println(user.toString());
    }
}

输出

无参构造方法
User{name='小智', age=21}

c: 命名空间注入,可直接注入构造方法的参数与值
注意在beans标签的头部需要导入这个xml约束

xmlns:c="http://www.springframework.org/schema/c"

在配置文件中使用


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    
    <bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21"/>

    
    <bean id="user2" class="com.xiaozhi.pojo.User" c:_0="阿杰" c:_1="21"/>
beans>

测试执行

public class Test04 {
    public static void main(String[] args) {
        //读取applicationContext.xml配置文件;获取Spring的上下文对象
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //获取User类的 bean;
        User user1 =  applicationContext.getBean("user1",User.class);
        User user2 =  applicationContext.getBean("user2",User.class);

        System.out.println(user1.toString());
        System.out.println(user2.toString());
    }
}

输出:

有参构造方法
有参构造方法
User{name='小智', age=21}
User{name='阿杰', age=21}

3.4 Bean的作用域

singleton(默认值) 单例模式:在 Spring 中只存在一个 bean 实例

即使不写也是默认存在的.

<bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21" scope="singleton"/>

狂神说Java --- 记录Spring学习笔记_第23张图片

比如说,我在执行这边分别获取两次bean;两次取到到的bean是同一个

狂神说Java --- 记录Spring学习笔记_第24张图片

prototype:原型模式 getBean()的时候都会 new Bean()

<bean id="user1" class="com.xiaozhi.pojo.User" c:name="小智" c:age="21" scope="prototype"/>

狂神说Java --- 记录Spring学习笔记_第25张图片

还是刚才的执行例子;两次取到的对象不一致了.

狂神说Java --- 记录Spring学习笔记_第26张图片

request:每次 http 请求都会创建一个 bean, 仅用于 WebApplicationContext环境
session:同一个 http session 共享一个 Bean, 不同 Session 使用不同的 Bean, 使用环境同上


3.5 自动装配Bean

自动装配是Spring为满足bean依赖的一种方式;由Spring在上下文中自动寻找,自动装配bean.

有三种装配方式;
在xml显示的手动装配;
在java中显示地装配
隐式的自动装配

首先设计几个类

Cat类

public class Cat {
    public void shoot(){
        System.out.println("阿猫说喵喵");
    }
}

Dog类

public class Dog {
    public void shoot(){
        System.out.println("阿狗说汪汪");
    }
}

Person类

public class Person {
    private Cat cat;
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

配置applicationContext.xml


<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-3.0.xsd">

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

    
    <bean id="person" class="com.xiaozhi.pojo.Person">
        <property name="name" value="小智"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    bean>

beans>

测试调用

public class Test04 {
    public static void main(String[] args) {
        //读取applicationContext.xml配置文件;获取Spring的上下文对象
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");

        //获取User类的 bean;
        Person person = applicationContext.getBean("person", Person.class);
        person.getCat().shoot();
        person.getDog().shoot();
    }
}

输出

阿猫说喵喵
阿狗说汪汪

3.5.1 byName,byType自动装配

使用byName时,需要保证所有的bean 的id是唯一的,且bean是需要与自动注入的属性的set方法一致;

使用byType时,需要保证所有bean的class唯一; 且bean要和自动注入的属性的类型保持一致.

先看看byName

需要在applicationContext.xml中更改配置Person类的bean;

直接用autowire="byName" 属性
自动在容器的上下文中查找,与自己对象的set方法后的值对应的bean.


    <bean id="cat" class="com.xiaozhi.pojo.Cat"/>
    <bean id="dog" class="com.xiaozhi.pojo.Dog"/>
    
 
<bean id="person" class="com.xiaozhi.pojo.Person" autowire="byName">
    <property name="name" value="小智"/>
bean>

狂神说Java --- 记录Spring学习笔记_第27张图片

在执行后,依然可输出

狂神说Java --- 记录Spring学习笔记_第28张图片

但是,配置Cat类和Dog类的bean时,修改id;


<bean id="cat456" class="com.xiaozhi.pojo.Cat"/>
<bean id="dog666" class="com.xiaozhi.pojo.Dog"/>


<bean id="person" class="com.xiaozhi.pojo.Person" autowire="byName">
    <property name="name" value="小智"/>
bean>

诶,执行时就出现异常了

狂神说Java --- 记录Spring学习笔记_第29张图片

这个说明什么呢;
只要配置的类的bean的id ; 和这个想要自动装配bean 的类中的set方法名字后面的名称一致,它就能自动装配bean了.


再看看 byType

和byName设置时差不多
需要在applicationContext.xml中更改配置Person类的bean;
设置autowire="byType"
自动在容器的上下文中查找;对应类的属性中的类型相同的bean


    <bean id="cat456" class="com.xiaozhi.pojo.Cat"/>
    <bean id="dog666" class="com.xiaozhi.pojo.Dog"/>
    
    
    
    <bean id="person" class="com.xiaozhi.pojo.Person" autowire="byType">
        <property name="name" value="小智"/>
    bean>

虽然这里的id是和set方法后面的名称不一致的;但是仍然可以执行成功;

狂神说Java --- 记录Spring学习笔记_第30张图片

但是有个问题啊;你这边一旦创建多个bean;就不行了;
byType需要保证这里的类型要是唯一的

狂神说Java --- 记录Spring学习笔记_第31张图片

但是,用了byType后,你甚至可以把装配的bean的id给省略了

狂神说Java --- 记录Spring学习笔记_第32张图片


3.5.2 使用注解实现装配

需要导入相关xml配置约束;配置注解的支持


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

配置xml文件


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

    <bean id="cat" class="com.xiaozhi.pojo.Cat"/>
    <bean id="dog" class="com.xiaozhi.pojo.Dog"/>
    <bean id="person" class="com.xiaozhi.pojo.Person"/>
    
    
    <context:annotation-config/>

beans>

直接在Person类的属性cat和dog处使用注解即可;@Autowired

@Autowired先执行byType

不过还是建议在setter方法上使用注解.

狂神说Java --- 记录Spring学习笔记_第33张图片

同样地装配成功了

狂神说Java --- 记录Spring学习笔记_第34张图片

扩展

(1) @Nullable 注解,在字段处标记后,该字段可以为null

(2) 仔细看看注解==@Autowired==;注意到后面是可以写参数required (默认为true)的;
要是显示地定义了 @Autowired(required = false) ,那么说明此字段的对象可以为null

package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

(3) 如果xml文件中同一个对象被多个bean使用;使用@Autowired无法按类型找到;’

这时就需要使用注解 @Qualifier(value=" ") 配合注解@Autowired;指定唯一的bean对象注入

狂神说Java --- 记录Spring学习笔记_第35张图片

(4) 使用注解 @Resource ,java的原生注解; 它是根据class来找的.

@Resource先执行byName

如果xml文件中同一个对象被多个bean使用;@Resource还可以加参数 @Resource(name=" ")

狂神说Java --- 记录Spring学习笔记_第36张图片


Spring注解开发

spring后,先保证导入 aop的包
且注解有约束和支持


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

bean的注入

在类上使用注解 @Component 可以代替xml文件中的配置bean

比如说这里使用注解就相当于

<bean id="user" class="com.xiaozhi.pojo.User"/>

在这里插入图片描述

属性的注入
在属性的字段上使用注解 @Value(“赋值”) 即可

比如说这里使用了注解就相当于

<bean id="user" class="com.xiaozhi.pojo.User">
     <property name="name" value="小智"/>
     <property name="age" value="21"/>
bean>

狂神说Java --- 记录Spring学习笔记_第37张图片

实际上; 注解 @Component 还有衍生的几个注解;
一般在dao层使用注解 @Repository ; 表示仓库;
service层使用注解 @Service ;
controller 层 使用 注解 @Controller

对于作用域还可使用注解 @Scope ;里面可传参value指定所用域范围.


3.5.3 使用JavaConfig实现配置

这部分不使用spring的配置文件;

之前仅作为spring的子项目,但在spring4之后是作为核心功能.

在一个类上使用注解 @Configuration ;该注解的底层已使用了注解@Component; 他也被spring接管了;表示该类为一个配置类

使用注解@ComponentScan("com.xiaozhi.pojo")配置包扫描;配置包扫描后,其实默认的id就是类名的小写了;

注解 @Bean 就相当于配置文件的bean标签;方法名相当于id;方法的返回值相当于class 属性;

注解 @Import(“其他配置文件类”) 可用来合并配置文件.

注意获取对象时,要先用AnnotationConfigApplicationContext获取上下文对象;

实体类User

//注解表名该类被spring接管;注入bean;
@Component
public class User {

    private String name;

    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    //该注解为属性赋值;
    @Value("小智")
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    @Value("21")
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

配置类UserConfig

//该注解的底层已使用了注解@Component; 他也被spring接管了;
//表示该类为一个配置类
@Configuration
//配置包扫描;
@ComponentScan("com.xiaozhi.pojo")
public class UserConfig {


    //配置bean;
    //方法名相当于之前配置文件的bean标签的id 属性
    //方法的返回值相当于class 属性;
    @Bean
    public User getUser(){
        return new User();
    }
}

执行;

public class Test06 {
    public static void main(String[] args) {
        //用注解的方式获取的上下文对象
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserConfig.class);

        //获取对象;
        User user = applicationContext.getBean("getUser", User.class);

        System.out.println(user);

    }
}

可输出

User{name='小智', age=21}

4. 静态代理模式

代码模式原型

狂神说Java --- 记录Spring学习笔记_第38张图片

关于静态代理

抽象角色 = => 接口或 抽象类

真实角色 = => 被代理的角色

代理角色 = => 代理真实角色, 代理真实角色后,会做出附属操作

客户 = => 访问代理对象

(1)可以使真实角色的操作简单;不用去关注公共业务;而公共业务交给代理角色;实现了业务的分工;公共业务发生扩展时,方便集中管理.
(2)缺点: 一个真实角色就要产生一个代理角色;代码量翻倍;开发效率会变低.

第一个例子;面向中介去租房;
租房接口

//租房
public interface Rent {
    public void rent();
}

房东实体类

//房东
public class Host implements Rent{

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

代理中介

//代理中介
public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    public void rent() {
        seeHouse();
        host.rent();
        contract();
        fee();
    }

    //看房子;
    public void seeHouse(){
        System.out.println("由中介带着看房");
    }
    //收费;
    public void fee(){
        System.out.println("收中介费用");
    }
    //签合同
    public void contract(){
        System.out.println("和中介签合同");
    }
}

租房的客户

//租房的人 =,我
public class Me {
    public static void main(String[] args) {
        Host host=new Host();

        Proxy proxy = new Proxy(host);
        //直接面向代理中介;
        proxy.rent();
    }
}

直接执行客户租房

由中介带着看房
房东出租房子
和中介签合同
收中介费用

狂神说Java --- 记录Spring学习笔记_第39张图片

例子2:
比如说原有一个抽象业务接口
UserService

//抽象的业务;
public interface UserService {
    void addUser();
    void deleteUser();
    void updateUser();
    void findUser();
}

有他的实现类UserServiceImpl

//真实对象;
public class UserServiceImpl implements UserService{
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
    }

    public void updateUser() {
        System.out.println("更新用户");
    }

    public void findUser() {
        System.out.println("查询用户");
    }
}

业务已经跑起来了,但是需要一个额外的扩展功能;这时就需要一个代理类;
UserServiceProxy

//代理人;  可扩展功能;并不影响原来的业务功能;
public class UserServiceProxy implements UserService{

    private  UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    public void addUser() {
        log("add添加");
        userService.addUser();
    }

    public void deleteUser() {
        log("delete删除");
        userService.deleteUser();
    }

    public void updateUser() {
        log("update更新");
        userService.updateUser();
    }

    public void findUser() {
        log("find查询");
        userService.findUser();
    }

    //模拟使用日志;
    public void log(String str){
        System.out.println("[模拟日志]=>使用的是"+str+"方法");
    }
}

那么用户在实现时,只要走代理类的功能;既保证了原有的业务功能,也有新的扩展功能;

public class Me {
    public static void main(String[] args) {

        UserServiceImpl userService=new UserServiceImpl();

        //使用代理角色;
        UserServiceProxy userServiceProxy = new UserServiceProxy();
        userServiceProxy.setUserService(userService);
        userServiceProxy.addUser();
        userServiceProxy.deleteUser();
        userServiceProxy.updateUser();
        userServiceProxy.findUser();
    }
}

输出

[模拟日志]=>使用的是add添加方法
添加用户
[模拟日志]=>使用的是delete删除方法
删除用户
[模拟日志]=>使用的是update更新方法
更新用户
[模拟日志]=>使用的是find查询方法
查询用户

5. 动态代理模式

代理类是动态生成的,
基于接口是 -->JDK动态代理 ;
基于类–> cglib
java的字节码实现时–>javasist

动态 代理接口,对应一类业务.

java.lang.reflect
Interface InvocationHandler

是由代理实例的调用处理程序实现的接口 。

其中有一个invoke方法;

Object invoke(Object proxy, 方法 method, Object[ ] args)
处理代理实例上的方法调用并返回结果。

狂神说Java --- 记录Spring学习笔记_第40张图片

java.lang.reflect
Class Proxy

Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

狂神说Java --- 记录Spring学习笔记_第41张图片

为某个接口创建代理FooInvocationHandler handler = new MyInvocationHandler(...);
     Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
                     newInstance(handler); 或更简单地: 
  Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                                          new Class<?>[] { Foo.class },
                                          handler); 

狂神说Java --- 记录Spring学习笔记_第42张图片

案例;
还是刚才的userservice,userimpl案例;
但是代理类动态生成

//动态生成代理类;
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口;
    private Object object;

    public void setObject(Object object){
        this.object=object;
    }

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

    //处理代理实例,返回结果;
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        //动态代理本质,用反射实现;
        Object res=method.invoke(object,args);
        return res;
    }

    //模拟日志的方法;
    public void log(String str){
        System.out.println("[模拟日志]=>使用的是"+str+"方法");
    }
}

在用户调用时;

public class Me {
    public static void main(String[] args) {
        //真实的角色;  UserServiceImpl
        UserServiceImpl userService=new UserServiceImpl();

        //并不存在的代理角色;
        ProxyInvocationHandler pI=new ProxyInvocationHandler();
        //设置需要代理的对象;
        pI.setObject(userService);
        //动态得到代理类;
        UserService proxy = (UserService) pI.findProxy();

        proxy.addUser();
        proxy.findUser();
        proxy.deleteUser();
        proxy.updateUser();
    }
}

输出

[模拟日志]=>使用的是addUser方法
添加用户
[模拟日志]=>使用的是findUser方法
查询用户
[模拟日志]=>使用的是deleteUser方法
删除用户
[模拟日志]=>使用的是updateUser方法
更新用户

6.面向切面 AOP

AOP (Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

狂神说Java --- 记录Spring学习笔记_第43张图片

狂神说Java --- 记录Spring学习笔记_第44张图片

使用spring实现AOP,先用maven导包

<dependency>
    <groupId>org.aspectjgroupId>
    <artifactId>aspectjweaverartifactId>
    <version>1.9.4version>
dependency>

方式1:使用原生的Spring API接口

创建UserService接口

//抽象的业务;
public interface UserService {
    void addUser();
    void deleteUser();
    void updateUser();
    void findUser();
}

实现类UserServiceImpl

//真实对象;
public class UserServiceImpl implements UserService{
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
    }

    public void updateUser() {
        System.out.println("更新用户");
    }

    public void findUser() {
        System.out.println("查询用户");
    }
}

模拟前置日志BeforeLog

//模拟前置日志;
public class BeforeLog implements MethodBeforeAdvice {
    /**
     *
     * @param method  要执行的目标对象方法;
     * @param objects 参数
     * @param target 目标对象
     * @throws Throwable
     */
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行");
    }
}

模拟后置日志

//模拟后置日志;
public class AfterLog implements AfterReturningAdvice {
    /**
     *
     * @param returnValue 返回值
     * @param method  要执行的目标对象方法;
     * @param objects 参数
     * @param target 目标对象
     * @throws Throwable
     */
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(method.getName()+"执行后,返回"+returnValue);
    }
}

applicationContext.xml中配置


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

    
   <bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
   <bean id="beforeLog" class="com.xiaozhi.log.BeforeLog"/>
   <bean id="afterLog" class="com.xiaozhi.log.AfterLog"/>

    
    
    <aop:config>
        
        <aop:pointcut id="point" expression="execution(* com.xiaozhi.service.UserServiceImpl.*(..))"/>

        
        <aop:advisor advice-ref="beforeLog" pointcut-ref="point"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
    aop:config>
beans>

执行输出

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

        //获取bean;

        //动态代理的是接口;
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        //调用方法;
        userService.addUser();
        userService.deleteUser();
        userService.findUser();
        userService.updateUser();
    }
}

输出

com.xiaozhi.service.UserServiceImpl的addUser方法被执行
添加用户
addUser执行后,返回null
com.xiaozhi.service.UserServiceImpl的deleteUser方法被执行
删除用户
deleteUser执行后,返回null
com.xiaozhi.service.UserServiceImpl的findUser方法被执行
查询用户
findUser执行后,返回null
com.xiaozhi.service.UserServiceImpl的updateUser方法被执行
更新用户
updateUser执行后,返回null

方式 2;使用自定义 实现

不用去实现接口,直接自定义类MyLog

public class MyLog {
    public void beforeLog(){
        System.out.println("========模拟执行前置========");
    }
    public void afterLog(){
        System.out.println("========模拟执行后置========");
    }
}

applicationContext.xml中配置


<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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
       
    
    <bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
    <bean id="myLog" class="com.xiaozhi.mydiy.MyLog"/>
    
    
    <aop:config>
        
        <aop:aspect ref="myLog">
            
            <aop:pointcut id="point" expression="execution(* com.xiaozhi.service.UserServiceImpl.*(..))"/>
            
            <aop:before method="beforeLog" pointcut-ref="point"/>
            <aop:after method="afterLog" pointcut-ref="point"/>
        aop:aspect>
    aop:config>
    
beans>

测试执行;同样可执行

========模拟执行前置========
添加用户
========模拟执行后置========
========模拟执行前置========
删除用户
========模拟执行后置========
========模拟执行前置========
查询用户
========模拟执行后置========
========模拟执行前置========
更新用户
========模拟执行后置========

方式3: 使用注解实现

自定义的类,用注解标注为切面

//使用注解实现;
//@Aspect 标注该类是个切面;
@Aspect
public class MyAnnotation {

    //注意使用的是 import org.aspectj.lang.annotation.Before;包下的
    @Before("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
    public void beforeLog(){
        System.out.println("========注解方式模拟执行前置========");
    }

    //import org.aspectj.lang.annotation.After;
    @After("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
    public void afterLog(){
        System.out.println("========注解方式模拟执行后置========");
    }

    //在环绕增强时,可给定参数,表示获取处理切入的点
    @Around("execution(* com.xiaozhi.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("在环绕之前");
        Signature signature = pjp.getSignature();
        System.out.println("获取信息=>"+signature);
        Object proceed = pjp.proceed();
        System.out.println("执行方法=>"+proceed);
        System.out.println("环绕后");
    }
}

在配置文件中,只需要加注解支持即可;


<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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
       
    
    
    <bean id="userServiceImpl" class="com.xiaozhi.service.UserServiceImpl"/>
    <bean id="myAnnotation" class="com.xiaozhi.annotation.MyAnnotation"/>

    
    <aop:aspectj-autoproxy/>

beans>

执行也可实现

在环绕之前
获取信息=>void com.xiaozhi.service.UserService.addUser()
========注解方式模拟执行前置========
添加用户
========注解方式模拟执行后置========
执行方法=>null
环绕后
在环绕之前
获取信息=>void com.xiaozhi.service.UserService.deleteUser()
========注解方式模拟执行前置========
删除用户
========注解方式模拟执行后置========
执行方法=>null
环绕后
在环绕之前
获取信息=>void com.xiaozhi.service.UserService.findUser()
========注解方式模拟执行前置========
查询用户
========注解方式模拟执行后置========
执行方法=>null
环绕后
在环绕之前
获取信息=>void com.xiaozhi.service.UserService.updateUser()
========注解方式模拟执行前置========
更新用户
========注解方式模拟执行后置========
执行方法=>null
环绕后

7. 整合Mybatis

官方文档mybatis-spring整合文档

https://mybatis.org/spring/zh/index.html

需要用到的包

<dependencies>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.4.6version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.22version>
        dependency>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.1.9.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>5.1.9.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.9.4version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatis-springartifactId>
            <version>2.0.6version>
        dependency>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.20version>
        dependency>
    dependencies>

先回顾一下Mybatis;

狂神说Java --- 记录Spring学习笔记_第45张图片

注意需要在pom.xml配置文件中配置资源指向地址


    <build>
        <resources>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
        resources>
    build>

创建工具类MybatisUtils;

public class MybatisUtils {
    private  static SqlSessionFactory sqlSessionFactory=null;
    //在调用工具类时就执行;
    static {
        try {
            //获取SqlSessionFactory对象;

            //获得配置文件;
            String resource = "mybatis-config.xml";
            //使用流读取资源;
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //加载资源流;
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //从 SqlSessionFactory 中获取 SqlSession;
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
    }
}

实体类User

//实体类User;
//使用lombok插件的注解;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;
}

持久层接口UserMapper

public interface UserMapper {
    //查询方法;
    public  List<User> findUser();
}

持久层配置文件UserMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xiaozhi.dao.UserMapper">


    <select id="findUser" resultType="user">
        select * from user;
    select>

mapper>

核心配置文件mybatis-config.xml


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    
    <properties resource="db.properties"/>
    
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    settings>

    
    <typeAliases>
        <package name="com.xiaozhi.pojo"/>
    typeAliases>

    
    <environments default="development">
        <environment id="development">
            
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            dataSource>
        environment>
    environments>

    
    <mappers>
        <mapper resource="com/xiaozhi/dao/UserMapper.xml"/>
    mappers>
configuration>

与数据库交互的属性文件db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username=root
password=123456

测试执行搭建环境

public class Test09 {
    @Test
    public void testFindUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //getmapper;
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> allUser = userMapper.findUser();
        //遍历结果;
        for (User user : allUser) {
            System.out.println(user);
        }
        //关闭sqlSession;
        sqlSession.close();
    }
}

测试成功;

狂神说Java --- 记录Spring学习笔记_第46张图片


7.1Spring整合 Mybatis的方式一

新建UserMapper接口的实现类UserMapperImpl

public class UserMapperImpl implements UserMapper{

    //操作是用sqlSession执行的;
    private SqlSessionTemplate sqlSession;

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

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

直接新建spring-dao.xml配置文件
编写数据源配置;sqlSessionFactory配置;SqlSessionTemplate配置;将实现类UserMapperImpl的bean也注入;


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

    

    <bean id="dataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    bean>

    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/xiaozhi/dao/UserMapper.xml"/>
        <property name="typeAliases" value="com.xiaozhi.pojo.User"/>
    bean>

    
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    bean>

    
    <bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
     bean>
beans>

这么一来,工具类MybatisUtils可直接省略;
且Mybatis的核心配置文件mybatis-config.xml也不用去写太多的配置


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"/>
    settings>
configuration>

测试执行

//整合Mybatis后;
    @Test
    public void testFindUser2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
       //获取bean
       UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        List<User> user = userMapper.findUser();
        for (User user1 : user) {
            System.out.println(user1);
        }
    }

输出

狂神说Java --- 记录Spring学习笔记_第47张图片


7.2 Spring整合 Mybatis的方式二

在写UserMapper接口的实现类UserMapperImpl时,可继承一个类SqlSessionDaoSupport;用来提供 SqlSession ;调用 getSqlSession()方法即可得到SqlSessionTemplate
省略了手动注入SqlSession

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    public List<User> findUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        return userMapper.findUser();
    }
}

且在配置bean时,用ref引用指向 赋值即可

<bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>

执行测试,查询成功

狂神说Java --- 记录Spring学习笔记_第48张图片


8.声明式事务

狂神说Java --- 记录Spring学习笔记_第49张图片

UserMapper接口再添加几个方法

public interface UserMapper {
    //查询方法;
    public  List<User> findUser();

    //添加用户
    public  void addUser(User user);

    //删除用户
    public void deleteUser(int id);
}

UserMapper.xml中编写sql语句


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xiaozhi.dao.UserMapper">


    
    <select id="findUser" resultType="user">
        select * from user;
    select>

    
    <insert id="addUser" parameterType="user">
        insert into user values (#{id},#{name},#{password});
    insert>

    
    <delete id="deleteUser" parameterType="_int">
      delete from user where id=#{id}
    delete>
mapper>

UserMapper接口的实现类UserMapperImpl

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{

    public List<User> findUser() {
        UserMapper userMapper=getSqlSession().getMapper(UserMapper.class);

        User user=new User(16,"石榴号","dsaasd");
        //添加用户;
        userMapper.addUser(user);
        //删除用户;
        userMapper.deleteUser(16);
        return userMapper.findUser();
    }

    public void addUser(User user) {
        getSqlSession().getMapper(UserMapper.class);
    }

    public void deleteUser(int id) {
        getSqlSession().getMapper(UserMapper.class);
    }
}

Mybatis的核心配置文件mybatis-config.xml


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"/>
    settings>
configuration>

sping-dao.xml配置文件;
编写数据源配置;sqlSessionFactory配置;SqlSessionTemplate配置;配置事务;


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

    

    <bean id="dataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/day2021_9_6_studyMybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    bean>

    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/xiaozhi/dao/UserMapper.xml"/>
        <property name="typeAliases" value="com.xiaozhi.pojo.User"/>
    bean>

    
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    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>
            <tx:method name="findUser" propagation="REQUIRED"/>
            <tx:method name="addUser" propagation="REQUIRED"/>
            <tx:method name="deleteUser" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED"/>
        tx:attributes>
    tx:advice>
    
    <aop:config>
        <aop:pointcut id="point" expression="execution(* com.xiaozhi.dao.*.*(..))"/>
        <aop:advisor pointcut-ref="point" advice-ref="txAdvice"/>
    aop:config>
    
beans>

还可以用一个spring容器的xml文件来合并其他的配置文件
applicationContext.xml


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

    
    <import resource="spring-dao.xml" />
    
    
    <bean id="userMapper" class="com.xiaozhi.dao.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    bean>
beans>

测试执行

public class Test10 {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        List<User> user = userMapper.findUser();
        for (User user1 : user) {
            System.out.println(user1);
        }
    }
}

一旦某个执行出现错误;不会将事务提交.


你可能感兴趣的:(部分总结笔记,spring,java)