提交 5866b55a 编写于 作者: W wizardforcel

2021-09-21 22:05:49

上级 fb0b2a31
......@@ -151,7 +151,7 @@ URI uri = URI.create("http://localhost:8080/books?name=" +
当我们必须处理大量的查询参数时,这种解决方案不是很方便。但是,我们可以尝试编写一个辅助方法,将`URLEncoder.encode()`方法隐藏在查询参数集合的循环中,也可以依赖 URI 生成器。
春季,URI 生成器是`org.springframework.web.util.UriComponentsBuilder`。以下代码是不言自明的:
Spring 中,URI 生成器是`org.springframework.web.util.UriComponentsBuilder`。以下代码是不言自明的:
```java
URI uri = UriComponentsBuilder.newInstance()
......
......@@ -847,31 +847,31 @@ public class AuthFilter implements Filter {
我们已经登录了我们的示例代码,为此,我们使用了 slf4j,我们在上一章中介绍了它。日志记录或多或少是开发人员的决定,支持技术级别的操作。在这里,我们还谈到了一些句子审计日志。这种类型的日志记录通常在功能需求中明确要求。
通常,AOP 将代码功能的不同方面分离为单独的代码片段,并相互独立地实现它们。这是一个非常单一的责任原则。这次,它的实现方式不仅是不同功能单独实现的,而且我们可以将它们连接在一起。这是单独定义的。在其他部分分别编码并获得 Spring 配置之前和之后执行什么?我们已经看到类似的东西了。类需要正确操作的依赖关系在单独的段(XML 或 Java 代码)中定义。对于 AOP,同样使用 Spring 也不奇怪。方面在配置文件或类中配置。
通常,AOP 将代码功能的不同切面分离为单独的代码片段,并相互独立地实现它们。这是一个非常单一的责任原则。这次,它的实现方式不仅是不同功能单独实现的,而且我们可以将它们连接在一起。这是单独定义的。在其他部分分别编码并获得 Spring 配置之前和之后执行什么?我们已经看到类似的东西了。类需要正确操作的依赖关系在单独的段(XML 或 Java 代码)中定义。对于 AOP,同样使用 Spring 也不奇怪。切面在配置文件或类中配置。
审计日志记录是一个典型的方面,我们将以它为例。有许多主题可以使用方面来实现,其中一些甚至值得通过这种方式实现。
审计日志记录是一个典型的切面,我们将以它为例。有许多主题可以使用切面来实现,其中一些甚至值得通过这种方式实现。
我们不希望在每个需要审计日志的业务方法或类中实现审计日志代码。相反,我们实现了一个通用面并配置了连接,以便每当调用需要审计日志记录的 bean 方法时,Spring 就会调用审计日志记录。
我们不希望在每个需要审计日志的业务方法或类中实现审计日志代码。相反,我们实现了一个通用面并配置了连接,以便每当调用需要审计日志记录的 bean 方法时,Spring 就会调用审计日志记录。
对于 AOP,我们还应该了解其他一些重要的术语,特别是如何在 Spring 中配置 AOP。
首先也是最重要的是面。这是我们想要实现的功能,在我们的示例中是审计日志记录。
首先也是最重要的是面。这是我们想要实现的功能,在我们的示例中是审计日志记录。
连接点是调用方面时的执行点。在 Java 中使用全面方面解决方案修改生成的类的字节码时,连接点几乎可以是任何东西。它可以是对字段的访问,读或写;它可以是对方法的调用或异常抛出。在 Spring 的情况下,不会修改类字节码;因此,Spring 无法识别对字段的访问或抛出的异常。使用 Spring,调用方法时总是使用连接点。
连接点是调用切面时的执行点。在 Java 中全面使用切面解决方案修改生成的类的字节码时,连接点几乎可以是任何东西。它可以是对字段的访问,读或写;它可以是对方法的调用或异常抛出。在 Spring 的情况下,不会修改类字节码;因此,Spring 无法识别对字段的访问或抛出的异常。使用 Spring,调用方法时总是使用连接点。
一条建议是如何在连接点调用方面。它可以在建议前,建议后,或周围的建议。如果通知在前面,则在调用方法之前调用方面。当通知在之后时,在调用方法之后调用方面。Around 意味着在方法调用之前调用方面,方面也有一个参数来调用方法,并且在方法调用之后仍然执行一些操作。这样,环绕建议与 Servlet 过滤器非常相似。
一条建议是如何在连接点调用切面。它可以在建议前,建议后,或周围的建议。如果通知在前面,则在调用方法之前调用切面。当通知在之后时,在调用方法之后调用切面。Around 意味着在方法调用之前调用切面,切面也有一个参数来调用方法,并且在方法调用之后仍然执行一些操作。这样,环绕建议与 Servlet 过滤器非常相似。
在方法调用之前调用事先通知,在它返回之后,框架将调用该方法。方面无法阻止调用原始方法。唯一的例外是当方面抛出异常时。
在方法调用之前调用事先通知,在它返回之后,框架将调用该方法。切面无法阻止调用原始方法。唯一的例外是当切面抛出异常时。
事后通知也受异常的影响。返回后的通知可以在方法返回时调用。只有当方法抛出异常时才调用抛出后通知。最后,在异常或返回的情况下调用事后通知。
切入点是一个特殊的字符串表达式,用于标识连接点。切入点表达式可以匹配零个、一个或多个连接点。当方面与切入点表达式相关联时,框架将知道连接点以及何时何地调用方面。换句话说,切入点是一个字符串,它告诉您何时以及为哪个方法调用方面。
切入点是一个特殊的字符串表达式,用于标识连接点。切入点表达式可以匹配零个、一个或多个连接点。当切面与切入点表达式相关联时,框架将知道连接点以及何时何地调用切面。换句话说,切入点是一个字符串,它告诉您何时以及为哪个方法调用切面。
尽管 AOP 的 Spring 实现不使用 AspectJ,也不修改为类创建的字节码,但它支持切入点表达式语言。尽管这种表达式语言提供了比 Spring 实现的更多的特性,但它是一种成熟的、广泛使用和接受的用于描述切入点的表达式语言,发明新的东西是没有意义的。
*序言*是向已经存在的类型添加方法或字段,并在运行时添加。Spring 允许此 AOP 功能向现有类型添加接口,并以建议类的形式添加接口的实现。在我们的示例中,我们不使用此功能。
*目标对象*方面建议的对象。这是包含关于方面的方法的 bean,即在调用方面之前或之后。
*目标对象*切面建议的对象。这是包含关于切面的方法的 bean,即在调用切面之前或之后。
那只是一组浓缩的定义,就像在数学书中一样。如果你读到这篇文章还没明白,别担心。我第一次读的时候也不明白。这就是为什么我们有下面的例子,在这些例子之后,我们刚刚讨论的内容将更有意义:
......@@ -902,11 +902,11 @@ public class SpringConfigurationAspect {
}
```
该类用`@Configuration`注解进行注解,以便 Spring 知道该类包含配置。`@Aspect`注解表示此配置还可以包含面定义。方法上的`@Around`注解给出了通知的类型,注解的参数字符串是切入点表达式。如果通知类型不同,则应使用注解之一,`@Before``@After``@AfterReturning``@AfterThrowing`
该类用`@Configuration`注解进行注解,以便 Spring 知道该类包含配置。`@Aspect`注解表示此配置还可以包含面定义。方法上的`@Around`注解给出了通知的类型,注解的参数字符串是切入点表达式。如果通知类型不同,则应使用注解之一,`@Before``@After``@AfterReturning``@AfterThrowing`
在我们的示例中,我们使用`@Around`方面来演示最复杂的场景。我们记录了目标方法在方法执行前后的执行情况,还通过`ProceedingJoinPoint`对象调用了原始方法。因为这两个对象返回了不同的类型,并且我们希望以不同的方式记录,所以我们定义了两个方面方法。
在我们的示例中,我们使用`@Around`切面来演示最复杂的场景。我们记录了目标方法在方法执行前后的执行情况,还通过`ProceedingJoinPoint`对象调用了原始方法。因为这两个对象返回了不同的类型,并且我们希望以不同的方式记录,所以我们定义了两个切面方法。
建议注解的参数是切入点字符串。在这种情况下,它是一个简单的。第一个`execution(* byId(..))`表示,对于任何名为`byId`且具有任何参数的方法的任何执行,都应该调用面。第二种方法非常相似,只是方法的名称不同。这些是简单的切入点表达式,但在大量使用 AOP 的大型应用中,它们可能非常复杂。
建议注解的参数是切入点字符串。在这种情况下,它是一个简单的。第一个`execution(* byId(..))`表示,对于任何名为`byId`且具有任何参数的方法的任何执行,都应该调用面。第二种方法非常相似,只是方法的名称不同。这些是简单的切入点表达式,但在大量使用 AOP 的大型应用中,它们可能非常复杂。
Spring 中的切入点表达式语法主要遵循 AspectJ 使用的语法。该表达式采用**切点指示符****PCD**)的概念,通常执行。后面是定义要截取的方法的模式。一般格式如下:
......@@ -937,7 +937,7 @@ execution(* set*(..))
public void businessService() {}
```
它将为在`packt.java.9.by.example.service`包的任何类中实现的任何方法定义一个连接点。这只是定义切入点表达式并将其赋给名称`businessService`,该名称由方法的名称给出。稍后,我们可以在面注解中引用此表达式,例如:
它将为在`packt.java.9.by.example.service`包的任何类中实现的任何方法定义一个连接点。这只是定义切入点表达式并将其赋给名称`businessService`,该名称由方法的名称给出。稍后,我们可以在面注解中引用此表达式,例如:
```java
@After("businessService()")
......@@ -945,13 +945,13 @@ public void businessService() {}
请注意,使用此方法纯粹是为了它的名称。Spring 不调用此方法。它仅用于借用其上定义的表达式的名称,该表达式使用了`@Pointcut`注解。需要某种东西(例如方法)来放置此注解,既然方法有名称,为什么不使用它呢?Spring来了。当它扫描配置类并看到注解时,它会在其内部结构中将其分配给方法的名称,当使用该名称(连同括号,以使模仿方法调用的新手程序员感到困惑)时,它会查找该名称的表达式。
AspectJ 定义了其他指示符。Spring AOP 可以识别其中的一些,但是它抛出了`IllegalArgumentException`,因为 Spring 只实现方法执行切入点。另一方面,AspectJ 还可以拦截 PCD 正在初始化的对象创建,例如。除了执行之外,一些其它 PCD 可以限制执行 PCD。例如,PCD,`within`可以用来限制面连接属于某些包中类的点,或者`@target`PCD 可以用来限制对象中的方法匹配,这些对象的注解在切入点表达式中的关键字`@target`之后在`(``)`之间给出。
AspectJ 定义了其他指示符。Spring AOP 可以识别其中的一些,但是它抛出了`IllegalArgumentException`,因为 Spring 只实现方法执行切入点。另一方面,AspectJ 还可以拦截 PCD 正在初始化的对象创建,例如。除了执行之外,一些其它 PCD 可以限制执行 PCD。例如,PCD,`within`可以用来限制面连接属于某些包中类的点,或者`@target`PCD 可以用来限制对象中的方法匹配,这些对象的注解在切入点表达式中的关键字`@target`之后在`(``)`之间给出。
Spring 使用的 PCD 在 AspectJ 中并不存在。这是一颗豆子。您可以定义一个包含`bean(name pattern)`的切入点表达式,将连接点限制为指定 bean 中的方法执行。模式可以是全名,也可以像几乎所有匹配的 PCD 表达式一样,`*`可以是小丑角色。
# 基于动态代理的 AOP
当 SpringAOP 第一次出现在 Java 程序员面前时,它看起来很神奇。我们如何有一个变量`classX`并调用该对象上的方法?相反,它在方法执行之前或之后执行某些方面,甚至在其周围执行某些方面,以拦截调用。
当 SpringAOP 第一次出现在 Java 程序员面前时,它看起来很神奇。我们如何有一个变量`classX`并调用该对象上的方法?相反,它在方法执行之前或之后执行某些切面,甚至在其周围执行某些切面,以拦截调用。
Spring 使用的技术称为动态代理。当我们有一个实现接口的对象时,我们可以创建另一个对象——代理对象——也实现该接口,但是每个方法实现都调用一个名为处理器的不同对象,实现 JDK 接口`InvocationHandler`。当代理对象上调用接口方法时,它将在处理器对象上调用以下方法:
......@@ -967,7 +967,7 @@ public Object invoke(Object target, Method m, Object[] args)
这些技术在运行时创建类并将其加载到 Java 内存中,它们是非常深入的技术工具。它们是高级主题。我并不是说当我还是一个 Java 程序员新手的时候不要玩它们。毕竟,会发生什么?Java不是一把上膛的枪。然而,重要的是,当你不了解一些细节或者一开始有些东西不起作用时,不要失去兴趣。或者第二个。或者第三。。。继续游泳。
Spring 中的 AOP 实现通过为目标对象生成代理对象来工作,处理器调用我们在 Spring 配置中定义的方面。这就是您不能将方面放在`final`类或`final`方法上的原因。此外,您不能在`private``protected`方法上配置方面。原则上,`protected`方法可以被代理,但这不是一个好的实践,因此 Spring AOP 不支持它。类似地,不能将方面放在不是 SpringBean 的类上。它们是由代码直接创建的,而不是通过 Spring 创建的,并且在创建对象时没有机会返回代理而不是原始对象。简单地说,如果不要求 Spring 创建对象,它就不能创建自定义对象。我们最不想做的就是执行这个程序,看看方面是如何执行的。审计日志的实现非常简单。我们使用标准日志,这对于审计日志的实际应用来说是不够的。我们所做的唯一特殊的事情是使用一个由名称`AUDIT_LOG`而不是类名称标识的记录器。在大多数日志框架中,这是对日志记录器的合法使用。尽管我们通常使用类来标识记录器,但是使用字符串来标识记录器是绝对可能的。在我们的日志记录中,这个字符串也将被打印在控制台的日志行中,并且它将在视觉上突出。
Spring 中的 AOP 实现通过为目标对象生成代理对象来工作,处理器调用我们在 Spring 配置中定义的切面。这就是您不能将切面放在`final`类或`final`方法上的原因。此外,您不能在`private``protected`方法上配置切面。原则上,`protected`方法可以被代理,但这不是一个好的实践,因此 Spring AOP 不支持它。类似地,不能将切面放在不是 SpringBean 的类上。它们是由代码直接创建的,而不是通过 Spring 创建的,并且在创建对象时没有机会返回代理而不是原始对象。简单地说,如果不要求 Spring 创建对象,它就不能创建自定义对象。我们最不想做的就是执行这个程序,看看切面是如何执行的。审计日志的实现非常简单。我们使用标准日志,这对于审计日志的实际应用来说是不够的。我们所做的唯一特殊的事情是使用一个由名称`AUDIT_LOG`而不是类名称标识的记录器。在大多数日志框架中,这是对日志记录器的合法使用。尽管我们通常使用类来标识记录器,但是使用字符串来标识记录器是绝对可能的。在我们的日志记录中,这个字符串也将被打印在控制台的日志行中,并且它将在视觉上突出。
考虑以下命令:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册