快速上手Spring注解、SpringAop

1 Spring 注解的使用

1 IOC 的概念

IOC(Inversion of Control):控制反转。

  • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。通俗的讲就是"将new对象的权利交给Spring,我们从Spring中获取对象使用即可"

Spring技术对 IOC 思想进行了实现

  • Spring提供了一个容器,称为IOC容器,用来充当IoC思想中的"外部"
  • IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean

DI(Dependency Injection):依赖注入

  • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。

2 使用简单的案例实现注解的使用

案例的代码文件的结构:

(1)dao层:

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

public interface BookDao {
    void saveBook();
}

(2)service层:

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

public interface BookService {
    void insertBook();
}

(3)其他实现类

@Configuration :注解用于标记一个类为配置类,表示该类包含Bean的定义。

@ComponentScan :告诉Spring 哪个packages 的用注解标识的类 会被spring自动扫描并且装入bean容器。

java 复制代码
@Configuration //标记该类为spring配置类
@ComponentScan({"com.xbf.dao","com.xbf.service"})
//如果扫描多个类,形如:
// @ComponentScan({"a", "b"})
//简单理解就是,传入一个静态数组
public class SpringConfig {

}

@Componet : 在Spring框架中,@Component注解是一个非常核心的概念,它用于将类标记为Spring容器中的一个Bean。这个注解告诉Spring,当应用启动时,需要在ApplicationContext中创建这个类的一个实例。这个过程是自动的,不需要显式编写代码来创建对象。

java 复制代码
@Component
public class BookDaoImpl implements BookDao {
    @Override
    public void saveBook() {
        System.out.println("我是BookDaoImpl类的saveBook()方法");
    }
}

@Autowired :在Spring框架中,@Autowired注解是实现依赖注入(DI)的重要工具。它可以自动地将定义好的Bean注入到Spring容器中的其他Bean中。这个注解可以用于成员变量、方法和构造函数上,从而省去了手动编写大量的获取依赖和赋值代码。

复制代码
@Component
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;
    @Override
    public void insertBook() {
        bookDao.saveBook();
        System.out.println("我是BookServiceImpl类的方法insert()");
    }
}

代码运行:

复制代码
public class App {
    public static void main(String[] args) {
        //加载核心配置文件
        ClassPathXmlApplicationContext ioc = new
                ClassPathXmlApplicationContext("Spring-Context.xml");

        //从ioc 容器中获取bean对象
        //BookDao bookDao = (BookDao) ioc.getBean("bookDao");
        //bookDao.addBook();
        
        // 获取 BookService 实例
        BookService bookService = (BookService) ioc.getBean("bookService");
        // 调用 BookService 的 insertBook 方法
        bookService.insertBook();
    }
}

运行结果:


2 SpringAOP 的使用

1 AOP 的基本概念

AOP(Aspect Oriented Programming):面向切面编程,一种编程范式,指导开发者如何组织程序结构

**作用:**在不惊动原始设计的基础上为其进行功能增强。

**Spring理念:**无入侵式/无侵入式

**原理:**动态代理
应用:1. 日志 2. 异常捕获、处理 3. 监控统计代码 4. 记录过程。

一些重要的概念:

  1. 连接点(JoinPoint):正在执行的方法,例如:update()、delete()、select()等都是连接点。
  2. 切入点(Pointcut):进行功能增强了的方法,例如:update()、delete()方法,select()方法没有被增强所以不是切入点,但是是连接点。
    • 在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法。
    • 一个具体方法:com.xbf.dao包下的BookDao接口中的无形参无返回值的save方法。
    • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法。
  3. 通知(Advice):在切入点前后执行的操作,也就是增强的共性功能。
    • 在SpringAOP中,功能最终以方法的形式呈现。
  4. 通知类:通知方法所在的类叫做通知类。
  5. 切面(Aspect):描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。

2 AOP 的案例实现

写一个计算器功能:计算加除法。并且用日志方式打印传递的参数、和结果、结束后通知用户计算完成!如果出现异常打印异常信息。完成步骤如下:

  1. 导入aop相关坐标
  2. 创建配置类进行Spring注解包扫描
  3. 定义业务接口与实现类
  4. 定义通知类,制作通知方法
  5. 定义切入点表达式、配置切面(绑定切入点与通知关系)
  6. 在配置类中开启AOP功能

案例代码的结构:


(1)导入AOP相关坐标

在 pom.xml 文件中,引入相关依赖:

java 复制代码
<!-- Spring 框架的核心模块,提供了 Spring 上下文和依赖注入功能 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    
    <!-- Spring 测试模块,提供了测试支持和集成 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    
    <!-- AspectJ 织入器,用于支持 Spring AOP 编程模型 -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.5</version>
    </dependency>
    
    <!-- JUnit 测试框架,用于编写和运行测试用例 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

(2)创建相关类

  • service 层:

接口类:

java 复制代码
package com.xbf.service;
public interface JiSuanQi {
    //加法
    int add(int a, int b);
    //减法
    int sub(int a, int b);
    //乘法
    int mul(int a, int b);
    //除法
    int div(int a, int b);
}

实现类:

java 复制代码
package com.xbf.service.impl;
import org.springframework.stereotype.Component;

@Component
public class JiSuanQiImpl implements com.xbf.service.JiSuanQi {
    @Override
    public int add(int a, int b) {

        return a + b;
    }
    @Override
    public int sub(int a, int b) {
        return a - b;
    }
    @Override
    public int mul(int a, int b) {
        return a * b;
    }
    @Override
    public int div(int a, int b) {
        return a / b;
    }
}
  • 核心配置类
