当前位置:   article > 正文

一篇文章带你学Spring从入门到精通_spring 学习

spring 学习

1.Spring框架概述

1.Spring简介

Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码

Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布

Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小

Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践

2.Spring三层架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWpFkRFy-1677231115454)(笔记图片/image-20230208173447318.png)]

3.Spring的优势

4.Spring的技术优点

•**非侵入式:**基于Spring开发的应用中的对象可以不依赖于Spring的API

•**控制反转:**IOC——Inversion of Control,指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们自己在代码中new创建。而使用 Spring 之后。对象的创建都是给了 Spring 框架。

•**依赖注入:**DI——Dependency Injection,是指依赖的对象不需要手动调用 setXX 方法去设置,而是通过配置赋值。

•**面向切面编程:**Aspect Oriented Programming——AOP

•**容器:**Spring 是一个容器,因为它包含并且管理应用对象的生命周期

•**组件化:**Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。

•**一站式:**在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上 Spring 自身也提供了表现层的 SpringMVC 和持久层的 Spring JDBC)

5.Spring重点概念

依赖注入(DI):

Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。

面向切面的程序设计(AOP):

Spring 框架的一个关键组件是面向切面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。

2.Spring体系架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYBAIr4r-1677231115456)(笔记图片/image-20230208173728424.png)]

1.核心容器

  1. spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
  2. spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
  3. context 模块建立在由 core和 beans 模块的基础上建立起来的,Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。
  4. spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。

2.数据访问-集成

JDBC 模块:提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。

ORM 模块:提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。

OXM 模块:提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。

JMS 模块:包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。

事务模块:为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理

3.Web应用服务

Web 模块:提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。

Web-MVC 模块:为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。

•**Web-Socket 模块:**为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。

•**Web-Portlet 模块:**提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。

4.其他模块

AOP 模块:提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

Aspects 模块:提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

Instrumentation 模块:在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

•**Messaging 模块:**为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

•**测试模块:**支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

3.构建Spring项目

1. idea搭建步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vfT3FzLB-1677231115457)(笔记图片/image-20230208162907671.png)]

2. 引入Spring依赖

<!-- spring核心包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.13</version>
        </dependency>

<!-- junt单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3.测试spring容器

在resouce目录下创建spring.xml配置文件

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

    <!-- User类的对象就交给Spring管理了 -->
    <bean id="user" class="com.huawei.SpringDemo2023.User" />

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在text/java 目录下创建测试类进行测试

//单元测试注解,代表可以直接运行该方法测试,需要依赖Junit类库
    @Test
    public void test1(){

        /**
         * 测试从Spring容器中取得指定的实例
         * 1.加载Spring配置文件
         * 2.取出Bean容器中的实例
         * 3.调用类中的方法
         */
        //1.加载Spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //2.取出Bean容器中的实例
        User user = (User)context.getBean("user");
        //3.调用方法
        user.say();

    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

4.Spring-IOC容器

1.ioc容器是什么?

简介

Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans

技术功能:

IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。

2.Spring提供的两种IOC容器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Es1gFSD-1677231115458)(笔记图片/image-20230208174226616.png)]

注意:

ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常不建议使用BeanFactory。BeanFactory 仍然可以用于轻量级的应用程序,如移动设备或基于 applet 的应用程序,其中它的数据量和速度是显著。

1.BeanFactroy容器

概述:

这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactory中被定义。

在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

加载容器配置的方法案例:

/**
         * BeanFactory创建实例步骤
         * 1.创建工厂类,加载Bean.xml配置文件
         * 2.通过工厂的方法获取指定对象实例
         * 3.实例对象调用方法
         */
        //1.创建工厂类,加载Bean.xml配置文件
        XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("Bean.xml"));
        //2.通过工厂的方法获取指定对象实例
        User user = (User) factory.getBean("user");
        //3.实例对象调用方法
        user.say();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2.Spring ApplicationContext 容器

概述:

Application Context 是 BeanFactory 的子接口,也被称为 Spring 上下文。

Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。

Applicationcontext容器提供了三种加载ioc容器的实现

ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。

FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径

WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

1.ClassPathXmlApplicationContext加载容器

//1. 加载配置文件,初始化容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //2. 通过同期的getBean方法获取容器中创建的对象
        User user = (User) context.getBean("user");
        System.out.println("2. 从容器中获取对象");
        user.say();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.FileSystemXmlApplicationContext 加载容器

/**
*第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的 FileSystemXmlApplicationContext *API 去生成工厂 bean
*/
ApplicationContext context = new FileSystemXmlApplicationContext
            ("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");
