Spring5,最全教程,带你认识IOC容器和AOP切面

1.Spring

1.1简介

  • Spring:春天----->给软件行业带来了春天!

  • 2002,首次推出了Spring框架的雏形:interface21框架!

  • Spring框架即以inteface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。

  • Rod Johnson,SpringFramework创始人,著名作者,很难想象Rod Johnson的学历,真的让人大吃一惊,他是悉尼大学博士,然而他的专业却不是计算机,而是音乐家

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

  • SSH :Struct2 + Spring + Hibernate

  • SSM:SpringMvc + Spring + Mybatis

官网:spring.io/projects/sp...

官方下载地址repo.spring.io/ui/native/r...

GitHub:github.com/spring-proj...

Maven:如果我们只导入spring的包有很多需要一个一个导入,我们可以导入更庞大的mvc的包,里面包含了spring

xml 复制代码
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

1.2优点

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

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

1.3组成

七大模块组成

1.4扩展

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

  • SpringBoot

    • 一个快速开发的脚手架
    • 基于SpringBoot可以快速的开发单个微服务
    • 预定大于配置
  • SpringCloud

    • SpringCloud是基于SpringBoot实现的

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

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

2.IOC理论推导

原来的架构

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

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

我们使用一个set接口实现,已经发生了革命性的变化

java 复制代码
private UserDao userDao;

public void setUserDao(UserDao userDao) {
    this.userDao = userDao; 
}
  • 之前,程序是主动创建对象!控制权在程序员手上
  • 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!

这种思想,从本质上解决了问题,我们程序员不用去管理对象的创建了,系统的耦合性大大降低,可以更加专注的在业务的实现上,这就是IOC的原型

在我们原来写的代码,每个模块都相互依赖,一个模块出错,全部都运行不了

我们使用IOC容器后的代码,由我们ICO来管理这些模块

未来的代码,每个模块都单独运行,互不影响

IOC本质

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

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

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

3.HelloSpring

给对象赋值

pojo

java 复制代码
package com.xh.pojo;

public class Hello {
    private String hello;

    public String getHello() {
        return hello;
    }

    public void setHello(String hello) {
        this.hello = hello;
    }

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

beans.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    使用Spring来创建对象,在Spring中这些都称为Bean
        类型 变量名 = new 类型();
        Hello hello = new Hello();

        id=变量名
        class=new 的新对象
        property 相当于给对象中的属性设置一个值!
-->
        <bean id="Hello" class="com.xh.pojo.Hello">
            <property name="hello" value="Spring"/>
        </bean>
</beans>

测试

java 复制代码
@Test
public void test1(){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Hello hello = (Hello) context.getBean("Hello");
    System.out.println(hello.toString());
}

赋值对象

这里指的是,我们通过xml的方式,给serviceImpl中的set方法注入dao的对象

dao

java 复制代码
public interface UserDao {
    void getuser();
}

dao实现类

java 复制代码
package com.xc.dao;

public class MysqlDaoImpl implements UserDao{
    public void getuser() {
        System.out.println("Mysql");
    }
}
java 复制代码
package com.xc.dao;

public class OracleImpl implements UserDao{
    public void getuser() {
        System.out.println("oracle");
    }
}

service

java 复制代码
package com.xc.service;

public interface UserService {
    void getuser();
}

service实现类

java 复制代码
package com.xc.service;

import com.xc.dao.UserDao;

public class UserServiceImpl implements UserService{
    private UserDao userDao;

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

    public void getuser() {
        userDao.getuser();
    }
}

beans.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    必须要实现set方法,底层就是调用的set方法-->
    <bean id="mysqlimpl" class="com.xc.dao.MysqlDaoImpl"/>
    <bean id="oracleimpl" class="com.xc.dao.OracleImpl"/>
    
