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...)]

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中去配置声明式事务,我们就需要在代码中手动配置事务!
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!
相关推荐
小池先生33 分钟前
springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失
java·spring boot·后端
小蜗牛慢慢爬行2 小时前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
wm10432 小时前
java web springboot
java·spring boot·后端
龙少95434 小时前
【深入理解@EnableCaching】
java·后端·spring
溟洵6 小时前
Linux下学【MySQL】表中插入和查询的进阶操作(配实操图和SQL语句通俗易懂)
linux·运维·数据库·后端·sql·mysql
SomeB1oody8 小时前
【Rust自学】6.1. 定义枚举
开发语言·后端·rust
SomeB1oody9 小时前
【Rust自学】5.3. struct的方法(Method)
开发语言·后端·rust
啦啦右一10 小时前
Spring Boot | (一)Spring开发环境构建
spring boot·后端·spring
森屿Serien10 小时前
Spring Boot常用注解
java·spring boot·后端
盛派网络小助手12 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#