1,Spring

1.1,简介

image-20210427101058879

官网:https://spring.io/projects/spring-framework

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

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

maven:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.5</version>
</dependency>

1.2,优点

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

spring就是一个轻量级的控制反转(IOC)和面向切面编程的框架!

1.3,组成

image-20210405150337568

1.4,拓展

现代化的java开发(基于spring的开发)

image-20210405150421201

spring boot

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

spring cloud

  • spring cloud是基于springboot实现的

因为现在大多数公司都在使用spring boot进行快速开发,学习它的前提是需要完全掌握spring和springmvc

2,IOC理论推导

image-20210405181303622

image-20210405181315533

image-20210405181529333

3,HelloSpring

image-20210405184728127

package pojo;

public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

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

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

类型 变量名 =new 类型();
Hello hello=new Hello();

bean =对象 new Hello();

id=变量名
class=new 的对象
peoperty相当于给对象中的属性设置一个值
ref:引用spring容器中创建好的对象
value:具体的值,基本数据类型
-->

<bean id="hello" class="pojo.Hello">
    <property name="str" value="Spring"/>
</bean>

</beans>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Hello;

public class MyTest {
    public static void main(String[] args) {
        //获取spring上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在spring中管理了,我们要使用,直接去里面取出来就可以
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());

    }
}

image-20210405184815360

image-20210405184644918

4,IOC创建对象的方式

1,使用无参构造创建对象,默认

2,使用有参构造创建对象

​ 2.1,下标赋值

  <bean id="user" class="poio.User">

        <constructor-arg index="0" value="kim"/>
    </bean>

​ 2.2,参数类型(不建议使用,假如有多个相同类型的属性就不好操作)

<bean id="user" class="poio.User">
        <constructor-arg type="java.lang.String" value="kim"/>
    </bean>

​ 2.3,参数名

<bean id="user" class="poio.User">
        <constructor-arg name="name" value="kim"/>
    </bean>

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

5,spring配置

5.1,别名(alias)

    <bean id="user" class="poio.User">
        <constructor-arg name="name" value="kim"/>
    </bean>
    <alias name="user" alias="asdf"/>
public class MyTest {
    public static void main(String[] args) {
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        User user = (User) context.getBean("asdf");
        user.show();
    }
}

image-20210407163636590

5.2,Bean的配置

<!--
id:bean 的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的权限定名:包名+类名
name:也是别名,name更高级,可取多个别名

-->
    <bean id="user" class="poio.User" name="user2 u3,u4;u5">
        <constructor-arg name="name" value="kim"/>
    </bean>

5.3,import

一般用于团队开发使用,可以将多个配置文件,导入合并为一个,假设现在项目中有多个人开发,这几个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以用import,将所有人的beans.xml合并成一个总的!

image-20210407164553972

6,DI依赖注入

6.1,构造器注入

第三节已经实现

6.2,所有方式注入【重点】

依赖注入:set注入

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

【环境搭建】:

image-20210407171540529

package pojo;

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 + '\'' +
                '}';
    }
}

package pojo;

import java.util.*;

public class Student {
    private String name;
    private  Address address;
    private String[] books;
    private List<String> bobbys;
    private Map<String,String> cards;
    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> getBobbys() {
        return bobbys;
    }

    public void setBobbys(List<String> bobbys) {
        this.bobbys = bobbys;
    }

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

    public Map<String, String> getCards() {
        return cards;
    }

    public void setCards(Map<String, String> cards) {
        this.cards = cards;
    }

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

<?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.xsd">
    <bean id="address" class="pojo.Address">
        <property name="address" value="china"/>
    </bean>

<bean id="student" class="pojo.Student">
    <!--    1.普通值注入-->
    <property name="name" value="kim"/>
    <!--    2.Bean注入,ref-->
    <property name="address" ref="address"/>
    <!--    3.数组注入-->
    <property name="books">
        <array>
            <value>芭芭拉</value>
            <value>胡桃</value>
            <value>菲谢尔</value>
        </array>
    </property>
    <!--    4.List注入-->
    <property name="bobbys">
        <list>
            <value>唱歌</value>
            <value>埋七七</value>
            <value>中二</value>
        </list>
    </property>
    <!--    5.Map注入-->
    <property name="cards">
        <map>
            <entry key="银行卡" value="16346546574641"/>
            <entry key="电话" value="46784987"/>