//第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
//来调用任何方法
      obj.getMessage();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3.bean的作用域

当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。

Spring 框架支持以下五个作用域,分别为 : singleton、prototype、request、session 和 global session

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j5GZpPdK-1677231115459)(笔记图片/image-20230209104632122.png)]

spring配置文件配置方法

<bean id="user" scope="prototype" class="com.huawei.SpringDemo2023.User" />
  • 1

4.bean的生命周期

Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁

1.bean的懒加载

当配置上lazy-init=true之后,表示该bean是懒加载模式,什么时候用到了该bean才会进行初始化。

它有两个值:true,false(默认)true表示该bean是懒加载,容器初始化的时候不进行初始化。

<bean id="user" lazy-init="false" class="com.huawei.SpringDemo2023.User" />
  • 1

2.bean的init-method方法(初始化回调)和destroy-method方法(销毁回调)

1. 初始化init-method方法
实现1:让类实现InitializingBean接口,重写afterPropertiesSet方法

spring.xml配置文件中,对应的bean标签是不需要配置init-method属性

bean类

public class User implements InitializingBean {

    private String name;

    public User(){
        System.out.println("我被实例了!");
    }

    public void say(){
        System.out.println("我被调用了!");
    }

    /**
     * 初始化回调-在对象创建完成之后
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("init初始化-afterPropertiesSet()");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

测试

//1. 加载配置文件,初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  • 1
  • 2
实现2(推荐):在bean标签中配置init-method方法

非侵入式的配置方法

spring配置文件中

<bean id="user" init-method="userInit"  class="com.huawei.SpringDemo2023.User" />
  • 1

在bean类中定义userInit方法

public class User{

    private String name;

    public User(){
        System.out.println("我被实例了!");
    }

    public void say(){
        System.out.println("我被调用了!");
    }

    /**
     * 初始化回调-在对象创建完成之后
     * @throws Exception
     */
    public void userInit(){
        System.out.println("userInit调用!");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
2. bean销毁回调-destroy方法
实现1:实现DisposableBean接口,重写destroy方法
public class User implements DisposableBean {

    private String name;

    public User(){
        System.out.println("我被实例了!");
    }

    public void say(){
        System.out.println("我被调用了!");
    }

    /**
     * 当对象销毁时回到
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        System.out.println("destroy-调用");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
实现2:在配置文件中添加
<bean id="user" destroy-method="userDes" class="com.huawei.SpringDemo2023.User" />
  • 1

bean类内

public class User{

    private String name;

    public User(){
        System.out.println("我被实例了!");
    }

    public void say(){
        System.out.println("我被调用了!");
    }

    /**
     * 当对象销毁时回到
     * @throws Exception
     */
    public void userDes(){
        System.out.println("userDes-调用");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

测试

//1. 加载配置文件,初始化容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        // registerShutdownHook 方法是关闭所有bean,触发销毁
        context.registerShutdownHook();
  • 1
  • 2
  • 3
  • 4
  • 5

3.前后置处理器类

作用:

​ 当容器中的bean调用的init-method方法回调时,在调用方法之前和之后添加操作

执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n9tGO5K8-1677231115460)(笔记图片/image-20230209140256399.png)]

创建一个前后置处理器类

package com.huawei.SpringDemo2023;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * 前后置处理器类
 * 2023/2/9
 */
public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     * 前置处理器
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("-----------1.前置处理器--------------");
        System.out.println("bean:"+bean);
        System.out.println("beanName:"+bean);

        return bean;
    }