    <bean id="userservice" class="com.xc.service.UserServiceImpl">
<!--        ref:引用上面spring已经创建好的对象
            value:写入基本的数据类型
-->
        <property name="userDao" ref="oracleimpl"/>
    </bean>

</beans>

测试

java 复制代码
@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    UserService userservice = (UserService) context.getBean("userservice");
    userservice.getuser();
}

4.IOC创建对象的方式

使用IOC创建对象的时候一定要定义构造器

通过IOC创建对象流程:

我们在new ClassPathXmlApplicatonContext(beans.xml)

的时候通过无参构造已经将我们配置文件中的bean创建到容器中(new 对象)实例化了

通过有参构造创建对象

xml 复制代码
<!--    方式一    通过无参构造创建对象-->
<bean id="user" class="com.kuang.pojo.User"></bean>

<!--    方式二,通过有参构造参数下标来赋值-->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg index="0" value="杨贵强"/>
    </bean>

<!--    方式三,通过有参构造参数类型创建对象-->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg type="java.lang.String" value="云朵"/>
    </bean>

<!--    方式四,通过有参构造参数顺序创建对象-->
    <bean id="user" class="com.kuang.pojo.User">
        <constructor-arg value="星辰"/>
    </bean>

一共有四中方法通过IOC创建对象

总结

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

5.Spring配置

别名

xml 复制代码
<!--    别名-->
<!--    我们可以给我们bean起一个别名,name对应我们需要起别名的id,alias对应我们别名名称-->
<!--    别名就是小名,我们在getbean的时候用大名还是小名都可以获取到对象-->
    <alias name="user" alias="user2"/>

Bean的配置

xml 复制代码
<!--
    id:bean的唯一标识符,也就是这个对象的名称
    class:bean对象所对应的全限定名:包名+类型
    name:也是别名,而且name可以同时取多个别名
-->
    <bean id="user" class="com.kuang.pojo.User" name="user2 user3,user4">
        <property name="name" value="星辰"/>
    </bean>

import

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

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

  • 张三
  • 李四
  • 王五
  • applicationcontext.xml
xml 复制代码
<import resource="beans.xml"/>
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>

使用的时候,直接使用总的配置就可以了

6.DI依赖注入

1.构造器注入

详情看4.IOC创建对象方式

2.Set方式注入【重点】

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

【环境搭建】

  1. 复杂类型

    java 复制代码
    package com.kuang.pojo;
    
    public class Address {
        private String address;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
  2. 证实测试对象

java 复制代码
package com.kuang.pojo;


import java.util.*;

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> car;
    private Set<String> games;
    private String wife;
    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> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCar() {
        return car;
    }

    public void setCar(Map<String, String> car) {
        this.car = car;
    }

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

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

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

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

    @Override
    public java.lang.String toString() {
        return "Student{" +
                "name=" + name +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", car=" + car +
                ", games=" + games +
                ", wife=" + wife +
                ", info=" + info +
                '}';
    }
}

ApplicationContext.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.kuang.pojo.Address">
        <property name="address" value="湖北省武汉市"/>
    </bean>

<!--    第一种普通值注入-->
    <bean id="student" class="com.kuang.pojo.Student">
<!--        普通set属性进行赋值-->
        <property name="name" value="星辰"/>
<!--        引用类型注入-->
        <property name="address" ref="address"/>
<!--        数组-->
        <property name="books">
            <array>
                <value>语文</value>
                <value>数学</value>
                <value>英语</value>
            </array>
        </property>
        <!--        list集合-->
        <property name="hobbys">
            <list>
                <value>苹果</value>
                <value>香蕉</value>
                <value>西瓜</value>
            </list>
        </property>
<!--        map集合-->
        <property name="car">
            <map>
                <entry key="ID" value="10000"/>
                <entry key="age" value="18"/>
            </map>
        </property>
<!--        set集合-->
        <property name="games">
            <set>
                <value>湖北</value>
                <value>北京</value>
                <value>上海</value>
            </set>
        </property>
