您的位置:首页 > 财经 > 产业 > 第六章 Spring框架深入学习(2023版本IDEA)

第六章 Spring框架深入学习(2023版本IDEA)

2024/12/22 9:49:07 来源:https://blog.csdn.net/2301_78884095/article/details/140524260  浏览:    关键词:第六章 Spring框架深入学习(2023版本IDEA)

学习目标

  • 6.1 增强类型扩展
      • 1. 继承(Inheritance)
      • 2. 组合(Composition)
      • 3. 装饰者模式(Decorator Pattern)
      • 4. 使用Java 8及以上版本的默认方法和静态方法
    • 6.1.1 异常抛出增强
      • 1. 自定义异常
      • 2. 在方法中抛出异常
      • 3. 捕获并处理异常
      • 4. 使用throws声明
      • 5. 异常链
      • 6. 合理使用检查型异常和运行时异常
    • 6.1.2 最终增强
    • 6.1.3 环绕增强
  • 6.2 依赖注入方式扩展
    • 6.2.1 构造注入
    • 6.2.2 p命名空间注入
    • 6.2.3 不同数据类型的注入
  • 6.3 使用注解实现Spring IOC
    • 6.3.1 使用注解方式实现用户保存功能
    • 6.3.2 使用Java标注注解完成装配
  • 6.4 使用注解实现Spring AOP
    • 6.4.1 使用注解方式标注切面
    • 6.4.2 使用注解定义其他类型的增强

  在第五章学习了Spring框架的一些基础概念和操作,同学们已经对Spring框架有了基本的了解。(如果没有了解可以去我主页看看 第一至五章 的内容来学习)本章将对第五章中的内容进行扩展学习,进一步感受Spring框架功能强大和使用方便的优势。

6.1 增强类型扩展

  在Java中,类型扩展通常指的是在现有类型的基础上增加新的功能或属性,但这并不是Java直接支持的一种特性,因为Java是一种静态类型语言,其类型系统相对固定。不过,我们可以通过几种不同的方式来实现类似“增强类型”的效果:

1. 继承(Inheritance)

这是最直接的方式,通过定义一个子类继承父类,你可以在子类中增加新的方法或属性,从而“扩展”父类的功能。但是,这种方式仅限于类之间的扩展,不适用于接口或已存在的第三方库中的类(除非这些类被设计为可以被扩展)。

class Animal {  void eat() {  System.out.println("This animal eats food.");  }  
}  class Dog extends Animal {  void bark() {  System.out.println("Woof!");  }  
}

2. 组合(Composition)

如果你不能或不想通过继承来扩展类型,可以使用组合。这意味着你可以在一个类中持有另一个类的实例,并通过这个实例来访问其方法。这样,你可以在你的类中添加新的方法或属性,并且可以通过组合进来的实例来使用其方法。

class Engine {  void start() {  System.out.println("Engine started.");  }  
}  class Car {  private Engine engine;  Car(Engine engine) {  this.engine = engine;  }  void startEngine() {  engine.start();  }  void openDoor() {  System.out.println("Door opened.");  }  
}

3. 装饰者模式(Decorator Pattern)

装饰者模式允许你动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式相比生成子类更为灵活。这种模式创建了一个包装对象,也就是装饰器,来包裹真实的对象。

interface Component {  void operation();  
}  class ConcreteComponent implements Component {  public void operation() {  System.out.println("ConcreteComponent's operation");  }  
}  class Decorator implements Component {  protected Component component;  public Decorator(Component component) {  this.component = component;  }  public void operation() {  component.operation();  }  
}  class ConcreteDecoratorA extends Decorator {  public ConcreteDecoratorA(Component component) {  super(component);  }  public void operation() {  super.operation();  addedFunctionality();  }  void addedFunctionality() {  System.out.println("New Functionality Added by ConcreteDecoratorA");  }  
}

4. 使用Java 8及以上版本的默认方法和静态方法

如果你正在扩展接口,并且希望为接口添加新方法而不破坏实现了该接口的旧类,可以使用Java 8引入的默认方法(default methods)和静态方法(static methods)。

interface MyInterface {  default void defaultMethod() {  System.out.println("This is a default method.");  }  static void staticMethod() {  System.out.println("This is a static method.");  }  
}

注意
  虽然默认方法和静态方法可以让你在接口中“添加”新方法,但它们并不真正改变已经存在的类型的“行为”,只是为实现了该接口的类提供了额外的功能。

