1、spring

1.1 简介

官方文档https://docs.spring.io/spring/docs/5.2.6.RELEASE/spring-framework-reference/index.html

github下载地址https://github.com/spring-projects/spring-framework

  • spring:春天
  • 2002 年推出了spring框架的雏形:interface21框架
  • 2004年3月24日这一天,Spring Framework 1.0(以interface21为基础) final正式出现在我们的视野中
  • Rod Johnson Spring Framework创始人,著名作者。 Rod在悉尼大学不仅获得了计算机学位,同时还获得了音乐学位。更令人吃惊的是在回到软件开发领域之前,他还获得了音乐学的博士学位。
  • spring的理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有技术框架

SSH:struct2 + Spring + hibernate
SSM:springMvc + Spring + Mybaits

maven依赖:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>
原文的设计理念:

Design Philosophy
When you learn about a framework, it’s important to know not only what it does but what principles it follows. Here are the guiding principles of the Spring Framework:

  • Provide choice at every level. Spring lets you defer design decisions as late as possible. For example, you can switch persistence providers through configuration without changing your code. The same is true for many other infrastructure concerns and integration with third-party APIs.
  • Accommodate diverse perspectives. Spring embraces flexibility and is not opinionated about how things should be done. It supports a wide range of application needs with different perspectives.
  • Maintain strong backward compatibility. Spring’s evolution has been carefully managed to force few breaking changes between versions. Spring supports a carefully chosen range of JDK versions and third-party libraries to facilitate maintenance of applications and libraries that depend on Spring.
  • Care about API design. The Spring team puts a lot of thought and time into making APIs that are intuitive and that hold up across many versions and many years.
  • Set high standards for code quality. The Spring Framework puts a strong emphasis on meaningful, current, and accurate javadoc. It is one of very few projects that can claim clean code structure with no circular dependencies between packages.

1.2 优点

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

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

1.3 组成

1.4 spring 核心:IOC 与 AOP

在这里插入图片描述

1.5 拓展

  1. Spring Boot:

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

    • Spring Cloud 是基于 Spring Boot实现的

学习springboot的前提是,需要你掌握spring及springmvc 承上启下的作用

2、IOC

历史的业务实现方式

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

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!

我们使用一个Set接口实现

public class UserServiceImpl implements UserService {

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

    public void getUser() {
        // 业务层 service 调用 dao 层
        userDao.getUser();
    }
}

  • 之前,程序是主动创建对象!控制权在程序员手上
  • 使用set注入以后,程序不再具有主动性,而是变成了被动的接受对象

2.1 IOC本质

控制反转Ioc(Inversion of control)是一种设计思想
oop中 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制
控制反转后将对象的创建转移给第三方
获得依赖对象的方式反转了

官方说明图

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

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

2.2 beans 基本结构 (官方文档:配置bean)

以下示例显示了基于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="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>

该id属性是标识单个bean定义的字符串。(再回去到bean对象后使用getBean()方法传入id即可初始化该类)
该class属性定义Bean的类型,并使用完全限定的类名。( class=“com.ctra.pojo.Hello” 包含包名)

3、hellospring

3.1 控制反转

2个问题
Hello 对象是谁创建的?hello 对象是由Spring创建的
Hello 对象的属性是怎么设置的?hello 对象的属性是由Spring容器设置的

这个过程就叫控制反转
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的
反转:程序本身不创建对象,而变成被动的接收对象

3.2 依赖注入

依赖注入: 就是利用 set 方法来进行注入的
IoC是一种编程思想,由主动的编程编程被动的接收

通过 ClassPathXmlApplicationContext (擦皮鞋 CPX)来获取上下文对象
通过Spring 我们要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IoC,一句话搞定:Spring 来创建,管理,装配!

3.3 Spring:创建、管理、装配

我们彻底不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IoC就是:对象由Spring来创建、管理、装配

4、IoC创建对象的方式

4.1 类的初始化

new一个擦皮鞋,即:产生一个容器(上下文)对象,就会初始化所有注册到bean的类
ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);

bean的配置

 <bean id="userT" class="com.ctra.pojo.UserT" >
        <property name="name" value="zhangsan"/>
 </bean>

4.2 无参构造器 (默认)

使用无参构造创建对象(默认)

4.3 有参构造器

1)下标赋值(Constructor argument index)

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

2)参数类型赋值(Constructor argument type matching)-不建议使用

问题:如果2个参数都是String的类型,则没法判断传值给谁

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

3)参数名赋值(Constructor argument name)

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

5、Spring 配置

5.1 Alias 别名