<!--        properties集合-->
        <property name="info">
            <props>
                <prop key="湖北">武汉</prop>
                <prop key="山东">菏泽</prop>
                <prop key="河南">郑州</prop>
            </props>
        </property>
<!--        注入null-->
        <property name="wife">
            <null></null>
        </property>

    </bean>

</beans>

测试

java 复制代码
import com.kuang.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

3.拓展方式注入

C命名空间注入和B命名空间注入

P命名空间注入

xml 复制代码
<bean id="user" class="com.kuang.pojo.User" p:name="星辰" p:age="18"/>

<!--这里等价于下面注入,只是更简便了-->

<bean id="user" class="com.kuang.pojo.User">
    <property name="name" value="星辰"/>
    <property name="age" value="18"/>
</bean>

C命名空间注入

xml 复制代码
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">


<!--    c命名空间,是通过构造器注入 constructor-arg-->
    <bean id="user" class="com.kuang.pojo.User" c:age="18" c:name="xc"/>
</beans>

注意点

7.Bean的作用域

  • 单例模式(singleton)容器里面只存在一个相同的对象,用户多次new这个对象,都是拿的容器中同一个

    xml 复制代码
    <bean id="user" class="com.kuang.pojo.User" c:age="18" c:name="xc" scope="singleton"/>
  • 原型模式(prototype)用户new多少个对象,就创建多少个对象

    xml 复制代码
    <bean id="user" class="com.kuang.pojo.User" c:age="18" c:name="xc" scope="prototype"/>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c2Z3OGk9-1659404482191)([img.jyxcwl.cn/image-20220...](https://link.juejin.cn?target=http%3A%2F%2Fimg.jyxcwl.cn%2Fimage-20220301091100529.png "http://img.jyxcwl.cn/image-20220301091100529.png"))

7.Bean自动装配

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

在Spring中有三种装配的方式

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

测试

  1. 环境搭建
  • 一个人有两个宠物!
java 复制代码
package com.kuang.pojo;

public class Cat {
    public void shot(){
        System.out.println("miao~");
    }
}
java 复制代码
package com.kuang.pojo;

public class Dog {
    public void shot(){
        System.out.println("wang~");
    }
}
java 复制代码
package com.kuang.pojo;

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

    @Override
    public String toString() {
        return "person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + 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;
    }
}
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

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

    <bean id="person" class="com.kuang.pojo.person">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
        <property name="name" value="星辰"/>
    </bean>

</beans>
java 复制代码
import com.kuang.pojo.person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        person person = (com.kuang.pojo.person) context.getBean("person");
        //cat对象.方法
        person.getCat().shot();
    }
}
java 复制代码
miao~

自动装配(Autowire)

上面那些通过propert方式使用ref指定一个引用对象,很麻烦,所以就有了自动装配,bean自动帮我们设置ref中的引用对象

方式一

使用byname

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

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

    <bean id="person" class="com.kuang.pojo.person" autowire="byName">
        <property name="name" value="星辰"/>
    </bean>

</beans>
  1. 这里使用byname表示,
  2. 这里需要绑定的bean id 必须唯一

方式二

使用bytype

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

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

    <bean id="person" class="com.kuang.pojo.person" autowire="byType">
        <property name="name" value="星辰"/>
    </bean>

</beans>
  1. 这里bytype表示,绑定的是class类型,这里bean的id可以不要,但是class必须要唯一

总结

  • byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
  • bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

注解自动装配

@Autowired

他的功能跟我们autowire="bytype"执行的效果是一样的,

先更具byname来设置,如果byname找不到,那么就bytype寻找class

以前我们使用自动装配

现在注解装配,更简洁

@Resource

也是一个自动装配的注解

小结

@Resource和@Autowired区别:

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

8.spring使用注解开发

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

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXAts48z-1659404482196)(C:\\Users\\杨贵强\\AppData\\Roaming\\Typora\\typora-user-images\\image-20220301111000405.png)

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

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

<!--    开启注解支持-->
    <context:annotation-config/>