    /**
     * 后置处理器
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("-----------2.后置处理器--------------");
        System.out.println("bean:"+bean);
        System.out.println("beanName:"+bean);
        return bean;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

在spring中配置前后置处理器类的实例

 <!-- User类的对象就交给Spring管理了 -->
    <bean id="user" init-method="userInit" class="com.huawei.SpringDemo2023.User" />
    <bean id="stu" init-method="initStu" class="com.huawei.SpringDemo2023.Student" />

    <!--    前后置处理器类 -->
    <bean id="myBeanPostProcessor" class="com.huawei.SpringDemo2023.MyBeanPostProcessor" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意:前后置处理器的触发即使不定义init方法也会触发,时机变为调用构造器前后

如果有多个前后置处理器类的实现,要实现Ordered接口实现getOrder方法

1.重写getOrder方法后,返回值值越小,执行优先级越高

2.执行优先级相同,根据Spring配置的文件中,配置bean的先后顺序作为优先级

/**
 * 前后置处理器类
 * 2023/2/9
 */
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {

    /**
     * 前置处理器
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("-----------1.MyBeanPostProcessor-前置处理器--------------");

        return bean;
    }

    /**
     * 后置处理器
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("-----------2.MyBeanPostProcessor-后置处理器--------------");
        return bean;
    }

    /**
     * 执行先后的顺序 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     * @return
     */
    @Override
    public int getOrder() {
        return 800;// 值越小执行优先级越高
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

4. bean属性的注入

调用bean类的set方法进行属性的注入

<!-- User类的对象就交给Spring管理了 -->
    <bean id="user" class="com.huawei.SpringDemo2023.User" >
        <property name="name" value="cxk" />
    </bean>
  • 1
  • 2
  • 3
  • 4
public class User{

    private String name;

    public User(){
        System.out.println("我被实例了!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("user-set方法调用-value:"+name);
        this.name = name;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5.bean定义继承

    <!-- 定义一个抽象模板 -->
    <bean id="templateA" abstract="true">
        <property name="name" value="123"></property>
    </bean>

    <!-- bean类通过parent属性继承  -->
    <bean id="user" class="com.huawei.SpringDemo2023.User" parent="templateA" >
		<!-- <property name="name" value="cxk" />-->
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5.Spring-依赖注入

1. 通过构造器注入的方法

被注入的类

public class TestEditor {
	// 需要spring注入的对象
    private SpellChecker spellChecker;

    public TestEditor(){
        System.out.println("TestEditor-实例化:无参构造器");
    }
	//通过有参构造器将要注入的对象创建的责任抛出(给springioc容器来操作)
    public TestEditor(SpellChecker spellChecker) {
        System.out.println("TestEditor-实例化:"+spellChecker);
        this.spellChecker = spellChecker;
    }

    public void testDI(){
        this.spellChecker.aa();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

要注入的类

public class SpellChecker {

    public void aa(){
        System.out.println("SpellChecker-AA");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

spring配置-构造器注入

<!-- 准备需要注入对象的实例 -->
   <bean id="spellChecker" class="com.huawei.SpringDemo2023.SpellChecker" />

    <!-- 要注入实例的类 -->
    <bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor">
        <!-- 将要注入的实例放入TestEditor类的有参构造器的第一个参数,如果有多个参数根据标签顺序注入 -->
        <!-- 当TestEditor加载时就会自动调用有参构造器,进行对象注入 -->
        <constructor-arg ref="spellChecker" />
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

1.构造器基础数据类型或String类型注入方法

如果你想要向一个对象传递一个引用,你需要使用 标签的 ref 属性,如果你想要直接传递值,那么你应该使用如上所示的 value 属性。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0k3jVP7n-1677231115462)(笔记图片/image-20230209150739808.png)]

通过type属性区分类型,基础数据类型直接写名称,引用类型写全限定名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-651Yzf0q-1677231115463)(笔记图片/image-20230209150742124.png)]

2. index属性值控制注入参数的顺序

index值从0开始,如:0代表第一个参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTn9oCAS-1677231115464)(笔记图片/image-20230209150916930.png)]

2.通过setter方法注入

配置文件

<!-- 准备需要注入对象的实例 -->
   <bean id="spellChecker" class="com.huawei.SpringDemo2023.SpellChecker" />

    <!-- 要注入实例的类 -->
    <bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor">
        <!-- 调用了spellChecker对应的setter方法实现注入 -->
       <property name="spellChecker" ref="spellChecker" />
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

要注入的类

public class TestEditor {

    private SpellChecker spellChecker;

    public SpellChecker getSpellChecker() {
        return spellChecker;
    }

    //setter方法就是提供给外部实现参数注入的方法
    public void setSpellChecker(SpellChecker spellChecker) {
        System.out.println("setter方法调用!");
        this.spellChecker = spellChecker;
    }

    public void testDI(){
        this.spellChecker.aa();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3.p-namesapce方法注入

新旧方式对比

旧的方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nuKE5M8w-1677231115464)(笔记图片/image-20230209164450002.png)]

新的方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oqNK2KDN-1677231115466)(笔记图片/image-20230209164452735.png)]

<!-- namespace方法会根据被注入的类自动调用构造器注入或setter方法注入 -->
<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor"
   p:spellChecker-ref="spellChecker"
/>
  • 1
  • 2
  • 3
  • 4

4. 内部bean注入

当需要注入实例时才编写bean标签配置实例的注入方式

setter方法内部bean注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2HvOYqxn-1677231115467)(笔记图片/image-20230209164615169.png)]