        </map>
    </property>
    <!--    6.Set注入-->
    <property name="games">
        <set>
            <value>原神</value>
            <value>崩坏</value>
            <value>mhy</value>
        </set>
    </property>
    <!--    7.null值注入-->
    <property name="wife">
        <null/>
    </property>
    <!--    8.Properties key,value-->
    <property name="info">
        <props>
            <prop key="学号">2018123122</prop>
            <prop key="姓名">罗莎莉亚</prop>
            <prop key="性别"></prop>
        </props>
    </property>


</bean>

</beans>


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


    }
}

image-20210407171711589

6.3,拓展方式注入

可以使用p命名空间c命名空间进行注入

官方解释:

image-20210407173441058

package pojo;

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

    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 +
                '}';
    }
}

<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    p命名空间注入,可以直接注入属性的值:property-->
    <bean id="user" class="pojo.User" p:name="kim" p:age="18"/>
  <!-- c命名空间为构造器注入,需要在实体类中加入无参有参构造:constructor  -->
<bean id="user2" class="pojo.User" c:name="kim2" c:age="18"/>

</beans>
  @Test
    public  void  test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");
        User user = (User) context.getBean("user");
        User user2 = (User) context.getBean("user2");
        System.out.println(user);
        System.out.println(user2);
    }

image-20210407173325640

注意点:

p,c命名空间不能直接使用,需要先导入xml约束

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

6.4,Bean的作用域

image-20210409085226962

1,单例模式(spring默认机制)

image-20210409085647983

<bean id="user2" class="pojo.User" c:name="kim2" c:age="18" scope="singleton"/>

2,原型模式:每次从容器中get的时候,都会产生一个新的对象

image-20210409085635369

3,其余的request,session,application这些只能在web开发中使用到的。

7,Bean的自动装配

自动装配是spring满足bean依赖的一种方式,

spring会在上下文中自动寻找,并自动给bean装配属性

三种装配方式:

1,在xml中显示配置

2,在java中显示配置

3,隐式的自动装配bean【重要】

7.1,测试

测试环境搭建:一个人有两个宠物

image-20210409092024360

package pojo;

public class Cat {
    public   void shout(){
        System.out.println("喵~");
    }
}

package pojo;

public class Dog {
    public   void shout(){
        System.out.println("汪~");
    }
}

package pojo;

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 + '\'' +
                '}';
    }
}

<?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.xsd">
   <bean id="cat" class="pojo.Cat"/>
   <bean id="dog" class="pojo.Dog"/>

    <bean id="people" class="pojo.Person">
        <property name="name" value="kim"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>
</beans>
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Person;

public class MyTest {
   @Test
    public void test1(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       Person people = context.getBean("people", Person.class);
       people.getCat().shout();
       people.getDog().shout();

   }
}

image-20210409092140185

7.2,ByName

将上面的xml文件改成如下两种也可成功运行:

byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid

<?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.xsd">
   <bean id="cat" class="pojo.Cat"/>
   <bean id="dog" class="pojo.Dog"/>

    <bean id="people" class="pojo.Person" autowire="byName">
        <property name="name" value="kim"/>

    </bean>
</beans>

7.3,ByType

byType:会自动在容器上下文中查找,和自己对象属性类型相同的beanid

<?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.xsd">
   <bean  class="pojo.Cat"/>
   <bean id="dog132" class="pojo.Dog"/>

    <bean id="people" class="pojo.Person" autowire="byType">
        <property name="name" value="kim"/>

    </bean>
</beans>

7.4,小结

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

7.5,spring使用注解开发

使用注解须知:

1,导入约束:context约束

2,配置注解支持

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

    <context:annotation-config/>

</beans>

@Autowired

直接在属性上使用,也可以在set方法上使用

使用Autowired我们可以不用编写set方法,前提是你这个自动装配的属性在IOC(spring)容器中存在,且符合名字byname

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

image-20210409094934919