<!--    开启扫描包,这样使用注解的时候,才可以扫描包下的bean-->
    <context:component-scan base-package="com.kuang.dao"/>
</beans>

bean注解注入容器

pojo

java 复制代码
package com.kuang.dao;

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


@Component //等价于 //    <bean id="user" class="com.kuang.dao.User"/>
public class User {
    private String name="星辰";
}

test

java 复制代码
import com.kuang.dao.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
    @Test
    public void test1(){
        ApplicationContext Context = new ClassPathXmlApplicationContext("applicationcontext.xml");
        User user = (User) Context.getBean("user");
        System.out.println(user.getName());
    }
}

对象属性如何注入

java 复制代码
package com.kuang.dao;

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


@Component //等价于 //    <bean id="user" class="com.kuang.dao.User"/>
public class User {

    @Value("星辰")  // 等价于 <property name="name" value="星辰"/>
    private String name;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
java 复制代码
import com.kuang.dao.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
    @Test
    public void test1(){
        ApplicationContext Context = new ClassPathXmlApplicationContext("applicationcontext.xml");
        User user = (User) Context.getBean("user");
        System.out.println(user.getName());
    }
}

衍生注解

@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!

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

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

自动装配配置

xml 复制代码
@Autowired:自动装配通过类型然后名称
	如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
@Nullable	:字段标记了这个注解,说明这个字段可以为null
@Resource	:自动装配通过名称然后类型 【跟Autowired顺序相反】

作用域

java 复制代码
package com.kuang.dao;

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


@Component //等价于 //    <bean id="user" class="com.kuang.dao.User"/>
@Scope("prototype") //单例singleton,原型prototype
public class User {

    private String name="星辰";


    public String getName() {
        return name;
    }

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

小结

xml与注解:

  • xml更加万能,适用于任何场合!维护简单方便
  • 注解不是自己类使用不了,维护相对复杂

xml与注解最佳实践:

  • xml用来管理bean;
  • 注解只负责完成属性的注入@value
  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持和包扫描
xml 复制代码
<!--    开启注解支持-->
    <context:annotation-config/>
<!--    开启扫描包,这样使用注解的时候,才可以扫描包下的bean-->
    <context:component-scan base-package="com.kuang.dao"/>

9.使用java的方式配置Spring

我们现在要完全不使用spring的xml配置了,全部交给java来做

JavaConfig是spring的一个子项目,在spring4之后,成为了一个核心功能

pojo

java 复制代码
package com.kuang.pojo;

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

@Component   //等价于 <bean id="user" class="com.kuang.pojo.user" />
public class User {
    @Value("星辰")
    private String name;

    public String getName() {
        return name;
    }

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

configuration

java 复制代码
package com.kuang.config;

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


//这个也会spring容器托管,注册到容器中,因为他本来就是一个@Coponent
//@Config代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
public class Config1 {

    //注册一个bean,就相当于我们之前写的一个bean标签
    //这个方法的名字,就相当于bean标签中的id属性
    //这个方法的返回值,就相当于bean标签中的class属性
    @Bean
    public User getuser(){
        return new User();//就说返回要注入到bean的对象
    }
    
    /*
    
    <bean id="user" class="com.kuang.pojo.user">
    	<property name="name" value="星辰"/>
    </bean>
    
    <bean id=getuser class="com.kuang.dao.User">
    	<property name="getuser" ref="user"/>
   	</bean>
    */ 
        

}

测试

java 复制代码
import com.kuang.config.Config1;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    @org.junit.Test
    public void test1(){
        ApplicationContext context = new AnnotationConfigApplicationContext(Config1.class);
        User getuser = (User) context.getBean("getuser");
        System.out.println(getuser.getName());
    }
}

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

10.AOP

静态代理

租房流程

好处:

  1. 可以使真实角色操作更加纯粹,不用去关注一些公共的业务
  2. 公共也就交给代理角色!实现了业务的分工
  3. 公共业务发送扩展的时候,方便集中管理!

缺点:

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

角色分析

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作【例如在原有的方法上,增加日志】
  • 客户:访问代理对象的人!

没有引入代理

引入代理

抽象角色:房子

java 复制代码
package com.kuang.jingtai;

public interface zhufang {
    //共同租房的形式
    void zhufang();
}

房东

java 复制代码
package com.kuang.jingtai;

public class fangdong implements zhufang{
    //房东实现租房的接口
    public void zhufang() {
        System.out.println("成功租到房子");
    }
}

代理

java 复制代码
package com.kuang.jingtai;

public class daili implements zhufang{
    private fangdong fangdong;
    public daili() {
    }

    public daili(com.kuang.jingtai.fangdong fangdong) {
        this.fangdong = fangdong;
    }

    //找中介租房的时候,
    public void zhufang() {
        //代理可以做一些附加的格外事情,
        //交钱
        jiaoqian();
        //签合同
        hetong();
        //用户交完钱后和签完合同后,直接吧房东的房子给用户
        fangdong.zhufang();
    }

    public void jiaoqian(){
        System.out.println("交钱");
    }
    public void hetong(){
        System.out.println("签合同");
    }

}

java 复制代码
package com.kuang.jingtai;

public class wo {
    public static void main(String[] args) {
        //获取我们想租房的房东
        fangdong fangdong = new fangdong();
        //获取我们的中介
        daili daili = new daili(fangdong);
        //通过代理进行租房
        daili.zhufang();
    }
}

加深理解

我们想在原因的代码功能基础上增加日志功能!

java 复制代码
package com.kuang.demo1;

//业务接口
public interface service {
    void add();
    void delete();
    void update();
    void query();
}
java 复制代码
package com.kuang.demo1;

//业务实现类
public class serviceImpl implements service{

    public void add() {
        System.out.println("新增一个用户");
    }

    public void delete() {
        System.out.println("清除一个用户");
    }

    public void update() {
        System.out.println("修改一个用户");
    }

    public void query() {
        System.out.println("查询一个用户");
    }
}
java 复制代码
package com.kuang.demo1;

//代理类
public class dailiImpl implements service{
    private serviceImpl serviceimpl;

    public void setServiceimpl(serviceImpl serviceimpl) {
        this.serviceimpl = serviceimpl;
    }


    //我们可以代理业务实现,增加日志功能
    public void add() {
        log("add");
        serviceimpl.add();
    }

    public void delete() {
        log("delete");
        serviceimpl.delete();
    }

    public void update() {
        log("update");
        serviceimpl.update();
    }

    public void query() {
        log("query");
        serviceimpl.query();
    }

    public void log(String msg){
        System.out.println("执行了"+msg+"方法");
    }
}
java 复制代码
package com.kuang.demo1;

public class test {
    public static void main(String[] args) {
        //真实对象
        serviceImpl service = new serviceImpl();
        //代理对象
        dailiImpl daili = new dailiImpl();
        //通过set方法代理我们真实对象
        daili.setServiceimpl(service);
        //通过代理调用方法
        daili.query();
    }
}

动态代理

java 复制代码
package com.kuang.dongtai;

public interface Host {
    void zhufang();
}
java 复制代码
package com.kuang.dongtai;

public class fangdong implements Host{
    public void zhufang() {
        System.out.println("成功出租房子");
    }
}
java 复制代码
package com.kuang.dongtai;

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

public class invocationHandler implements InvocationHandler {

    //需要被代理的接口
    private Host host;

    public void setHost(Host host) {
        this.host = host;
    }

    //程序自动生成代理类
    public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(), host.getClass().getInterfaces(),this);
    }

    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态的本质就是通过反射机制实现的
        Object invoke = method.invoke(host, args);
        return invoke;
    }
}
java 复制代码
package com.kuang.dongtai;