java 复制代码
package com.xbf.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan({"com.xbf.service","com.xbf.advice"})
@EnableAspectJAutoProxy //开启 Spring 的 AspectJ 自动代理功能,支持 AOP
public class SpringConfig {

}
  • 通知类
java 复制代码
package com.xbf.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;

@Component
@Aspect //通知类
public class MyAdvice {

    @Pointcut("execution(* com.xbf.service.impl.JiSuanQiImpl.*(int, int))")
    public void pointcut(){};

    //1.前置通知
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("参数:" + Arrays.toString(joinPoint.getArgs()));
        System.out.println("开始计算");
    }
    //2.后置通知
    @After("pointcut()")
    public void after() {
        System.out.println("计算结束");
    }
    //3.返回通知
    @AfterReturning(value = "pointcut()", returning = "result")
    public void afterReturning(Object result) {
        System.out.println("计算结果:" + result);
    }
    //4 异常通知
    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void afterThrowing(Throwable e) {
        System.out.println("异常:" + e.getMessage());
    }
}

@Pointcut 注解的解释:

apl 复制代码
 @Pointcut("execution(* com.xbf.service.impl.JiSuanQiImpl.*(int, int))")
    public void pointcut(){};
上式:AspectJ 切点表达式,用于定义一个切点(pointcut)。这个切点表达式指定了在哪些方法执行时应用通知。下面是对这段代码的详细解释:
	@Pointcut("execution(* com.xbf.service.impl.JiSuanQiImpl.*(int, int))"):这是一个注解,用于定义一个切点。@Pointcut 注解是 AspectJ 框架中的一个特性,它允许你定义一个方法作为切点,然后在其他通知注解(如 @Before、@After、@Around 等)中引用这个切点。
	"execution(* com.xbf.service.impl.JiSuanQiImpl.*(int, int))":这是切点表达式的具体内容。它的含义是:匹配 com.xbf.service.impl.JiSuanQiImpl 包中的任意类的任意方法,这些方法接收两个 int 类型的参数。execution 是 AspectJ 中最常用的切点指示器,用于指定方法的执行作为切点。
	这个切点表达式定义了一个非常具体的切点,它只匹配 JiSuanQiImpl 类中的那些接收两个 int 参数的方法。在这个切面类 MyAdvice 中,这个切点被用于四个不同的通知注解(@Before、@After、@AfterReturning、@AfterThrowing),这意味着在JiSuanQiImpl 类的这些特定方法执行之前、之后、返回结果后以及抛出异常后,都会执行相应的通知方法。
  • 快速生成测试类:

JUnit是一个用于编写和运行可重复的自动化测试的开源测试框架,它是单元测试框架的xUnit架构的一个实例。JUnit主要有两个版本:JUnit 4和JUnit 5。

  • JUnit 4:这是JUnit的一个较早期版本,它支持Java 5及以上版本。JUnit 4引入了注解的使用,使得测试用例的编写更加简洁和直观

  • JUnit 5:这是JUnit的最新版本,它在设计上与JUnit 4相比有了重大的改进。JUnit 5的主要目标是支持现代Java开发实践,包括对Java 8及更高版本的支持。

默认会在 src/Test 目录下生成。

java 复制代码
package com.xbf.service.impl;

import com.xbf.config.SpringConfig;
import com.xbf.service.JiSuanQi;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class JiSuanQiTest {
    @Autowired
    private JiSuanQi jiSuanQi;

    @Test
    public void add() {

        //System.out.println("加法");
        System.out.println(jiSuanQi.add(2,4));
    }

    @Test
    public void sub() {
        System.out.println(jiSuanQi.sub(5,9));
    }

    @Test
    public void mul() {
    }

    @Test
    public void div() {
        //System.out.println(jiSuanQi.div(5,9));
        double n = jiSuanQi.div(5,9);
        double m = jiSuanQi.div(5,0);
    }
}

注解的解释:

apl 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
Java中的两个注解:用于配置JUnit测试框架与Spring框架的集成。

@RunWith(SpringJUnit4ClassRunner.class):
这个注解是JUnit框架提供的,用于指定测试运行器(Runner)。
SpringJUnit4ClassRunner是Spring框架提供的一个测试运行器,它允许在JUnit测试中使用Spring的依赖注入和事务管理等功能。
通过这个注解,JUnit会自动加载Spring的应用上下文(Application Context),并在测试类中注入Spring管理的Bean。

@ContextConfiguration(classes = SpringConfig.class):
这个注解也是Spring框架提供的,用于指定Spring应用上下文的配置类。
SpringConfig.class 是一个配置类,通常包含了Spring框架的各种配置,如Bean的定义、扫描包路径、数据库连接等。
通过这个注解,JUnit会在运行测试之前加载 SpringConfig 类,并根据其中的配置初始化Spring应用上下文。
这两个注解通常一起使用,确保JUnit测试能够在Spring容器的环境中运行,从而可以使用Spring的依赖注入和其他功能来测试Spring管理的组件。
在这个例子中,JiSuanQiTest 类是一个JUnit测试类,它使用了这两个注解来配置Spring环境,以便能够测试 JiSuanQi 类的功能。

(3)测试结果

相关推荐
hqxstudying13 分钟前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·21 分钟前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
春生野草40 分钟前
关于SpringMVC的整理
spring
martinzh1 小时前
Spring AI 项目介绍
后端
Bug退退退1231 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠1 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
前端付豪1 小时前
20、用 Python + API 打造终端天气预报工具(支持城市查询、天气图标、美化输出🧊
后端·python
爱学习的小学渣1 小时前
关系型数据库
后端
武子康2 小时前
大数据-33 HBase 整体架构 HMaster HRegion
大数据·后端·hbase
前端付豪2 小时前
19、用 Python + OpenAI 构建一个命令行 AI 问答助手
后端·python