如果**@Autowired**自动装配的环境比较复杂,自动装配无法通过一个注解完成的时候,可以使用@Qualifier(value = “xxx”)去配合@Autowired使用。

public class Person {
    @Autowired
    private Cat cat;
    @Autowired
    @Qualifier(value ="dog111")
    private Dog dog;
    private  String name;
}
 <bean id="cat" class="pojo.Cat"/>
   <bean id="dog" class="pojo.Dog"/>
   <bean id="dog111" class="pojo.Dog"/>
    <bean id="people" class="pojo.Person" >

image-20210409095718898

@Resource和@Autowired区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过byname方式实现
  • @Resource默认通过byname方式实现,如果找不到名字,则通过bytype实现,如果两个都找不到就报错
  • 执行顺序不同

8,Spring使用注解开发

Spring4之后要使用注解开发,必须导入aop的包

image-20210409192251554

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

<?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
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!--    开启注解支持-->
    <context:annotation-config/>
    
</beans>

1,bean

2,属性如何注入


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

    public String name;

    //等价于 <property name="name" value="KIM"/>
    @Value("KIM")
    public void setName(String name) {
        this.name = name;
    }
}

3,衍生的注解

@Component有几个衍生注解,在web开发中,会按照mvc三层架构分层,功能都是等价的

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

4,自动装配

5,作用域

//等价于 <bean id="user" class="pojo.User"/>
@Component
@Scope("singleton")
public class User {

    public String name;

    //等价于 <property name="name" value="KIM"/>
    @Value("KIM")
    public void setName(String name) {
        this.name = name;
    }
}

6,小结

image-20210409194904378

9,使用Java的方式配置Spring

JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能。

image-20210409201715669

package pojo;

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

@Component
public class User {
    private  String name;

    public String getName() {
        return name;
    }
    @Value("KIM")
    public void setName(String name) {
        this.name = name;
    }

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


package config;

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

@Configuration
//这个也会被Spring容器托管,注册打哦容器中,因为它本事就是一个@Component
//@Configuration 代表这是一个配置类,和之前的beans.xml是一样的

@ComponentScan("java")
public class UserConfig {
    //注册一个bean,相当于之前写的一个bean标签,
    //这个方法的名字就相当于bean中的id属性
    //这个方法的返回值,就相当于bean标签中的class属性
    @Bean
    public User user() {
        return new User();//返回要注入到bean的对象
    }
}

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import pojo.User;
//这个也会被Spring容器托管,注册打哦容器中,因为它本事就是一个@Component
//@Configuration 代表这是一个配置类,和之前的beans.xml是一样的
@Configuration
@ComponentScan("java")
@Import(UserConfig2.class)
public class UserConfig2 {
    //注册一个bean,相当于之前写的一个bean标签,
    //这个方法的名字就相当于bean中的id属性
    //这个方法的返回值,就相当于bean标签中的class属性
    @Bean
    public User user() {
        return new User();//返回要注入到bean的对象
    }
}

import config.UserConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import pojo.User;

public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
        ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        User user = (User) context.getBean("user");
        System.out.println(user.getName());
    }
}

10,AOP

10.1,代理模式

这是SpringAOP的底层

image-20210410152954481

10.1.1,静态代理

角色分析:

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

image-20210410154546106

接口:

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

真实角色:

package demo01;

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子!");
    }
}

代理角色:

package demo01;

public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }

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

    @Override
    public void rent() {
        host.rent();
        seeHouse();
        fee();
        contact();
    }
    //看房
    public void seeHouse(){
        System.out.println("中介代理看房!");
    }
    //收费
    public  void  fee(){
        System.out.println("收中介费!");
    }
    //合同
    public void  contact(){
        System.out.println("签合同!");
    }
}

客户端访问角色:

package demo01;

public class Cilent {
    public static void main(String[] args) {
        //房东要租房子
        Host host = new Host();
        //代理,中介帮房东租房子,但中介要带有一些附属操作,看房子,签合同等等
        Proxy proxy = new Proxy(host);
        //你不用面对房东,直接找中介就可租房子了
        proxy.rent();

    }
}

image-20210410154651444

代理模式的好处:

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

缺点:

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

10.1.2,静态代理加深理解

aop:面向切面编程