6.1.1 异常抛出增强

  异常抛出增强是指当目标对象方法抛出异常时进行织入操作的一种增强方式。通常,异常抛出增强用来为项目提供统一的异常处理功能,具有可灵活插拨的特点。
  使用异常抛出增强时,需要在配置文件中使用<aop:after-throwing>标签进行配置,语法如下。
  语法:

<aop:config><aop:aspect ref="增强方法所在的Bean"><aop:after-throwing method="增强处理方法"pointcut-ref="切入点id" throwing="e"/></aop:aspect>
</aop:config>

  上述语法中,<aop:after-throwing>标签表示增强处理类型为异常抛出增强。

  在Java中,异常抛出是处理运行时错误的一种重要机制。通过抛出异常,你可以让方法在遇到无法处理或不应处理的错误时,通知调用者。这种机制增强了代码的健壮性和可维护性。下面是如何在Java代码中通过抛出异常来增强其健壮性的一些示例:

1. 自定义异常

首先,你可以通过继承Exception类(对于可检查的异常)或RuntimeException类(对于运行时异常)来创建自定义异常。这有助于你更清晰地表达错误的性质,并提供更具体的错误信息。

public class MyCustomException extends Exception {  public MyCustomException(String message) {  super(message);  }  // 可以添加其他构造器或方法  
}

2. 在方法中抛出异常

当方法无法继续执行其任务时,可以抛出异常。这可以是自定义异常,也可以是Java标准库中的异常。

public void doSomething(int number) throws MyCustomException {  if (number < 0) {  throw new MyCustomException("Number cannot be negative");  }  // 其他逻辑...  
}

3. 捕获并处理异常

调用可能抛出异常的方法时,你应该捕获这些异常并适当处理它们。这可以通过try-catch块来完成。

try {  doSomething(-1);  
} catch (MyCustomException e) {  System.err.println("Caught an exception: " + e.getMessage());  // 处理异常,例如记录日志、回滚事务、显示错误消息等  
}

4. 使用throws声明

如果方法不处理某个异常,但认为调用者应该处理它,那么可以在方法签名中使用throws关键字来声明该方法可能抛出的异常。

public void anotherMethod() throws IOException, MyCustomException {  // 方法体...  // 可能抛出IOException或MyCustomException  
}

5. 异常链

在处理异常时,有时需要将一个异常包装在另一个异常中,并抛出新的异常。这可以通过在构造器中传递原始异常作为参数来实现,从而保持异常的上下文信息。

try {  // 可能抛出IOException的代码  
} catch (IOException e) {  throw new MyCustomException("Failed to perform operation", e);  
}

6. 合理使用检查型异常和运行时异常

  • 检查型异常(如IOException)应该用于那些合理的、可恢复的或需要调用者特别关注的异常情况。
  • 运行时异常(如NullPointerException、IllegalArgumentException)通常用于指示编程错误,如空指针引用、无效的参数等,这些错误通常是由程序员的失误引起的,而不是由外部因素引起的。

6.1.2 最终增强

  最终增强是指无论目标对象的方法正常运行还是抛出异常,该增强处理都会执行的一种增强方式。其与Java中finally代码块的作用相似,通常用于释放资源等操作,具有可灵活插拨的特点。
  使用最终增强,需要在配置文件中使用aop:after标签进行配置,语法如下。
语法:

<aop:config><aop:aspect ref="增强方法所在的Bean"><aop:after method="增强处理方法" pointcut-ref="切入点id"></aop:aspect>
</aop:config>

6.1.3 环绕增强

  环绕增强是指在目标对象方法前后都可以进行织人的一种增强处理方式。在环绕增强处理中,可以获取修改目标方法的参数、返回值,可以对它进行异常处理,甚至可以决定目标方法是否被执行。
  使用环绕增强,需要在配置文件中使用<aop:around>标签进行配置,语法如下。
语法:

<aop:config><aop:aspect ref="增强方法所在的 Bean"><aop:around method="增强处理方法" pointcut-ref="切入点id"/></aop:aspect>
</aop:config> 

6.2 依赖注入方式扩展

  在第5章我们学习了Spring IOC通过setter方法实现对属性的赋值功能,这种方式被称为设值注入。除此之外,Spring框架还提供了多种属性注入方式,下面逐一进行学习。