<!-- 别名,如果添加了别名,我们也可以使用别名获取到这个对象-->
<alias name="fromName" alias="toName"/>

5.2 Bean的配置

    <!--
    id : bean 的唯一标识符,相遇对象名
    class : bean 对象所对应的全限定名: 包名+类型
    name:也是别名,而且比 name 用法更加灵活(支持多别名)
    -->

<bean id="userT" class="com.ctra.pojo.UserT" name="user2 u2,u3;t2">
   <property name="name" value="zhangsan"/>
</bean>

5.3 import

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

6、DI 依赖注入

6.1 构造器注入

如:4、IoC创建对象的方式

6.2 Set方式注入 ☆☆☆

1)依赖注入:就是 Set 注入

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

【环境搭建】

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

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
  1. 真实测试对象
package com.ctra.pojo;

import java.util.*;

public class Student {
    //    bean | ref | idref | list | set | map | props | value | null
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String, String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
}

3.beans.xml

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

    <bean id="student" class="com.ctra.pojo.Student">
        <property name="name" value="wangl"/>
    </bean>
</beans>

6.3 拓展方式注入

p命名空间 与 c命名空间
使用时需要导入约束条件
xmlns:p="http://www.springframework.org/schema/p" xmlns:p="http://www.springframework.org/schema/p"

p-namespace

依赖于 get、set方法 和 无参构造器(实体类)

bean 配置
user.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.ctra.pojo.User" p:age="12" p:name="wangl" />

</beans>

测试 :

	@Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("user.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user.toString());
    }

c-namespace

依赖于 有参构造函数(实体类)

没有在实体类中加入构造函数则无法注入

bean 配置
user.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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user2" class="com.ctra.pojo.User" c:name="zhangsan" c:age="99"/>

</beans>

测试:

    @Test
    public void test2() {
        ApplicationContext context = new ClassPathXmlApplicationContext("user.xml");
        User user = context.getBean("user2", User.class);
        System.out.println(user.toString());
    }

6.4 Bean作用域

ScopeDescription
singleton 单例模式(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype 原型模式Scopes a single bean definition to any number of object instances.
requestScopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
sessionScopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
applicationScopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocketScopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
  1. 单例模式(Spring默认机制)- 单线程
<bean id="user" class="com.ctra.pojo.User" p:age="12" p:name="wangl" scope="singleton"/>

测试:

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("user.xml");
        User user = context.getBean("user", User.class);
        User user1 = context.getBean("user", User.class);
        System.out.println(user==user1);
    }
输出: true
  1. 原型模式:每次从容器中getBean 的时候,都会产生一个新对象
<bean id="user" class="com.ctra.pojo.User" p:age="12" p:name="wangl" scope="prototype"/>

测试:

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("user.xml");
        User user = context.getBean("user", User.class);
        User user1 = context.getBean("user", User.class);
        System.out.println(user==user1);
    }
输出: false
  1. 其余的 request、session、application这些只能在web开发中用到

7、Bean 的自动装配

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

在Spring中有三种装配的方式

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

7.1 测试:正常装配

正常装配会将类通过 ref 引用到 property 中

bean 配置

<?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="dog" class="com.ctra.pojo.Dog"/>
    <bean id="cat" class="com.ctra.pojo.Cat"/>
    <bean id="people" class="com.ctra.pojo.People">
        <property name="name" value="zhangsa"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>

</beans>

测试:

import com.ctra.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        People people = context.getBean("people", People.class);
        people.getCat().shout();
        people.getDog().shout();

    }
}

实体类:Cat

package com.ctra.pojo;

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

实体类:Dog

package com.ctra.pojo;

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

实体类:People

package com.ctra.pojo;

public class People {
    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 "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

7.2 ByName 自动装配

bean配置

<?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="dog" class="com.ctra.pojo.Dog"/>
    <bean id="cat" class="com.ctra.pojo.Cat"/>
    
    <bean id="people" class="com.ctra.pojo.People" autowire="byName">
        <property name="name" value="zhangsa"/>
    </bean>

</beans>

注意上面的 dog 和 cat 的bean对象不能省略,否则报错空指针异常

7.3 byType 自动装配

bean配置

<?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="dog22" class="com.ctra.pojo.Dog"/>
    <bean id="cat11" class="com.ctra.pojo.Cat"/>

    <bean id="people" class="com.ctra.pojo.People" autowire="byType">
        <property name="name" value="zhangsa"/>
    </bean>

</beans>

总结:

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

7.4 使用注解实现自动装配 (官方文档)

jdk 1.5 支持的注解,Spring2.5 支持注解