image-20210410160045134

需求:

  • 在每一次做CRUD操作之前都进行日志记录
  • 要求不改动原有代码,符合“开闭原则”

image-20210410160130172

接口:

package demo02;

public interface UserService {
    public void add();
    public void del();
    public void update();
    public void query();
}

实现类:

package demo02;

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

    @Override
    public void del() {
        System.out.println("删除了一个用户");

    }

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

    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");

    }
}

测试类

package demo02;

public class Client {
    public static void main(String[] args) {
        UserServiceImpl service = new UserServiceImpl();


        UserServiceProxy proxy = new UserServiceProxy();

        proxy.setUserService(service);

        proxy.add();
        proxy.update();

    }
}

代理类(实现日志功能):

package demo02;

public class UserServiceProxy implements UserService{
    private  UserServiceImpl userService;

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

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void del() {
        log(("del"));
    userService.del();
    }

    @Override
    public void update() {
        log("update");
        userService.update();

    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }
    //日志方法
    public void log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}

image-20210410160500397

10.1.3,动态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决

  • 真实角色:被代理的角色

  • 代理角色:代理真实角色,代理之后一般会做一些附属操作

  • 客户:访问代理对象的人

  • 动态代理的代理类是动态生成的,不是我们直接写好的

  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

    • 基于接口–JDK动态代理【这里使用】
    • 基于类:cglib
    • java字节码实现:javasist

需要理解两个类:Proxy 代理、InvocationHander 调用处理程序

image-20210410165235587

接口

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

真实角色

package demo03;

public class Host implements Rent {
    @Override
    public void rent() {
        System.out.println("房东要出租房子!");
    }
}

ProxyInvocationHander类

package demo03;

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

//用这个类自动生成代理类
public class ProxyInvocationHander implements InvocationHandler {

    //被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

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


   //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //动态代理的本质,就是使用反射机制实现
        seeHouse();
        Object invoke = method.invoke(rent,args);
        fare();
        return null;
    }
    public void  seeHouse(){
        System.out.println("中介带看房子!");
    }
    public void  fare(){
        System.out.println("中介收中介费!");
    }
}
package demo03;

public class Client {
    public static void main(String[] args) {
        //真实角色
        Host host = new Host();
        //代理角色:现在没有
        ProxyInvocationHander pih = new ProxyInvocationHander();//这里的proxy是动态生成的,我们并没有写
        //通过调研程序处理角色来处理我们要调用的接口对象!
        pih.setRent(host);
        Rent proxy = (Rent) pih.getProxy();
        proxy.rent();

    }
}

image-20210410165441029

优化:

image-20210410165511778

接口:

package demo04;

public interface UserService {
    public void add();
    public void del();
    public void update();
    public void query();
}

接口实现类:

package demo04;

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

    @Override
    public void del() {
        System.out.println("删除了一个用户");

    }

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

    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");

    }
}

通用的动态代理类:

package demo04;

import demo03.Rent;

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

//用这个类自动生成代理类
public class ProxyInvocationHander implements InvocationHandler {

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

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

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


   //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //动态代理的本质,就是使用反射机制实现
        log(method.getName());
        Object invoke = method.invoke(target,args);
        return null;
    }

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

}
package demo04;

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService=new UserServiceImpl();
        //代理角色,不存在
        ProxyInvocationHander pih = new ProxyInvocationHander();
        pih.setTarget(userService);//设置要代理的对象
        //动态生成代理类
        UserService proxy = (UserService) pih.getProxy();
        proxy.add();
    }

}

image-20210410165700655

动态代理的好处:

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

10.2,AOP

image-20210411215139361

image-20210411215222979

image-20210411215246710

image-20210411215309469

Spring的方式实现aop:

需要导入以下包

    <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

image-20210411223542508

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

image-20210411222615086

public interface UserService {
    public void add();
    public void del();
    public void update();
    public void query();
}
package service;

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

    @Override
    public void del() {
        System.out.println("删除了一个用户!");

    }

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

    }

    @Override
    public void query() {
        System.out.println("查询了一个用户!");

    }
}
<?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
        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-->
    <bean id="userservice" class="service.UserServiceImpl"/>
    <bean id="log" class="log.log"/>
    <bean id="afterlog" class="log.AfterLog"/>