构造器内部bean注入

<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" >
    <constructor-arg name="cxk">
        <bean class="com.huawei.SpringDemo2023.SpellChecker" />
    </constructor-arg>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5

5.集合的注入

集合的注入类似内部bean的注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rpRYX0fp-1677231115467)(笔记图片/image-20230209164807138.png)]

四种类型注入案例:

被注入的类

1. list注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pbbxKxgJ-1677231115468)(笔记图片/image-20230209164917626.png)]

2.Set注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yk9B4awz-1677231115469)(笔记图片/image-20230209164920792.png)]

3.Map注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RTWpt5Dh-1677231115470)(笔记图片/image-20230209164924396.png)]

4.Properties注入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ci1IydTr-1677231115470)(笔记图片/image-20230209164928374.png)]

5.集合中混合数据注入(实例注入集合)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rbSKhhly-1677231115471)(笔记图片/image-20230209165001312.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dMsA3sLO-1677231115472)(笔记图片/image-20230209165004041.png)]

6.SpringBean的自动装配

Spring 容器可以在不使用和 元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。

1.自动装配模式

下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用元素的 autowire 属性为一个 bean 定义指定自动装配模式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hxCS8XSv-1677231115472)(笔记图片/image-20230209165048732.png)]

1.1装配模式-byName

这种模式由属性名称指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

要注入的类

public class TestEditor {

    private SpellChecker cxk;

    public SpellChecker getCxk() {
        return cxk;
    }
    