  1. 导入约束 :context约束
  2. 配置注解的支持:context:annotation-config
<?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 自动装配

spring的注解

  1. 由上图可以看出: @Autowired 默认是 byType 的方式 自动装配的
  1. 由于@Autowired 默认是 byType 的方式,所以在bean的配置中重复定义的id只要包含该类(进而使用byName匹配)则不会报错
  1. 由于没有可匹配的name 则通过 @Qualifier(" ") 去匹配 对应的类

@Qualifier

public class People {
    @Autowired
    @Qualifier("cat11")
    private Cat cat;
    @Autowired
    @Qualifier("dog11")
    private Dog dog;
}

如果@Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用 @Qualifier(value=“xxx”) 去配置@Autowired的使用,制定一个唯一的bean对象注入

@Resource

jdk 中的 注解 (jdk11废除)

public class People {

    @Resource
    private Cat cat;

    @Resource(name = "dog11")
    private Dog dog;
}

总结:
@Resource 和 @Autowired 的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired 先通过byType的方式实现,再通过byname 的方式实现,如果俩个都找不到则报错
  • @Resource 默认通过 byname 的方式实现,如果找不到名字,则通过byType实现,如果俩个都找不到则报错
  • @Autowired 与 @Resource 除了顺序 基本相同

8、 使用注解开发

在 spring4 之后,要是用注解开发,必须要保证 aop的包导入了
在这里插入图片描述
使用注解需要导入 context 约束(<context:annotation-config/>),增加注解的支持

8.1 使用注解开发前提:context:component-scan

<!-- 指定要扫描的包,这包下的注解就会生效-->
<context:component-scan base-package="com.ctra.pojo"/>

8.2 衍生注解 (@Component、@Repository、@Service、@Controller)

@Component 注解 就等价于 <bean id="user" class="com.ctra.pojo.User"/>

@Component
public class User {
    public  String name = "wangl";
}

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

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

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

8.3 @Value (pojo的属性注入)

@Value 注解 就等价于 <property name="name" value="kuangshen"/>

@Component
public class User {

    // @Value 就等价于 <property name="name" value="kuangshen"/>
    // 就等价于 public String name ="wangl";
    public  String name ;

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

8.4 自动装配注解

  • @Autowired:自动装配 (先 byType 后 byName)
  • @Qualifier:如果Autowired 不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”)
  • @Nullable:字段标记了这个注解,说明这个字段可以为null
  • @Resource:自动装配(先 byName 后 byType)

8.5 作用域注解 @Scope

@Component
@Scope("singleton")
public class User {

    // @Value 就等价于 <property name="name" value="kuangshen"/>
    // 就等价于 public String name ="wangl";
    public  String name ;

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

8.6 小结:

xml 与 注解:

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

xml 与 注解 最佳实践:

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

9、使用Java的方式配置Spring

我们现在要完全不适用Spring的xml配置了,全权交给java来做

9.1 @Bean 与 @Configuration

@Bean方法将在@Configuration类中声明,以确保始终使用“完全”模式,因此将该方法引用将重定向到容器的生命周期管理。这样可以防止@Bean通过常规Java调用意外地调用相同的 方法,从而有助于减少在“精简”模式下运行时难以追查的细微错误。

package com.ctra.config;

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

// @Configuration 代表这是一个配置类,就和我们之前看的 beans.xml
@Configuration
public class MyConfig {
    // 注册一个 bean,就相当于我们之前写的一个 bean 标签
    // 这个方法的名字,就相当于bean标签中的id属性
    // 这个方法的返回值,就相当于bean标签中的class属性
    @Bean
    public User getUser(){
        // 由于这里创建了一个 user对象,所以可以不用在User类中使用 @Component
       return new User();
    }

}

测试:

import com.ctra.config.MyConfig;

import com.ctra.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class myTest {

    public static void main(String[] args) {
        // 通过纯注解的方式获得上下文
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser.getName());
        System.out.println(getUser.toString());

    }
}

10、 代理模式

为什么要学习代理模式?
这就是SpringAOP的底层 【SpringAOP 和SpringMVC】
代理模式分类:

  • 动态代理
  • 静态代理

10.1 静态代理

角色分析:

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

代码步骤:

  1. 接口
package com.ctra.staticproxy;
// 接口
public interface ITeacherDao {
    // 授课方法
    void teach();
}

  1. 被代理角色
package com.ctra.staticproxy;
// 被代理的类
public class TeacherDao implements ITeacherDao {
    public void teach() {
        System.out.println("老师授课中");
    }
}