<!--    方式一:使用原生SpringAPI接口-->

<!--    配置aop:需要导入aop的约束-->
    <aop:config>
<!--        切入点:expression表达式 execution(要执行的位置) -->
        <aop:pointcut id="point" expression="execution(* service.UserServiceImpl.*(..))"/>
<!--    执行环绕增强-->
        <aop:advisor advice-ref="log" pointcut-ref="point"/>
        <aop:advisor advice-ref="afterlog" pointcut-ref="point"/>

    </aop:config>
</beans>
package log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class log implements MethodBeforeAdvice {
   //method:要执行的目标对象的方法
    //object:参数
    //o:目标对象
    public void before(Method method, Object[] objects, Object o) throws Throwable {

        System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
package log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"方式,返回结果为"+o);
    }
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;
import service.UserServiceImpl;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理的是接口
        UserService userservice = (UserService) context.getBean("userservice");

        userservice.add();

    }
}

image-20210411222738889

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

image-20210411224217412

package diy;

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

}
<!--  方式二:自定义类  -->
    <bean id="diy" class="diy.DiyPointCut"/>
    <aop:config>
<!--        自定义切面 ref要引用的类-->
        <aop:aspect ref="diy">
<!--            切入点-->
            <aop:pointcut id="point" expression="execution(* service.UserServiceImpl.*(..))"/>
<!--            通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

image-20210411224305837

方式三:使用注解实现

image-20210411230022179

package diy;

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 AnnotationPointCut {
    @Before("execution(* service.UserServiceImpl.*(..))")
    public  void  before(){
        System.out.println("=====方法执行前====");
    }
    @After("execution(* service.UserServiceImpl.*(..))")
    public void  after(){
        System.out.println("=====方法执行后====");
    }
    //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
    @Around("execution(* service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");

        System.out.println(jp.getSignature());

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

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

}
<!--    方式三-->
<bean id="annotationPointCut" class="diy.AnnotationPointCut"/>
<!--开启注解支持  JDK(默认 proxy-target-class="false")  cglib(proxy-target-class="true")-->
    <aop:aspectj-autoproxy proxy-target-class="false"/>

image-20210411225952978

11,Spring整合Mybatis

步骤:

1,导入相关jar包

  • junit
  • mybatis
  • mysql
  • spring相关
  • aop织入
  • mybatis-spring【new】
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.5</version>
    </dependency>
<!--    spring操作数据库还需要一个spring-jdbc的包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.5</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.5</version>
    </dependency>
 <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.16</version>
    </dependency>

</dependencies>

2,编写配置文件

3,测试

11.1,mybatis回顾

image-20210412160711499

image-20210412160731468

1,编写实体类

import lombok.Data;

@Data
public class User {
    private int id;
    private  String name;
    private  String pwd;

}

2,编写核心配置文件

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>
    <typeAliases>
        <package name="pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

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

3,编写接口

package dao;

import pojo.User;

import java.util.List;

public interface UserMapper {
    public List<User> selectUser();
}

4,编写Mapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user
    </select>
</mapper>

5,测试

import dao.UserMapper;
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 org.junit.Test;
import pojo.User;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {
    @Test
    public void  Test1() throws IOException {
        String resources="mybatis-config.xml";
        InputStream in = Resources.getResourceAsStream(resources);
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = sessionFactory.openSession(true);

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.selectUser();

        for (User user : userList) {
            System.out.println(user);
        }


    }
}

image-20210412160850158

如果期间出现:"1 字节的 UTF-8 序列的字节 1 无效。"的报错

将xml中的"UTF-8"都改为"UTF8"

11.2,mybatis-spring

官网:http://mybatis.org/spring/zh/index.html

方式一:

image-20210412164207926

1,编写数据源配置

2,sqlSessionFactory

3,SqlSessionTemplate

4,需要给接口加实现类

5,测试

package pojo;

import lombok.Data;

@Data
public class User {
    private int id;
    private  String name;
    private  String pwd;

}
<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    DataSource:使用spring的数据源替换mybatis的配置  c3p0  dbcp  druid
        这里用spring提供的jdbc