    // byName方法只会使用setter方法实现注入
    public void setCxk(SpellChecker cxk) {
        this.cxk = cxk;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

配置

<!-- 准备需要注入对象的实例 -->
<bean id="cxk" class="com.huawei.SpringDemo2023.SpellChecker" />

<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" autowire="byName"></bean>
  • 1
  • 2
  • 3
  • 4

1.2 装配模式-byType

这种模式由属性名称指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

要注入的类

public class TestEditor {

    private SpellChecker cxk;

    public SpellChecker getCxk() {
        return cxk;
    }

    // byType方法只会使用setter方法实现注入
    public void setCxk(SpellChecker cxk) {
        System.out.println("setter");
        this.cxk = cxk;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

配置

!-- 准备需要注入对象的实例 -->
<bean id="xxx" class="com.huawei.SpringDemo2023.SpellChecker" />

<bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" autowire="byType"></bean>
  • 1
  • 2
  • 3
  • 4

1.3 装配模式-constructor

这种模式与 byType 非常相似,但它应用于构造器参数。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。如果找到匹配项,它会注入这些 bean,否则,它会抛出异常。

要注入的类

public class TestEditor {

    private SpellChecker cxk;

    // constructor方法只会使用构造器方法实现注入
    public TestEditor(SpellChecker cxk) {
        System.out.println("构造器");
        this.cxk = cxk;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

配置

<!-- 准备需要注入对象的实例 -->
    <bean id="xxx" class="com.huawei.SpringDemo2023.SpellChecker" />

    <bean id="testEditor" class="com.huawei.SpringDemo2023.TestEditor" autowire="constructor"></bean>
  • 1
  • 2
  • 3
  • 4

7.Spring基于注解化的配置

目的:减少在xml中的复杂配置

1.使用方法-引入注解

<!-- 将所有Spring关于依赖注入的注解类实例化存放到ioc容器汇总 -->
    <context:annotation-config />
  • 1
  • 2

2.常见注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UhGdPsgu-1677231115473)(笔记图片/image-20230209171124594.png)]

1.@Required 注解

必填验证注解,@Required 注解应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。

spring版本5.3.9,注解被弃用,如果不填写,也不会报错

要注入的类

public class TestEditor {

    private SpellChecker cxk;

    
    public SpellChecker getCxk() {
        return cxk;
    }
    
    // 只能用于setter方法上
    @Required
    public void setCxk(SpellChecker cxk) {
        this.cxk = cxk;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

2. @Autowired 注释

@Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。

@Autowired 注释可以在 setter 方法中被用于自动连接 bean,就像 @Autowired 注释,容器,一个属性或者任意命名的可能带有多个参数的方法。

注意:1.该注解是默认带有类似@Required注解功能的,有必填验证

​ 2.要注入的类中,提供的有参构造器尽量提供一个无参构造器,因为spring实例对象需要调用构造器,万一出现构造器必需传值而spring没有实例可以注入就会抛出UnsatisfiedDependencyException异常

@Autowired(required=false)非必填验证

1.setter方法上使用
// 使用setter方法注入,装配方法根据byType规则装配
    @Autowired
    public void setCxk(SpellChecker cxk) {
        System.out.println("setter:"+cxk);
        this.cxk = cxk;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
2.属性上使用

你可以在属性中使用 @Autowired 注释来除去 setter 方法。当时使用 为自动连接属性传递的时候,Spring 会将这些传递过来的值或者引用自动分配给那些属性。

// 如果有构造器,则采用构造器的方式进行注入,如果没有则直接根据类型注入到属性中不调用setter方法
// 装配模式依旧使用bytype方法匹配
@Autowired
private SpellChecker cxk;
  • 1
  • 2
  • 3
  • 4
3.构造器上使用

你也可以在构造函数中使用 @Autowired。一个构造函数 @Autowired 说明当创建 bean 时,即使在 XML 文件中没有使用 元素配置 bean ,构造函数也会被自动连接。

// 注入方式使用构造器注入,匹配规则使用byType方法匹配
@Autowired
public TestEditor(SpellChecker cxk) {
    System.out.println("构造器:"+cxk);
    this.cxk = cxk;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.Qualifier注解-配合@Autowired 注释

作用: @Autowired 注释自动装配的基础上通过bean的id或name进行选择注入

spring配置文件

<bean id="textEditor" class="com.huawei.SpringDemo2023.TestEditor"></bean>

    <bean id="j1" class="com.huawei.SpringDemo2023.SpellChecker" >
        <property name="name" value="高启强" />
    </bean>

    <bean id="j2" class="com.huawei.SpringDemo2023.SpellChecker" >
        <property name="name" value="高启盛" />
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

要注入的类

public class TestEditor {

    @Autowired // 在byType的基础上选择
    @Qualifier("j1")// 选择bean的name或id
    private SpellChecker cxk;


    public void test(){
        System.out.println(this.cxk.getName());
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4.Spring-JSR250注解

1.@PostConstruct@PreDestroy
public class TestEditor {

    private SpellChecker cxk;

    /**
     * 替代了init-method配置,描述初始化回调方法
     */
    @PostConstruct
    public void testInit(){
        System.out.println("初始化!");
    }

    /**
     * 替代了destroy-method配置,描述销毁回调方法
     */
    @PreDestroy
    public void testDestory(){
        System.out.println("销毁!");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
2.@Resource注解
1. name属性定义

通过bean的id或name进行连线装配

<!-- 将所有Spring关于依赖注入的注解类实例化存放到ioc容器汇总 -->
<context:annotation-config />

<bean id="textEditor" class="com.huawei.SpringDemo2023.TestEditor"></bean>

<bean id="j1" class="com.huawei.SpringDemo2023.SpellChecker" >
    <property name="name" value="高启盛" />
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
public class TestEditor {

    @Resource(name="j1")
    private SpellChecker cxk;

    public TestEditor(){
        System.out.println("构造器:无参");
    }

    public TestEditor(SpellChecker cxk){
        System.out.println("构造器:有参"+cxk);
        this.cxk = cxk;
    }

    public SpellChecker getCxk() {
        return cxk;
    }

    public void setCxk(SpellChecker cxk) {
        System.out.println("setter");
        this.cxk = cxk;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
2.type属性定义

根据类型自动装配

public class TestEditor {

    // 注入的实例类型是SpellChecker类型以及子类
    @Resource(type = SpellChecker.class)
    private SpellChecker cxk;

    public TestEditor(){
        System.out.println("构造器:无参");
    }

    public TestEditor(SpellChecker cxk){
        System.out.println("构造器:有参"+cxk);
        this.cxk = cxk;
    }

    public SpellChecker getCxk() {
        return cxk;
    }

    public void setCxk(SpellChecker cxk) {
        System.out.println("setter");
        this.cxk = cxk;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
3.两种属性可以同时使用

先根据类型区分,在根据名称连接

@Resource(name = "j1",type = SpellChecker.class)
private SpellChecker cxk;
  • 1
  • 2

5.@Configuration 和 @Bean 注解

@Configuration: 标识这是一个配置bean实例的类(放在类声明上

@Bean: 标识一个返回实例对象的方法(放在方法声明上

作用:使用类和方法替代xml配置容器的方式

注意:使用类的方法配置,spring.xml文件中就可以不用编写bean标签加载实例了

配置类

package com.huawei.SpringDemo2023;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 容器配置类
 * 2023/2/10
 */
// 描述当前类是一个描述ioc容器配置的类---》等同于spring.xml配置文件
    // 想要获取当前类中的bean配置需要加载当前配置类
@Configuration
public class MyConfig {

    // <bean id="getSpellCheckerJ1" class="om.huawei.SpringDemo2023.SpellChecker" />
    // 被添加@Bean注解的方法返回值实例将添加到ioc容器中
    @Bean
    public SpellChecker getSpellCheckerJ1(){
        SpellChecker spellChecker = new SpellChecker();
        spellChecker.setName("高启盛");
        return spellChecker;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

测试

/**
 * 测试工具类
 * 2023/2/8
 */
public class TextClass {

    @Test
    public void text1(){

        //ApplicationContext
        System.out.println("1. 容器加载");
        //1. 加载配置类,初始化容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

        //传统的方法通过名称获取,此时传递的是方法的名称
        SpellChecker bean = (SpellChecker) context.getBean("getSpellCheckerJ1");

        // 通过bean方法的返回值类型获取实例
        //SpellChecker bean = context.getBean(SpellChecker.class);

        System.out.println(bean.getName());

    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

多配置类注册方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0MUl6Sjr-1677231115474)(笔记图片/image-20230210112309264.png)]

6.@Import 注解

@import 注解,导入另一个配置类的内容合并

注意:该注解只能使用在配置类声明上

配置类-1

@Configuration
@Import(MyConfig2.class)// config2导入到当前配置类
public class MyConfig {

    // <bean id="getSpellCheckerJ1" class="om.huawei.SpringDemo2023.SpellChecker" />
    // 被添加@Bean注解的方法返回值实例将添加到ioc容器中
    @Bean
    public SpellChecker getSpellCheckerJ1(){
        SpellChecker spellChecker = new SpellChecker();
        spellChecker.setName("高启盛");
        return spellChecker;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

配置类-2

@Configuration
public class MyConfig2 {

    @Bean
    public SpellChecker getSpellCheckerJ2(){
        SpellChecker spellChecker = new SpellChecker();
        spellChecker.setName("蔡徐坤");
        return spellChecker;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

测试

@Test
public void text1(){

    //ApplicationContext
    System.out.println("1. 容器加载");
    //1. 加载配置类,初始化容器
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

    //传统的方法通过名称获取,此时传递的是方法的名称
    SpellChecker bean = (SpellChecker) context.getBean("getSpellCheckerJ2");

    // 通过bean方法的返回值类型获取实例
    //SpellChecker bean = context.getBean(SpellChecker.class);

    System.out.println(bean.getName());

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

7.@Bean可以配置声明周期函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FBNye9JH-1677231115474)(笔记图片/image-20230210113036240.png)]

8.@Scope注解-Bean的作用域注解

默认范围是单实例,

但是你可以重写带有 @Scope 注解的该方法

@Scope(“prototype”)多实例,IOC容器启动创建的时候,并不会创建对象放在容器在容器当中,当你需要的时候,需要从容器当中取该对象的时候,就会创建。

@Scope(“singleton”)单实例 IOC容器启动的时候就会调用方法创建对象,以后每次获取都是从容器当中拿同一个对象(map当中)。

@Scope(“request”)同一个请求创建一个实例

@Scope(“session”)同一个session创建一个实例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mCt8gqxX-1677231115475)(笔记图片/image-20230210113350539.png)]

8.Spring-AOP

在每个类中有相同的业务代码,都可以使用aop解决

AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

为什么要使用AOP?

想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。

AOP术语

AOP 领域中的特性术语:

通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。

连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。

切点(PointCut): 可以插入增强处理的连接点。

切面(Aspect): 切面是通知和切点的结合。

引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。

织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。

4.使用配置AOP

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.8.RC3</version>
</dependency>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

1. 基于XML配置方法实现AOP

1.开启aop配置
<!-- AOP配置 -->
    <aop:config>
        ...
</aop:config>
  • 1
  • 2
  • 3
  • 4
2.定义个切面

切面是一整个aop的独立业务逻辑,需要定一个类来描述

配置

<aop:config>
    <!-- 描述一个切面(包含:连接点、通知的配置) -->
   <aop:aspect id="testAspect" ref="myAspect1"></aop:aspect>
</aop:config>

<!-- 配置切面的类 -->
<bean id="myAspect1" class="com.huawei.SpringDemo2023.aop.TestAspect" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

切面类

package com.huawei.SpringDemo2023.aop;

/**
 * 描述切面功能类
 * 配置通知方法
 * 2023/2/10
 */
public class TestAspect {

   ... 

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
3.定义切点

切点就是定义在哪个方法或访问哪些类时会触发aop操作的时机

切点表达式:

方法表达式以 * 号开始,标识我们不关心方法的返回值类型。然后我们指定了全限定类名和方法名。对于方法参数列表,我们使用 … 标识切点选择任意的play方法,无论该方法的入参是什么。多个匹配之间我们可以使用链接符 &&、||、!来表示 “且”、“或”、“非”的关系。但是在使用 XML 文件配置时,这些符号有特殊的含义,所以我们使用 “and”、“or”、“not”来表示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8hWp8n2Y-1677231115481)(笔记图片/image-20230210150729527.png)]

配置案例:

<!-- AOP配置 -->
    <aop:config>
        <!-- 描述一个切面(包含:连接点、通知的配置) -->
        <aop:aspect id="testAspect" ref="myAspect1">
            <!-- 描述一个切点 -->
            <aop:pointcut id="cut1" expression="execution(* com.huawei.SpringDemo2023.aop.Cat.catSay(..))" />
        </aop:aspect>
    </aop:config>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
4.定义通知

通知的作用:通过aop的方式,增强调用处前置、后置、返回、异常的回调功能

使用规则:

前置通知:方法调用前调用,必然调用

后置通知:方法调用后调用(返回值返回之前就调用),必然调用

异常后通知:只有切点方法异常才会触发,且出现异常后,返回后通知就不会被调用

返回后通知:只有切点方法正常返回值才会触发,如果异常就不会触发

环绕通知:一个方法可以实现前后置、异常、返回后通知,控制目标方法是否调用,改变方法的返回值,应用于复杂场景下的aop通知

​ 使用了环绕通知,建议不要使用其他通知类型

通知类型:

通知标识关键字描述
前置通知before在一个方法执行之前,执行通知。
后置通知after在一个方法执行之后,不考虑其结果,执行通知。
返回后通知after-returning在一个方法执行之后,只有在方法成功完成时,才能执行通知。
抛出异常后通知after-throwing在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
环绕通知around在建议方法调用之前和之后,执行通知。

通知的回调方法属于切面的定义,需要定义在切面类中

切面类:定义通知方法

package com.huawei.SpringDemo2023.aop;

/**
 * 描述切面功能类
 * 配置通知方法
 * 2023/2/10
 */
public class TestAspect {

    /**
     * 前置通知
     */
    public void beforeAdvice(){
        System.out.println("----1.前置通知");
    }

    /**
     * 后置通知
     */
    public void afterAdvice(){
        System.out.println("----2.后置通知");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

配置通知(以前置、后置通知为案例)

<!-- AOP配置 -->
    <aop:config>
        <!-- 描述一个切面(包含:连接点、通知的配置) -->
        <aop:aspect id="testAspect" ref="myAspect1">
            <!-- 描述一个切点 -->
            <aop:pointcut id="cut1" expression="execution(* com.huawei.SpringDemo2023.aop.Cat.catSay(..))" />
            <!-- 配置通知 -->
            <!-- 1.前置通知 -->
            <aop:before pointcut-ref="cut1" method="beforeAdvice" />
            <!-- 2.后置通知 -->
            <aop:after pointcut-ref="cut1" method="afterAdvice" />
        </aop:aspect>
    </aop:config>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
1.返回后通知

xml配置

<!-- 3.返回后通知 returning 定义一个接收方法返回值的形参,如果方法没有返回值注入null,有返回值注入方法的返回值 -->
<aop:after-returning pointcut-ref="cut1" method="afterReturning" returning="retValue" />
  • 1
  • 2

切面类中通知配置

/**
     * 返回后通知
     * retValue: 接收方法的返回值
     * 返回后通知只能得到切点方法的返回值,但是无法修改
     */
    public void afterReturning(Object retValue){
        System.out.println("---2.1 返回后通知");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
2.异常后通知

xml配置

<!-- 4.异常后通知 throwing 定义一个接收异常对象的形参 -->
            <aop:after-throwing pointcut-ref="cut1" method="afterThrowing" throwing="ex" />
  • 1
  • 2

切面配置

/**
     * 异常后通知
     * ex: 切点方法异常抛出后,抛出的异常对象
     */
    public void afterThrowing(Throwable ex){
        System.out.println(ex);
        System.out.println("--2.2 异常后通知");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
3.环绕通知

xml配置

<!-- 配置通知 -->
<aop:around pointcut-ref="cut1" method="around" />
  • 1
  • 2

切面类中配置的环绕通知方法

public Object around(ProceedingJoinPoint point){

        System.out.println("---1.前置通知");
        try {
            Object obj = point.proceed();// 让切点方法执行,obj是切入点方法的返回值,如果没有返回值则返回null
            System.out.println("---2.1 返回后通知");
        } catch (Throwable e) {
            System.out.println("---2.2异常后通知");
        }
        System.out.println("---2.后置通知");

        return "哈哈哈哈";// 返回值返回的就是切点调用方法的返回值,可以通过自定义的方法改变返回值
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
5.调用方法,触发AOP

定义切点会进入的目标类

public class Cat {

    public void catSay(){
        System.out.println("喵!!!!");
    }

    public void catSay(String name){
        System.out.println("喵2!!!!"+name);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

测试,当调用cat的catSay方法是否会触发aop

此时切点表达式为:execution(* com.huawei.SpringDemo2023.aop.Cat.catSay(…))

 @Test
    public void text1(){

        //ApplicationContext
        System.out.println("1. 容器加载");
        //1. 加载配置类,初始化容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        Cat bean = context.getBean(Cat.class);

        bean.catSay();

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

9.基于注解配置的自动包类扫描

使用原因:

前面的例子我们都是使用XML的bean定义来配置组件。在一个稍大的项目中,通常会有上百个组件,如果这些组件采用XML的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。

Spring2.5为我们引入了组件自动扫描机制,它可以在类路径底下寻找标注了**@Component、@Service、@Controller、@Repository注解**的类,并把这些类纳入进Spring容器中管理。

1.配置使用方法

1. 开启自动包类扫描

<context:component-scan base-package=“cn.itcast” />这个配置隐式注册了多个对注解进行解析处理的处理器,包括context:annotation-config/该配置注册的处理器,也就是说写了<context:component-scan base-package=“cn.itcast” />配置,就不用写context:annotation-config/配置了,此外base-package为需要扫描的包(含子包)。 在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类注册为bean

<!-- bean自动注入实例的扫描注解开启 -->
    <!-- 扫描com.huawei.SpringDemo2023的所有子包以及类带有@Component、@Service、@Controller、@Repository的类添加实例到ioc容器 -->
    <!-- 该配置自动将所有Spring关于依赖注入的注解都自动开启了 <context:annotation-config/> -->
    <!-- use-default-filters属性默认为true代表自动扫描报下所有带有@Component、@Service、@Controller、@Repository的类 -->
    <context:component-scan base-package="com.huawei.SpringDemo2023" />
  • 1
  • 2
  • 3
  • 4
  • 5

2. 在需要自动创建实例添加到ioc容器的类声明上添加注解

注解说明:

一般通用组件:@Component

控制器层类:@Controller

业务实现层类:@Service

案例:

@Component
public class Cat {

    public void catSay(){
        System.out.println("喵!!!!");
    }


    public void catSay(String name){
        System.out.println("喵2!!!!"+name);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

从容器获取

System.out.println("1. 容器加载");
        //1. 加载配置类,初始化容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        Cat bean = context.getBean(Cat.class);

        bean.catSay();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2. 指定(include-filter)/过滤(exclude-filter)扫描标签配置

另外context:component-scan还提供了两个子标签(1)context:include-filter(2)context:exclude-filter在说明这两个子标签前,先说一下context:component-scan有一个use-default-filters属性,该属性默认为true,这就意味着会扫描指定包下的全部的标有@Component的类,包含子注解@Service,@Reposity等,并注册成bean

1. context:incluce-filter

可以发现这种扫描的粒度有点太大,如果你只想扫描指定包下面的Controller,该怎么办?此时子标签context:incluce-filter

案例实现:

<context:component-scan base-package="com.huawei.*" use-default-filters="false">  
	<context:include-filter type="annotation"expression="org.springframework.stereotype.Controller"/>   
</context:component-scan> 

  • 1
  • 2
  • 3
  • 4

注意:

这里要注意:如果加上use-default-filters="false"则默认情况下是true,可能会出现扫描到非@Controller注解的类加载为bean,所以指定扫描注解一定要加上use-default-filters="false"配置。

2.context:exclude-filter

另外在我参与的项目中可以发现在base-package指定的包中有的子包是不含有注解了,所以不用扫描,此时可以指定context:exclude-filter来进行过滤,说明此包不需要被扫描

案例实现:

<context:component-scan base-package="com.huawei.*" use-default-filters="false">  
	<context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller"/>   
</context:component-scan> 
  • 1
  • 2
  • 3

3.总结

<context:exclude-filter>指定的不扫描
<context:include-filter>指定的扫描

  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/461416
推荐阅读
相关标签
  

闽ICP备14008679号