  1. 代理角色
package com.ctra.staticproxy;

public class TeacherDaoProxy implements ITeacherDao {

    private ITeacherDao target; // 目标对象,通过接口来聚合

    public TeacherDaoProxy(ITeacherDao target) {
        this.target = target;
    }

    public void teach() {
        System.out.println("begin...");
        target.teach();
        System.out.println("end...");
    }
}

  1. 客户端(访问)
package com.ctra.staticproxy;

public class Test {
    public static void main(String[] args) {
        // 被代理对象
        TeacherDao teacherDao = new TeacherDao();

        // 代理
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);

        // 通过代理对象,调用到被代理对象的方法
        teacherDaoProxy.teach();
    }
}

代理模式的好处:

  • 可以是真实角色的操作更加纯粹!不用去关注一些公共的业务
  • 公共也就交给代理角色,是现在业务的分工
  • 公共业务发证拓展的时候,方便集中管理

缺点:

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

10.2 动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为俩大类:基于接口的动态代理,基于类的动态代理
    • 基于接口 jdk 动态代理【我们在这里使用】
    • 基于类: cglib
    • java字节码实现:javasist

Proxy类 与 InvocationHandler接口

需要了解两个类:都为java.lang.reflect
Proxy:代理类
InvocationHandler:调用处理程序(实现的接口 )

动态代理的好处:

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

11、 AOP

11.1 什么是AOP

11.2 AOP在Spring中的作用

提供声明式事务;允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如:日志、安全、缓存、事务 等等。。
  • 切面(ASPECT):横切关注点 被模块化的特殊对象。即:它是一个类
  • 通知(Advice):切面需要完成的工作。即:他是类中的一个方法
  • 目标(Target):被通知对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 切入点(PointCut):切面通知 执行的“地点”的定义
  • 连接点(JointPoint):与切入点匹配的执行点

11.3 使用Spring实现AOP

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

		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

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

MethodBeforeAdvice

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

方式三:使用注解实现

12、spring 整合 Mybatis 步骤

这一小结的模块,已经被我单独拿出一篇文章,传送门:
spring 整合 MyBatis (详细说明Mybatis被替换的逐一过程):https://blog.csdn.net/wanglei19891210/article/details/106993851

一、回忆 Mybatis

步骤:

1、导入相关jar包 (maven)

仓库依赖API :https://blog.csdn.net/wanglei19891210/article/details/106898789

  • junit
  • mybatis
  • mysql数据库
  • spring相关的
  • aop织入
  • mybatis-spring【new】
2、IDEA 链接数据库

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、mybatis核心配置文件

就是连接数据库配置
在resources 中创建 mybatis-config.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 核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
            <!-- 事务管理-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&amp;useSSL=false&amp;userUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="wl86662165"/>
            </dataSource>
        </environment>
    </environments>

</configuration>
4、创建 pojo 包与实体类

在java 下创建 pojo 包,然后创建User类,然后粘贴如下内容

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private Integer id;
    private String pwd;
}
5、创建 mapper(dao) 包与对应实体类的 mapper接口 UserMapper

在java 下创建 与pojo同级的mapper包,然后创建UserMapper接口,然后粘贴如下内容

public interface UserMapper {
    public List<User> getUserList();
}
6、创建 mapper(dao) 包下 xml配置文件UserMapper.xml

在java 下创建 与pojo同级的mapper包,然后创建UserMapper接口,然后粘贴如下内容

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ctra.mapper.UserMapper">
    <select id="getUserList" resultType="user">
        select * from  mybatis.user
    </select>
</mapper>

这里再回顾一下 namespace 和 id的用法,其他的CRUD操作详见:
MyBatis 全网最通俗易懂的教程(2020年、非常详细)

  • < mapper> namespace=“com.ctra.mapper.UserMapper” 绑定UserMapper接口
  • id:为接口对应方法名
7、核心配置文件,映射Mapper的xml

在第三点的核心配置文件内加入 mapper 映射xml

<!-- 如上 第3点的核心配置文件-->
<environments default="development">
    <environment id="development">
        <!-- 事务管理-->
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            ...
        </dataSource>
    </environment>
</environments>


<!-- 新增核心配置文件的 mapper 关系映射-->
<mappers>
    <mapper class="com.ctra.mapper.UserMapper"/>
</mappers>
8、测试

在 Test 下创建 MyTest.java 程序,然后粘贴如下内容

void test() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); 
    SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession session = build.openSession(true);
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> userList = mapper.getUserList();
    for (User user : userList) {
        System.out.println(user);
    }
    session.close();
}

