快速上手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)测试结果

相关推荐
老马啸西风几秒前
开源分布式系统追踪-01-Zipkin-01-入门介绍
java
工一木子7 分钟前
【Leecode】Leecode刷题之路第82天之删除排序链表中的重复元素II
java·数据结构·算法·leetcode·链表
亽仒凣凣27 分钟前
Tomcat官网下载安装
java·tomcat
Amor风信子27 分钟前
华为OD机试真题---机房布局
java·开发语言·数据结构·算法·华为od
吴代庄38 分钟前
探秘Redis哨兵模式:原理、运行与风险全解析
java·redis·系统架构
喵手39 分钟前
Spring注解篇:@EnableAutoConfiguration详解
java·后端·spring
916字节1 小时前
Kafka从0到1精通
spring·spring cloud·微服务·架构
独自破碎E1 小时前
Java 面经之 Kafka
java·开发语言·kafka
BestandW1shEs1 小时前
快速理解类的加载过程
java·jvm
初晴~1 小时前
【Redis】高并发场景下秒杀业务的实现思路(单机模式)
java·数据库·redis·后端·spring·缓存·中间件