public class test {
    public static void main(String[] args) {
        fangdong fangdong = new fangdong();
        invocationHandler invocationHandler = new invocationHandler();
        invocationHandler.setHost(fangdong);
        fangdong proxy =(fangdong)invocationHandler.getProxy();
        proxy.zhufang();
    }
}

实现AOP日志

AOP底层是基于动态代理实现的,动态代理的是接口

xml 复制代码
<!--        导入aop依赖-->
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

方式一

使用Spring自带的API接口实现

接口

java 复制代码
package com.kuang.service;

public interface UserService {
    void add();
    void delete();
    void update();
    void select();
}

实现类

java 复制代码
package com.kuang.service;

public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("增加了一个用户");
    }

    public void delete() {
        System.out.println("清除了一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void select() {
        System.out.println("查询了一个用户");
    }
}

日志

前置

java 复制代码
package com.kuang.aop;

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforeLog implements MethodBeforeAdvice {

    //前置增强
    //method:方法
    //objects:参数
    //o:目标对象
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName()+"执行了"+method.getName()+"方法");
    }
}

后置

java 复制代码
package com.kuang.aop;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterAdviceLog implements AfterReturningAdvice {
    //后置增强
    //o:返回值
    //method:方法
    //objects:参数
    //o1:目标对象
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println(method.getName()+"执行完毕"+"返回值"+o);
    }
}

配置类

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
">

    <!--先将我们对象全部注入到spring容器中-->
    <bean id="UserServiceImpl" class="com.kuang.service.UserServiceImpl"/>
    <bean id="AfterAdviceLog" class="com.kuang.aop.AfterAdviceLog"/>
    <bean id="BeforeLog" class="com.kuang.aop.BeforeLog"/>

<!--    使用aop:config 来给配置切入点日志-->
    <aop:config>
<!--        切入点,id=切入名称,expression:表达式= execution(修饰符 包名.类名.所以方法(所有参数)) -->
        <aop:pointcut id="service" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>

<!--        通知:前置增强和后置增强,advice-ref:日志类   pointcut-ref:切入点-->
        <aop:advisor advice-ref="BeforeLog" pointcut-ref="service"/>
        <aop:advisor advice-ref="AfterAdviceLog" pointcut-ref="service"/>
    </aop:config>


</beans>

execution表达式

方式二

自定义切面类,给写入点通知

自定义切面

java 复制代码
package com.kuang.utils;

public class log {
    public void Before(){
        System.out.println("执行方法前");
    }
    public void after(){
        System.out.println("执行方法后");
    }
}

自定义切面

xml 复制代码
    <aop:config>
<!--        自定义切面,ref 要引用的类,就说我们自定义的切面类的bean id-->
        <aop:aspect ref="diylog">
<!--            定义切入点-->
            <aop:pointcut id="log" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--            通知,前置和后置增强-->
            <aop:before method="Before" pointcut-ref="log"/>
            <aop:after method="after" pointcut-ref="log"/>
        </aop:aspect>
    </aop:config>

总结:

方式一:使用spring的API接口【主要SpringAPI接口实现】

方式二:自定义实现AOP【主要是切面定义】

使用注解实现

java 复制代码
package com.kuang.utils;

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;

//使用注解配置AOP

@Aspect//标志这是一个切面
public class anocation {

//    前置增强
    @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 point) throws Throwable {
        System.out.println("===环绕前===");
        Object proceed = point.proceed();//执行原本业务方法
        System.out.println("===环绕后===");
    }

}

applicationcontext.xml

xml 复制代码
<!--开启aop注解支持-->
    <aop:aspectj-autoproxy/>

结果

xml 复制代码
===环绕前===
方法执行前
增加了一个用户
===环绕后===
方法执行后

11.整合Mybatis

步骤:

  1. 导入相关依赖包
  • junt
  • springmvc
  • aspectjweaver
  • mysql
  • mybatis
  • spring-jdbc
  • mybatis-spring
  • lombok
  1. 编写xml配置文件
    • db.properties【数据库信息】
    • mybatis-config.xml【mybatis配置】
    • applicationcontext.xml【Spring配置】
  2. 测试