二、 Mybatis-spring (整合篇,非独立创建)

什么是 MyBatis-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException。最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。
在这里插入图片描述

1、安装
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.0.5</version>
</dependency>
2、bean 配置文件

就是连接数据库配置
在resources 中创建 spring-dao.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">

</beans>
3、bean 配置文件-整合:dataSource(原:核心配置xml)

前提:需要maven依赖 :spring-jdbc 或 c3p0

dataSource -> DriverManagerDataSource ->JDBC
dataSource -> ComboPooledDataSource ->c3p0

在resources 中 spring-dao.xml 的 beans 中添加如下代码

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

    <!--  DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
            我们这里使用Spring 提供的JDBC:org.springframework.jdbc.datasource-->
    <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?serverTimezone=UTC&amp;useSSL=false&amp;userUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="wl86662165"/>
    </bean>

</beans>
4、bean 配置文件-整合:sqlSessionFactory(原:测试)

SqlSessionFactoryBean
在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory 的。 而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建。

在resources 中 spring-dao.xml 的 beans 中添加如下代码

<!-- sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 加载数据源 -->
    <property name="dataSource" ref="dataSource"/>
    <!-- 绑定mybatis配置文件-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations" value="classpath:com/ctra/mapper/*.xml"/>
</bean>
5、bean 配置文件-整合:sqlSession(原:测试)

使用 SqlSession
在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession。一旦你获得一个 session 之后,你可以使用它来执行映射了的语句,提交或回滚连接,最后,当不再需要它的时候,你可以关闭 session。使用 MyBatis-Spring 之后,你不再需要直接使用 SqlSessionFactory 了,因为你的 bean 可以被注入一个线程安全的 SqlSession,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。

在resources 中 spring-dao.xml 的 beans 中添加如下代码

<!-- sqlSessionTemplate:就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <!-- 只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
6、mapper(dao) 包下新增实现类 mapperImpl

由于spring接管UserMapper对象,但是mybatis无法自动创建(sqlsession)
在 mapper 包下新增 UserMapperImpl.java 文件,添加如下代码

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

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

    public List<User> getUserList() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUserList();

    }
}
7、bean 配置文件-整合:将新增的mapperImpl 实现类,注册到bean

配置UserMapperImpl的bean,通过property 属性,将sqlSession注入到UserMapperImpl实现类中
添加如下代码

<!--    将实现类注入到bean中-->
<bean id="userMapper" class="com.ctra.mapper.UserMapperImpl">
    <property name="sqlSession"  ref="sqlSession"/>
</bean>
8、测试

getBean() 中的 mapper为上面mapper实现类在bean注册的id名

@Test
void test2() throws IOException {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
    for (User user : userMapper.getUserList()) {
        System.out.println(user);
    }
}

三、SqlSessionDaoSupport

SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法,就像下面这样:

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
  public User getUser(String userId) {
    return getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}

在这个类里面,通常更倾向于使用 MapperFactoryBean,因为它不需要额外的代码。但是,如果你需要在 DAO 中做其它非 MyBatis 的工作或需要一个非抽象的实现类,那么这个类就很有用了。

SqlSessionDaoSupport 需要通过属性设置一个 sqlSessionFactory 或 SqlSessionTemplate。如果两个属性都被设置了,那么 SqlSessionFactory 将被忽略。

假设类 UserMapperImpl 是 SqlSessionDaoSupport 的子类,可以编写如下的 Spring 配置来执行设置:

新建 UserMapperImpl2

// 使用 SqlSessionDaoSupport 简化 获取sqlsession的注入操作
// 但是 SqlSessionDaoSupport 的父类需要注入
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    public List<User> getUserList() {
//        SqlSession session =getSqlSession();
//        UserMapper mapper = session.getMapper(UserMapper.class);
//        return mapper.getUserList();

        // 上下等价

        //        简化成一句话
        return getSqlSession().getMapper(UserMapper.class).getUserList();
    }
}

13、声明式事务

13.1 回顾事务

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

13.2 事务的ACID原则

  • 原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  • 一致性(Consistency):事务前后数据的完整性必须保持一致。
  • 隔离性(Isolation):事务之间要相互隔离。
  • 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

13.2 spring中的事务管理

声明式事务

在 bean.xml中的配置

    <!---=================开启事务===========================-->
    <!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--    AOP实现事务的织入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        给那些方法配置事务-->
<!--        配置事务的传播特性:new propagation-->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/> <!--propagatio:广播-->
        </tx:attributes>
    </tx:advice>

<!--    配置事务的切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.ctra.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>

编程式事务

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