-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>


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

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

    </bean>


</beans>
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>
    <typeAliases>
        <package name="pojo"/>
    </typeAliases>

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

<!--    <import resource="spring-mvc.xml"/>-->


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

</beans>
package dao;

import pojo.User;

import java.util.List;

public interface UserMapper {
    public List<User> selectUser();
}
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user
    </select>
</mapper>
package dao;

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

import java.util.List;

public class UserMapperImpl implements UserMapper{
    //所有的操作,原来都使用sqlSession来执行,现在都用SqlSessionTemplate
   private SqlSessionTemplate sqlSession;

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

    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}
import dao.UserMapper;
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 org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.User;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {
    @Test
    public void  Test1() throws IOException {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }

    }
}

image-20210412164426633

方式二:

将上述代码修改:

image-20210412165645580

package dao;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import pojo.User;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{


    public List<User> selectUser() {
//        SqlSession sqlSession = getSqlSession();
//        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//        return mapper.selectUser(); 精简为一行如下

        return  getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}
<bean id="userMapper2" class="dao.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
import dao.UserMapper;
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 org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.User;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyTest {
    @Test
    public void  Test1() throws IOException {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }

    }
}

可以查询出相同的结果:

image-20210412165747889

12,声明式事务

12.1,回顾事务

  • 把一组业务当成一个业务来做,要么都成功,要么都失败。
  • 项目开发中非常重要,要确保完整性和一致性

事务的ACID原则:

  • 原子性,确保要么都成功,要么都失败
  • 一致性,
  • 隔离性
    • 多个业务可能操作用一个资源,防止数据损坏
  • 持久性
    • 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中

12.2,Spring中的事务管理

  • 声明式事务:AOP

  • 编程式事务:需要在代码中进行事务的管理(try… catch)

    image-20210413151859046

12.1中的例子修改为:

package dao;

import pojo.User;

import java.util.List;

public interface UserMapper {
    public List<User> selectUser();

    //添加一个用户
    public int addUser(User user);
    //删除一个用户
    public int delUser(int id);
}
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserMapper">
    <select id="selectUser" resultType="user">
        select * from mybatis.user
    </select>
    <insert id="addUser" parameterType="user">
        insert  into mybatis.user (id, name, pwd) values(#{id},#{name},#{pwd});
    </insert>
    <delete id="delUser" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>
</mapper>
package dao;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import pojo.User;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    public List<User> selectUser() {
        User user = new User(9, "胡桃", "123456");

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

        mapper.addUser(user);
        mapper.delUser(1);

        return mapper.selectUser();



        //      return  getSqlSession().getMapper(UserMapper.class).selectUser();
    }

    @Override
    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }

    @Override
    public int delUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).delUser(id);
    }
}
package pojo;

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

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

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

<!--    <import resource="spring-mvc.xml"/>-->



    <bean id="userMapper2" class="dao.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

</beans>
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>
    <typeAliases>
        <package name="pojo"/>
    </typeAliases>

</configuration>
<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">

<!--    DataSource:使用spring的数据源替换mybatis的配置  c3p0  dbcp  druid
        这里用spring提供的jdbc
-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>


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

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

    </bean>


<!--配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg name="dataSource" ref="dataSource" />
    </bean>
<!--结合AOP实现事务的织入-->
    <!--    配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        给哪些方法配置事务-->
<!--        配置事务的传播特性propagation【new】-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="query" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
<!--    配置事务切入-->
    <aop:config >
        <aop:pointcut id="txPointCut" expression="execution(* dao.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>
import dao.UserMapper;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.User;

import java.io.IOException;
import java.util.List;

public class MyTest {
    @Test
    public void  Test1() throws IOException {

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);

        List<User> userList = userMapper.selectUser();

        for (User user : userList) {
            System.out.println(user);
        }


    }
}

在spring-dao.xml中配置了声明式事务之后,如果一个方法中有一个操作出错,其他的操作都不会执行。比如将delete单词写错之后,插入的操作也不能实现。

注:本笔记于b站up主“遇见狂神说”
https://www.bilibili.com/video/BV1WE411d7Dv
处学习记录,仅供学习与参考

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