回忆Mybatis

pojo

java 复制代码
package com.kuang.pojo;

import lombok.Data;

@Data
public class user {
    private int id;
    private String name;
    private String password;
}

mapper

java 复制代码
package com.kuang.dao;

import com.kuang.pojo.user;

import java.util.List;

public interface UserMapper {
    List<user> queryUserList();
}

mybatis工具类

java 复制代码
package com.kuang.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
        }catch (Exception e){
            e.toString();
        }
    }

    public static SqlSession getSqlSession(){
       return sqlSessionFactory.openSession();
    }
}

数据库信息

properties 复制代码
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=0000

mybatis配置信息

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--    导入数据库-->
    <properties resource="db.properties"/>

<!--    开启别名-->
    <typeAliases>
        <package name="com.kuang.pojo.user"/>
    </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>

<!--    注册mapper-->
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>

</configuration>

test

java 复制代码
import com.kuang.dao.UserMapper;
import com.kuang.pojo.user;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class Test {
    @org.junit.Test
    public void test1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<user> users = mapper.queryUserList();
        for (user user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

整合方式一

pojo

java 复制代码
package com.kuang.pojo;

import lombok.Data;

@Data
public class user {
    private int id;
    private String name;
    private String password;
}

UserMapper

java 复制代码
package com.kuang.dao;

import com.kuang.pojo.user;

import java.util.List;

public interface UserMapper {
    List<user> queryUserList();
}

UsermapperImpl

java 复制代码
package com.kuang.dao;

import com.kuang.pojo.user;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper{
//    构造SqlSession
    private SqlSessionTemplate sqlSession;
//这里spring中的bean通过set方法进行注入
    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

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

Usermapper.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.dao.UserMapper">

<!--  数据库字段别名  -->
    <resultMap id="queryUserList_Map" type="com.kuang.pojo.user">
        <result property="password" column="pwd"/>
    </resultMap>

    <select id="queryUserList" resultMap="queryUserList_Map" parameterType="com.kuang.pojo.user">
        select * from user
    </select>
</mapper>

mybatis配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!--    开启别名-->
    <typeAliases>
        <package name="com.kuang.pojo.user"/>
    </typeAliases>
    
<!--    开启日志-->
<!--    <settings>-->
<!--        <setting name="" value=""/>-->
<!--    </settings>-->

<!--    注册mapper-->
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>

</configuration>

ApplicationContext.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    这里使用Spring自带的jdbc数据源-->
    <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"/>
        <property name="username" value="root"/>
        <property name="password" value="0000"/>
    </bean>

<!--    构造SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
<!--        引入mybtais整合-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

<!--    通过构造器获取SqlSession-->
    <bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>


<!--    添加bean-->
    <bean id="UserMapperImpl" class="com.kuang.dao.UserMapperImpl">
        <property name="sqlSession" ref="SqlSession"/>
    </bean>

</beans>

测试

java 复制代码
import com.kuang.dao.UserMapper;
import com.kuang.pojo.user;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class Test {
    @org.junit.Test
    public void test1(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        UserMapper userMapperImpl = (UserMapper) applicationContext.getBean("UserMapperImpl");
        List<user> users = userMapperImpl.queryUserList();
        for (user user : users) {
            System.out.println(user);
        }
    }
}

方式二

SqlSessionDaoSupport

java 复制代码
package com.kuang.dao;

import com.kuang.pojo.user;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

//通过基础SqlSessionDaoSupport简化代码,不用手动set方法去设置sqlSession
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{

    public List<user> queryUserList() {

        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.queryUserList();

//        return getSqlSession().getMapper(UserMapper.class).queryUserList();

    }
}
xml 复制代码
<!--    使用SqlSessionDaoSupport实现spring整合操作mybatis-->
    <bean id="UserMapperImpl2" class="com.kuang.dao.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

12.声明式事务

在不改变原有的代码,实现解耦,配置事务

spring中不允许手动回滚,需要配置事务的bean进行自动事务

回顾事务

  • 要么都成功,要么都失败!
  • 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎
  • 确保完整性和一致性

事务的ACID原则

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一个资源,防止数据瞬坏
  • 持久性
    • 事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化写到数据库中

Spring中的事务管理

pojo

java 复制代码
package com.kuang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;
}

dao

java 复制代码
package com.kuang.dao;

import com.kuang.pojo.User;

import java.util.List;

public interface UserMapper {
    List<User> queryUserList();
    int addUser(User user);
    int deleteUser(int id);
}

impl

java 复制代码
package com.kuang.dao;

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

import java.util.List;

public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate SqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        SqlSession = sqlSession;
    }

    public List<User> queryUserList() {

        UserMapper mapper = SqlSession.getMapper(UserMapper.class);
        try {
            mapper.addUser(new User(6,"xc","123456"));
            mapper.deleteUser(5);
            SqlSession.commit();
        }catch (Exception e){
            SqlSession.rollback();
        }
        return mapper.queryUserList();
    }

    public int addUser(User user) {
        return 0;
    }

    public int deleteUser(int id) {
        return 0;
    }
}