6.2.1 构造注入

  构造注入的指Spring框架通过构造方法为属性赋值的一种注入方式。构造注入可以在对象初始化时为属性赋值,具有良好的时效性。
  使用构造注入,需要在配置文件中使用<constructor-arg>标签进行配置,语法如下。
语法:

<bean id="唯一标识" class="类的全路径"><constructor-arg name="参数名称" ref="依赖对象"/>
</bean>

知识扩展
(1)如果有多个参数,可以在当前bean标签下配置多个<constructor-arg>标签。
(2)除使用name属性区别多个参数外,还可以使用<constructor-arg>标签中的index属性指定参数的位置索引,位置从0开始。
(3)<constmctor-arg>标签提供了type属性,用以标识参数的类型。

6.2.2 p命名空间注入

  在Java中,没有直接称为“p命名空间”的官方概念,因为Java使用包(package)来组织代码,而不是命名空间(尽管在很多情况下,包和命名空间可以互换使用,尤其是在讨论Java与其他语言如C#的比较时)。然而,如果你想要在Java中“注入”代码到一个特定的包(或你认为的“命名空间”)中,你实际上是在创建或修改属于该包的类、接口、枚举或注解。

  p命名空间的特点是使用属性而不是子元素的形式配置Bean的属性,从而简化了Bean的配置。p标签的语法非常简单,如下所示。
语法

<bean id="唯一标识" class="类的全路径"p:"属性1"="注入的值"p:"属性2"="注入的值" />
<bean id="唯一标识" class="类的全路径"p:属性-ref="注入的Bean"/>

  以下是一个简单的步骤,说明如何在Java中向一个名为com.example.p的包中“注入”一个新的类:

  1. 创建包目录结构: 首先,你需要在你的项目结构中创建一个名为com/example/p的目录结构。这通常是在你的源代码目录下完成的。
  2. 创建类文件: 在com/example/p目录下,创建一个新的Java类文件。例如,你可以创建一个名为MyClass.java的文件。
  3. 编写类代码: 在MyClass.java文件中,编写你的类代码,并使用package语句来声明这个类属于com.example.p包。
// 文件路径: src/com/example/p/MyClass.java  
package com.example.p;  public class MyClass {  public void myMethod() {  System.out.println("Hello from MyClass in com.example.p package");  }  
}
  1. 编译代码: 使用Java编译器(如javac)编译你的类文件。确保你的编译命令包含了正确的源目录路径,以便编译器能够找到你的类文件。
javac -d bin/ src/com/example/p/MyClass.java

这个命令假设你的源代码在src/目录下,你希望编译后的类文件放在bin/目录下。-d bin/参数指定了输出目录。

  1. 运行代码: 编译完成后,你可以使用java命令来运行你的类(注意,你需要从包含main方法的类开始运行,这里只是一个示例,所以你可能需要创建另一个包含main方法的类来运行MyClass)。
    如果你已经有一个包含main方法的类,并且它调用了MyClass的myMethod方法,你可以这样运行它:
java -cp bin/ com.example.p.YourMainClass

确保将YourMainClass替换为实际包含main方法的类名。

注意
  在Java中,“注入”这个词通常与依赖注入(Dependency Injection, DI)框架(如Spring)相关联,它允许你以声明的方式将依赖项注入到类的实例中,而不是在代码中硬编码这些依赖项。但是,在你的情况下,你似乎只是在谈论向包中添加新代码,这与依赖注入不是同一回事。

注意
  配置文件中使用p命名空间时,需要先添加p命名空间的声明:
xmlns:p=“http://www.springframework.org/schema/p”

6.2.3 不同数据类型的注入

  在Java中,不同类型的数据注入(或更准确地说,是在Java代码中使用不同类型的数据)通常涉及到变量的声明、初始化以及它们如何在程序中被使用。这里,我将展示一些基本的示例,说明如何在Java代码中注入或处理不同类型的数据。

  1. 基本数据类型
    Java有八种基本数据类型:byte, short, int, long, float, double, char, 和 boolean。
public class BasicDataTypes {  public static void main(String[] args) {  byte b = 10;  short s = 2000;  int i = 30000;  long l = 4000000000L; // 注意L后缀表示long类型  float f = 5.5f; // f或F后缀表示float类型  double d = 6.6;  char c = 'A';  boolean bool = true;  System.out.println("byte: " + b);  System.out.println("short: " + s);  System.out.println("int: " + i);  System.out.println("long: " + l);  System.out.println("float: " + f);  System.out.println("double: " + d);  System.out.println("char: " + c);  System.out.println("boolean: " + bool);  }  
}
  1. 引用数据类型
    引用数据类型包括类、接口、数组等。这里,我将展示如何使用类(对象)和数组。

类(对象)

class Person {  String name;  int age;  Person(String name, int age) {  this.name = name;  this.age = age;  }  @Override  public String toString() {  return "Person{" +  "name='" + name + '\'' +  ", age=" + age +  '}';  }  
}  public class ObjectExample {  public static void main(String[] args) {  Person person = new Person("Alice", 30);  System.out.println(person);  }  
}

数组

public class ArrayExample {  public static void main(String[] args) {  int[] numbers = {1, 2, 3, 4, 5};  for (int number : numbers) {  System.out.println(number);  }  String[] strings = {"Hello", "World", "Java"};  for (String str : strings) {  System.out.println(str);  }  }  
}
  1. 泛型
    泛型允许你在编译时检查类型安全,同时保持代码的灵活性和可重用性。
import java.util.ArrayList;  
import java.util.List;  public class GenericExample {  public static void main(String[] args) {  List<String> stringList = new ArrayList<>();  stringList.add("Apple");  stringList.add("Banana");  stringList.add("Cherry");  for (String fruit : stringList) {  System.out.println(fruit);  }  // 泛型方法示例  printList(stringList);  }  public static <T> void printList(List<T> list) {  for (T item : list) {  System.out.println(item);  }  }  
}

在这些示例中,我们展示了如何在Java代码中使用不同类型的数据,包括基本数据类型、引用数据类型(如对象和数组)以及泛型。这些基本构建块是编写Java程序时不可或缺的部分。

6.3 使用注解实现Spring IOC

  第5章中已经学习了使用XML配置文件的方式实现Spring IOC相关的内容,但是当项目越来越庞大肘,使用这种方式需要在配置文件中编写大量的代码。Spring从2.0版本开始引入注解的配置方式来解决这个问题。

6.3.1 使用注解方式实现用户保存功能

  在Java中,使用注解(Annotation)通常不直接实现业务逻辑,如用户保存功能。注解更多地被用作元数据,用于为代码提供额外的信息,这些信息可以在编译时或运行时被读取和处理。然而,你可以结合注解、Spring框架(特别是Spring Data JPA或Spring MVC)来实现用户保存功能,其中注解用于声明性地配置你的服务、控制器和仓库。

  以下是一个简单的例子,展示了如何使用Spring Boot、Spring Data JPA和JPA注解来实现用户保存功能。在这个例子中,我们将定义一个用户实体(User),一个用户仓库接口(UserRepository),和一个用户服务(UserService),以及一个控制器(UserController)来处理HTTP请求。

  1. 用户实体(User.java)
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.GenerationType;  
import javax.persistence.Id;  @Entity  
public class User {  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private Long id;  private String name;  private String email;  // 构造器、getter和setter省略  public User() {  }  public User(String name, String email) {  this.name = name;  this.email = email;  }  // getter和setter  public Long getId() {  return id;  }  public void setId(Long id) {  this.id = id;  }  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  public String getEmail() {  return email;  }  public void setEmail(String email) {  this.email = email;  }  
}
  1. 用户仓库接口(UserRepository.java)
import org.springframework.data.jpa.repository.JpaRepository;  public interface UserRepository extends JpaRepository<User, Long> {  // 继承JpaRepository,Spring Data JPA会自动实现基本的CRUD操作  
}
  1. 用户服务(UserService.java)
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  @Service  
public class UserService {  @Autowired  private UserRepository userRepository;  public User saveUser(User user) {  return userRepository.save(user);  }  // 其他业务逻辑...  
}
  1. 用户控制器(UserController.java)
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.web.bind.annotation.*;  @RestController  
@RequestMapping("/users")  
public class UserController {  @Autowired  private UserService userService;  @PostMapping  public User createUser(@RequestBody User user) {  return userService.saveUser(user);  }  // 其他HTTP方法处理...  
}

  在这个例子中,我们没有直接使用注解来实现用户保存功能,而是利用了Spring Data JPA的JpaRepository接口来自动实现CRUD操作。我们的UserService类中的saveUser方法通过注入的UserRepository来保存用户。最后,UserController中的createUser方法处理HTTP POST请求,并将接收到的用户数据传递给UserService来保存。

这种方式充分利用了Spring框架的声明式配置和自动装配特性,使得代码更加简洁和易于维护。

6.3.2 使用Java标注注解完成装配

  Spring框架是一个超级粘合平台,它除本身提供@Autowired注解实现Bean的装配功能外,还支持同样可以实现该功能的@Resource注解。@Resource注解是在Java规范提案——JSR-250中定义的。

  在Java中,使用注解(Annotation)来完成装配(如依赖注入)主要依赖于框架如Spring。Spring框架通过注解的方式提供了强大的依赖注入功能,使得开发者可以以声明式的方式管理Java对象的依赖关系。
  以下是一个简单的示例,展示了如何使用Spring的@Component、@Autowired等注解来完成Java代码的装配。

  1. 引入Spring依赖

首先,确保你的项目中引入了Spring的依赖。如果你使用的是Maven,可以在pom.xml中添加Spring Boot的起步依赖(Spring Boot自动包含了Spring的依赖):

<dependencies>  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter</artifactId>  </dependency>  
</dependencies>
  1. 创建组件

使用@Component(或@Service、@Repository、@Controller等,它们都是@Component的特化)注解来标记Spring容器需要管理的类。

package com.example.demo.service;  import org.springframework.stereotype.Service;  @Service  
public class UserService {  public String getUserName() {  return "John Doe";  }  
}
  1. 装配组件

在需要使用UserService的类中,通过@Autowired注解来自动装配这个组件。

package com.example.demo.controller;  import com.example.demo.service.UserService;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.ResponseBody;  @Controller  
public class UserController {  @Autowired  private UserService userService;  @GetMapping("/user")  @ResponseBody  public String getUser() {  return "User Name: " + userService.getUserName();  }  
}
  1. 启动类

使用@SpringBootApplication注解来标记Spring Boot的启动类,这个注解包含了@Configuration、@EnableAutoConfiguration、@ComponentScan等注解,它告诉Spring Boot如何找到并配置应用程序的其余部分。

package com.example.demo;  import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  @SpringBootApplication  
public class DemoApplication {  public static void main(String[] args) {  SpringApplication.run(DemoApplication.class, args);  }  
}
  1. 运行应用

现在,当你运行DemoApplication的main方法时,Spring Boot会自动扫描到@Component、@Service、@Controller等注解标记的类,并将它们注册为Spring应用上下文中的Bean。然后,它会处理@Autowired注解,将UserService注入到UserController中。

最后,你可以通过访问/user这个URL来测试你的应用,它应该会返回"User Name: John Doe"。

这就是使用Java注解完成装配的一个基本示例。在实际的项目中,你可能会用到更多的Spring注解和特性来构建更复杂的应用程序。

6.4 使用注解实现Spring AOP

  使用注解实现Spring AOP需要用到AspectJ框架。AspectJ本身就是AOP的框架,它扩展了Java语言,定义了AOP语法,且自带编译器。此编译器可以将代码编译成遵守字节编码规范的Class文件,在编译期间即可实现代码的织入功能。

6.4.1 使用注解方式标注切面

  在Java中,使用Spring框架的注解方式来标注切面(Aspect)代码是一种非常流行和便捷的方法。切面编程(AOP, Aspect-Oriented Programming)允许你将横切关注点(如日志、事务管理等)与业务逻辑代码分离,以提高代码的可维护性和复用性。

  以下是一个使用Spring注解方式标注切面的基本步骤和示例代码。

  1. 引入依赖

首先,确保你的项目中引入了Spring AOP的依赖。如果你使用的是Maven,可以在pom.xml中添加如下依赖:

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-aop</artifactId>  
</dependency>

注意
如果你使用的是Spring Boot,则spring-boot-starter-aop已经包含了所有必要的AOP依赖。

  1. 定义一个切面

使用@Aspect注解来定义一个切面类,并使用@Component或@Configuration(如果你还希望在切面中声明Bean)来让Spring容器管理这个类。

package com.example.demo.aspect;  import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.JoinPoint;  
import org.springframework.stereotype.Component;  @Aspect  
@Component  
public class LoggingAspect {  // 定义切点  @Before("execution(* com.example.demo.service.*.*(..))")  public void logBeforeMethod(JoinPoint joinPoint) {  System.out.println("Before executing method: " + joinPoint.getSignature().getName());  }  
}

在这个例子中,@Aspect注解表明该类是一个切面。@Before注解定义了一个前置通知(Advice),它会在匹配到的方法执行之前执行。execution(* com.example.demo.service..(…))是一个切点表达式,它指定了切面的应用范围:即com.example.demo.service包及其子包下的所有类的所有方法。

  1. 启用AspectJ自动代理

在Spring Boot项目中,通常不需要额外配置来启用AspectJ自动代理,因为spring-boot-starter-aop已经包含了必要的自动配置。但是,如果你不是在使用Spring Boot,或者需要自定义AspectJ自动代理的行为,你可以在配置类上添加@EnableAspectJAutoProxy注解。

  1. 编写业务逻辑代码

编写你的业务逻辑代码,就像没有使用AOP一样。Spring AOP会在运行时自动将切面应用到你的业务逻辑上。

  1. 测试

运行你的应用程序,并观察切面的效果。在上面的例子中,每当com.example.demo.service包下的方法被调用时,控制台都会输出一条日志信息,表明该方法即将被执行。

通过以上步骤,你可以很容易地在Java项目中使用注解方式标注切面代码,并利用Spring AOP的强大功能来实现横切关注点的分离。

6.4.2 使用注解定义其他类型的增强

  在Spring AOP(面向切面编程)中,除了前置通知(@Before)之外,还可以使用多种类型的注解来定义不同类型的增强(Advice),这些增强可以在目标方法执行的不同阶段插入自定义行为。以下是一些常用的Spring AOP增强类型及其对应的注解:

  1. 后置通知(@After):
    在目标方法执行之后(无论方法执行成功还是抛出异常)执行。它不能阻止异常传播,也不能修改返回值。
@After("execution(* com.example.demo.service.*.*(..))")  
public void logAfterMethod(JoinPoint joinPoint) {  System.out.println("After executing method: " + joinPoint.getSignature().getName());  
}
  1. 返回后通知(@AfterReturning):
    在目标方法正常执行完成后执行,可以访问方法的返回值。如果方法抛出异常,则不会执行。
@AfterReturning(pointcut = "execution(* com.example.demo.service.*.*(..))", returning = "result")  
public void logAfterReturning(JoinPoint joinPoint, Object result) {  System.out.println("Method returned: " + result);  
}
  1. 抛出异常后通知(@AfterThrowing):
    在目标方法抛出异常后执行,可以访问异常对象。
@AfterThrowing(pointcut = "execution(* com.example.demo.service.*.*(..))", throwing = "ex")  
public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {  System.out.println("Method threw an exception: " + ex.getMessage());  
}
  1. 环绕通知(@Around):
    环绕通知是功能最强大的通知类型,它可以在目标方法执行前后自定义行为,甚至决定是否执行目标方法以及修改其返回值。环绕通知需要返回一个Object,这个返回值会被当作目标方法的返回值。
@Around("execution(* com.example.demo.service.*.*(..))")  
public Object logAroundMethod(ProceedingJoinPoint pjp) throws Throwable {  System.out.println("Before proceeding method: " + pjp.getSignature().getName());  try {  Object result = pjp.proceed(); // 执行目标方法  System.out.println("After proceeding method: " + pjp.getSignature().getName());  return result;  } catch (IllegalArgumentException e) {  System.out.println("Method threw IllegalArgumentException: " + e.getMessage());  throw e; // 可以选择重新抛出异常,或者进行其他处理  }  
}
  1. 引入(@DeclareParents)(虽然不直接作为增强类型,但它是AOP的一个强大特性):
    允许你为类动态地添加接口的实现。这通常用于装饰器模式,可以在不修改类代码的情况下给类添加新的行为。
// 注意:这是一个声明性的引入,不是直接作为增强执行的  
@DeclareParents(value = "com.example.demo.service.*+", defaultImpl = MyDefaultImpl.class)  
public static MyMixin myMixin;

在这个例子中,@DeclareParents用于为com.example.demo.service包下的所有类声明一个新的父接口(或父类,但Spring AOP通常用于接口),并且指定了一个默认实现类MyDefaultImpl。然而,请注意,@DeclareParents通常用于基于接口的代理,并且在实际编程中较少直接使用,因为它更多地用于声明性配置而不是在切面中直接定义增强逻辑。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com