mapper.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.dao.UserMapper">
    <resultMap id="queryUserList_Map1" type="com.kuang.pojo.User">
        <result property="password" column="pwd"/>
    </resultMap>

    <select id="queryUserList" resultMap="queryUserList_Map1" parameterType="com.kuang.pojo.User">
        select * from user
    </select>

    <insert id="addUser" parameterType="com.kuang.pojo.User">
        insert into user set id=#{id},name=#{name},pwd=#{password}
    </insert>

<!--    这里故意写错,执行事务-->
    <delete id="deleteUser" parameterType="com.kuang.pojo.User">
        delet user where id=#{id}
    </delete>


</mapper>

mybatis-config.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>
</configuration>

applicationcontext.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
                http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
">

    <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"/>
        <property name="username" value="root"/>
        <property name="password" value="0000"/>
    </bean>

    <!-- 构建SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!-- 通过构造器创建sqlsession -->
    <bean id="SqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <!--注册bean-->
    <bean id="UserMapperImpl" class="com.kuang.dao.UserMapperImpl">
        <property name="sqlSession" ref="SqlSession"/>
    </bean>

<!--    通过构造器创建声明式事务对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg index="0" ref="dataSource"/>
    </bean>

<!--    结合AOP实现事务的织入-->
<!--    配置事务通知:-->
    <tx:advice id="tx" transaction-manager="transactionManager">
<!--        给那些方法配置事务-->
<!--        配置事务的传播特性:propagation=***-->
        <tx:attributes>
            <!--标记那些方法开启配置事务-->
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
<!--            read-only 只读-->
            <tx:method name="query" read-only="true"/>
        </tx:attributes>
    </tx:advice>

<!--    配置事务切面-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="txpointcut" expression="execution(* com.kuang.dao.*.*(..))"/>
        <!--通知-->
        <aop:advisor advice-ref="tx" pointcut-ref="txpointcut"/>
    </aop:config>

</beans>

test

java 复制代码
import com.kuang.dao.UserMapper;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapperImpl = (UserMapper) context.getBean("UserMapperImpl");
        List<User> users = userMapperImpl.queryUserList();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

报错,但是spring通过aop切面执行了事务。数据库数据没有改变

思考

为什么需要事务?

  • 如果不配置事务,那可能数据提交不一致的问题;
  • 如果不在Spring中去配置声明式事务,我们就需要在代码中手动配置事务!
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!
相关推荐
uzong1 小时前
技术故障复盘模版
后端
GetcharZp1 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程2 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研2 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi2 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国3 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy3 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack4 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt
bobz9655 小时前
pip install 已经不再安全
后端
寻月隐君5 小时前
硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端
后端·rust·github