🍊
翻译橙
🍊返回主站🤖参与贡献
  • hello,这里是翻译橙
  • spring boot参考文档
    • 1. 法律
    • 2. 寻求帮助
    • 3. 文档概述
    • 4. 入门
    • 5. 升级Spring Boot
    • 6. 使用 Spring Boot 进行开发
      • 6.1. 构建系统
      • 6.2. 构建你的代码
      • 6.3. 配置类
      • 6.4. 自动配置
      • 6.5. Spring Bean 和依赖注入
      • 6.6. 使用@SpringBootApplication注解
      • 6.7. 运行您的应用程序
      • 6.8. 开发者工具
      • 6.9. 打包您的生产应用程序
      • 6.10. 接下来读什么
    • 7.核心特性
      • 7.1. SpringApplication
      • 7.2. 外部化配置
      • 7.3.Profile配置
      • 7.4.日志记录
      • 7.5.国际化
      • 7.6 面向切面的编程
      • 7.7. JSON
      • 7.8. 任务执行与调度
      • 7.9. 单元测试
        • 7.9.1. 测试范围依赖
        • 7.9.2. 测试 Spring 应用程序
        • 7.9.3. 测试 Spring Boot 应用程序
        • 7.9.4. 测试容器
        • 7.9.5. 测试工具
      • 7.10. Docker Compose 支持
      • 7.11. 测试容器支持
      • 7.12. 创建您自己的自动配置
      • 7.13. Kotlin 支持
      • 7.14 SSL
      • 7.15.接下来要读什么
    • 8. 网络
      • 8.1. Servlet Web 应用程序
        • 8.1.1. “Spring Web MVC 框架”
        • 8.1.2. JAX-RS 和Jersey
        • 8.1.3. 嵌入式 Servlet 容器支持
      • 8.2 反应式网络应用程序
        • 8.2.1. “Spring WebFlux 框架”
        • 8.2.2. 嵌入式反应式服务器支持
        • 8.2.3. 反应式服务器资源配置
      • 8.3. 优雅关机
      • 8.4. spring安全
        • 8.4.1. MVC安全
        • 8.4.2. WebFlux 安全
        • 8.4.3. OAuth2
        • 8.4.4. SAML 2.0
      • 8.5. spring 会话
      • 8.6.GraphQL
      • 8.7. Spring HATEOAS
      • 8.8.接下来读什么
    • 9. 数据
      • 9.1. SQL数据库
      • 9.2. 使用 NoSQL 技术
      • 9.3. 接下来读什么
    • 10. 消息
      • 10.1. JMS
      • 10.2. AMQP
      • 10.3. Apache Kafka 支持
      • 10.4. Apache Pulsar 支持
      • 10.5. RSocket
      • 10.6. Spring Integration
      • 10.7. WebSockets
      • 10.8. What to Read Next
    • 11. IO
      • 11.1. 缓存
      • 11.2. Hazelcast
      • 11.3. Quartz 调度程序
      • 11.4. 发送电子邮件
      • 11.5. 验证
      • 11.6. 调用 REST 服务
      • 11.7. web services
      • 11.8. 使用 JTA 进行分布式事务
      • 11.9. 接下来读什么
    • 12. 容器镜像
  • Spring核心功能
    • 1.IOC容器和Bean简介
      • 1.2. 容器概述
      • 1.3. Bean概述
      • 1.4. 依赖项
        • 1.4.1. 依赖注入
        • 1.4.2. 详细的依赖关系和配置
        • 1.4.3. 使用depends-on
        • 1.4.4. 延迟初始化的 Bean
        • 1.4.5. 自动装配协作者
        • 1.4.6. 方法注入
    • 2. Resources
      • 2.1. 介绍
      • 2.2. Resource接口
      • 2.3. 内置Resource实现
      • 2.4. ResourceLoader接口
      • 2.5. ResourcePatternResolver接口
      • 2.6. ResourceLoaderAware接口
      • 2.7. 资源作为依赖
      • 2.8. 应用程序上下文和资源路径
    • 3. 验证、数据绑定和类型转换
      • 3.1. 使用 Spring 的 Validator 接口进行验证
      • 3.2. 将代码解析为错误消息
      • 3.3. Bean 操作和BeanWrapper
      • 3.4. spring类型转换
      • 3.5. spring字段格式
      • 3.6. 配置全局日期和时间格式
      • 3.7. Java Bean 验证
    • 4. SpEL表达式
    • 5. Spring 面向切面编程
      • 5.1. AOP 概念
      • 5.2. Spring AOP 的能力和目标
      • 5.3. AOP 代理
      • 5.4. @AspectJ 支持
        • 5.4.1. 启用@AspectJ 支持
        • 5.4.2. 声明一个切面
        • 5.4.3. 声明切入点
        • 5.4.4. 声明切点
        • 5.4.5. 切面说明
        • 5.4.6. 切面实例化模型
        • 5.4.7. AOP 示例
      • 5.5. 基于模式的 AOP 支持
      • 5.6. 选择要使用的 AOP 声明样式
      • 5.7. 混合切面类型
      • 5.8. 代理机制
      • 5.9. @AspectJ 代理的程序化创建
      • 5.10. 在 Spring 应用程序中使用 AspectJ
      • 5.11.更多资源
    • 6. Spring AOP API
      • 6.1. Spring中的切入点API
      • 6.2. Spring 中的 Advice API
      • 6.3. Spring 中的 Advisor API
      • 6.4. 使用ProxyFactoryBean创建 AOP 代理
      • 6.5. 简洁的代理定义
      • 6.6. 以编程方式创建 AOP 代理ProxyFactory
      • 6.7. 操作切面对象
      • 6.8. 使用“自动代理”工具
      • 6.9. 使用TargetSource实现
      • 6.10. 定义新的切面类型
    • 7. 空指针安全
    • 8. 数据缓冲器和编解码器
    • 9. 日志
    • 10. 附录
      • 10.1. XML 模式
      • 10.2. 自定义XML Schema
        • 10.2.1. 创作 Schema
        • 10.2.2. 编码一个NamespaceHandler
        • 10.2.3. 使用BeanDefinitionParser
        • 10.2.4. 注册处理程序和模式
        • 10.2.5. 在 Spring XML 配置中使用自定义扩展
        • 10.2.6. 更详细的例子
      • 10.3. 应用程序启动步骤
  • 使用redis实现分布式锁
  • Java 安全标准算法名称
  • JDK 9 JEP
  • JDK 10 JEP
  • 人件
    • 《人件》
    • 第一部分 管理人力资源
      • 01 此时此刻,一个项目正在走向失败
      • 02 干酪汉堡,做一个,卖一个
      • 03 维也纳在等你
      • 04 质量——如果时间允许
      • 05 再谈帕金森定律
      • 06 苦杏素
    • 第二部分 办公环境
      • 07 家具警察
      • 08 “朝九晚五在这里啥也完成不了。”
      • 09 在空间上省钱
      • 间奏曲:生产效率度量和不明飞行物
      • 10 大脑时问与身体时间
      • 11 电话
      • 12 门的回归
      • 13 采取保护步骤
    • 第三部分 正确的人
      • 14 霍恩布洛尔因素
      • 15 谈谈领导力
      • 16 雇一名杂耍演员
      • 17 与他人良好合作
      • 18 童年的终结
      • 19 在这儿很开心
      • 20 人力资本
    • 第四部分 高效团队养成
      • 21 整体大于部分之和
      • 22 黑衣团队
      • 23 团队自毁
      • 24 再谈团队自毁
      • 25 竞争
      • 26 一顿意面晚餐
      • 27 敞开和服
      • 28 团队形成的化学反应
    • 第五部分 沃土
      • 29 自我愈复系统
      • 30 与风险共舞
      • 3l 会议、独白和交流
      • 32 终极管理罪恶得主是……
      • 33 “邪恶”电邮
      • 34 让改变成为可能
      • 35 组织型学习
      • 36 构建社区
    • 第六部分 快乐地工作
      • 37 混乱与秩序
      • 38 自由电子
      • 39 霍尔加·丹斯克
由 GitBook 提供支持
在本页

这有帮助吗?

在GitHub上编辑
  1. Spring核心功能
  2. 6. Spring AOP API

6.2. Spring 中的 Advice API

现在我们可以检查 Spring AOP 如何处理通知。

6.2.1. 切面生命周期

每个切面都是一个 Spring bean。切面实例可以在所有切面对象之间共享,或者对于每个切面对象都是唯一的。这对应于每个类或每个实例的切面。

每类切面最常使用。它适用于通用切面,例如事务Advisor。这些不依赖于代理对象的状态或添加新状态。它们仅作用于方法和参数。

每个实例的切面适用于介绍,以支持 mixins。在这种情况下,切面将状态添加到代理对象。

您可以在同一个 AOP 代理中混合使用共享切面和实例切面。

6.2.2. spring的切面类型

Spring 提供了几种切面类型,并且可以扩展以支持任意切面类型。本节介绍基本概念和标准通知类型。

环绕切面

Spring 中最基本的通知类型是围绕通知的拦截。

Spring 与使用方法拦截的环绕通知的 AOP Alliance接口兼容。实现MethodInterceptor和围绕通知实现的类也应该实现以下接口:

public interface MethodInterceptor extends Interceptor {

    Object invoke(MethodInvocation invocation) throws Throwable;
}

invoke()方法的参数MethodInvocation暴露了被调用的方法、目标连接点、AOP 代理和方法的参数。 invoke()方法应该返回调用的结果:连接点的返回值。

以下示例显示了一个简单的MethodInterceptor实现:

public class DebugInterceptor implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("Before: invocation=[" + invocation + "]");
        Object rval = invocation.proceed();
        System.out.println("Invocation returned");
        return rval;
    }
}

注意对MethodInvocation的proceed()方法的调用。这沿着拦截器链向连接点前进。大多数拦截器调用此方法并返回其返回值。但是, MethodInterceptor与任何周围的切面一样,可以返回不同的值或抛出异常,而不是调用proceed 方法。但是,您不想在没有充分理由的情况下执行此操作。

MethodInterceptor实现提供与其他符合 AOP 联盟的 AOP 实现的互操作性。本节其余部分讨论的其他通知类型实现了常见的 AOP 概念,但以特定于 Spring 的方式。虽然使用最具体的通知类型有优势,但如果您可能希望在另一个 AOP 框架中运行方面,请坚持使用MethodInterceptor的环绕通知。请注意,切入点目前在框架之间不能互操作,AOP 联盟目前没有定义切入点接口。

前置通知

更简单的通知类型是之前的通知。这不需要MethodInvocation 对象,因为它只在进入方法之前被调用。

before 通知的主要优点是不需要调用proceed() 方法,因此不会因疏忽而未能沿拦截器链继续执行。

以下清单显示了该MethodBeforeAdvice接口:

public interface MethodBeforeAdvice extends BeforeAdvice {

    void before(Method m, Object[] args, Object target) throws Throwable;
}

(Spring 的 API 设计允许在通知之前使用字段,尽管通常的对象适用于字段拦截,而且 Spring 不太可能实现它。)

请注意,返回类型是void. 之前通知可以在连接点运行之前插入自定义行为,但不能更改返回值。如果之前的通知抛出异常,它会停止拦截器链的进一步执行。异常会沿拦截器链向上传播。如果未选中或在调用方法的签名上,则直接将其传递给客户端。否则,它会被 AOP 代理包装在未经检查的异常中。

以下示例显示了 Spring 中的 before 通知,它计算所有方法调用:

public class CountingBeforeAdvice implements MethodBeforeAdvice {

    private int count;

    public void before(Method m, Object[] args, Object target) throws Throwable {
        ++count;
    }

    public int getCount() {
        return count;
    }
}

前置通知可以与任何切入点一起使用。

异常通知

如果连接点抛出异常,则在连接点返回后调用 Throws 通知。Spring 提供了类型化的 throws 切面。请注意,这意味着该 org.springframework.aop.ThrowsAdvice接口不包含任何方法。它是一个标签接口,标识给定对象实现了一个或多个类型化的 throws 切面方法。这些应采用以下形式:

afterThrowing([Method, args, target], subclassOfThrowable)

只有最后一个参数是必需的。方法签名可能有一个或四个参数,这取决于通知方法是否对方法和参数感兴趣。接下来的两个清单显示了作为 throws 切面示例的类。

如果抛出RemoteException(包括来自子类),则会调用以下切面:

public class RemoteThrowsAdvice implements ThrowsAdvice {

    public void afterThrowing(RemoteException ex) throws Throwable {
        // Do something with remote exception
    }
}

与前面的通知不同,下一个示例声明了四个参数,以便它可以访问调用的方法、方法参数和目标对象。如果抛出ServletException,则调用以下切面:

public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {

    public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
        // Do something with all arguments
    }
}

最后一个示例说明了如何在处理RemoteException和ServletException的单个类中使用这两种方法。任意数量的 throws 切面方法可以组合在一个类中。以下清单显示了最后一个示例:

public static class CombinedThrowsAdvice implements ThrowsAdvice {

    public void afterThrowing(RemoteException ex) throws Throwable {
        // Do something with remote exception
    }

    public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
        // Do something with all arguments
    }
}

如果 throws-advice 方法本身抛出异常,它会覆盖原始异常(即,它会更改抛出给用户的异常)。覆盖异常通常是 RuntimeException,它与任何方法签名兼容。但是,如果 throws-advice 方法抛出检查异常,它必须匹配目标方法声明的异常,因此在某种程度上与特定目标方法签名耦合。不要抛出与目标方法的签名不兼容的未声明的检查异常!

抛出的切面可以与任何切入点一起使用。

返回通知

Spring 中的后返回通知必须实现该 org.springframework.aop.AfterReturningAdvice接口,如下清单所示:

public interface AfterReturningAdvice extends Advice {

    void afterReturning(Object returnValue, Method m, Object[] args, Object target)
            throws Throwable;
}

返回后的通知可以访问返回值(它不能修改)、调用的方法、方法的参数和目标。

返回通知后的以下内容计算所有未引发异常的成功方法调用:

public class CountingAfterReturningAdvice implements AfterReturningAdvice {

    private int count;

    public void afterReturning(Object returnValue, Method m, Object[] args, Object target)
            throws Throwable {
        ++count;
    }

    public int getCount() {
        return count;
    }
}

此切面不会更改执行路径。如果它抛出异常,它会被抛出拦截器链而不是返回值。

返回后的通知可以与任何切入点一起使用。

引入通知

Spring 将引入通知视为一种特殊的拦截通知。

简介需要实现以下接口的 IntroductionAdvisor和 IntroductionInterceptor:

public interface IntroductionInterceptor extends MethodInterceptor {

    boolean implementsInterface(Class intf);
}

从AOP联盟MethodInterceptor接口继承的invoke()方法必须实现引入。也就是说,如果被调用的方法在引入的接口上,则引入拦截器负责处理方法调用——它不能调用proceed()。

引入通知不能与任何切入点一起使用,因为它仅适用于类,而不是方法级别。您只能将引入通知与IntroductionAdvisor一起使用 ,它具有以下方法:

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {

    ClassFilter getClassFilter();

    void validateInterfaces() throws IllegalArgumentException;
}

public interface IntroductionInfo {

    Class<?>[] getInterfaces();
}

没有MethodMatcher,因此,没有Pointcut与介绍切面相关联。只有类过滤是合乎逻辑的。

该getInterfaces()方法返回此Advisor引入的接口。

该validateInterfaces()方法用于内部查看引入的接口是否可以被IntroductionInterceptor配置的.

考虑一个来自 Spring 测试套件的示例,假设我们想要为一个或多个对象引入以下接口:

public interface Lockable {
    void lock();
    void unlock();
    boolean locked();
}

这说明了一个混合。我们希望能够将切面对象转换为Lockable,无论它们的类型如何,并调用锁定和解锁方法。如果我们调用该lock()方法,我们希望所有的 setter 方法都抛出一个LockedException. 因此,我们可以添加一个方面,该方面提供了使对象不可变的能力,而他们对此一无所知:AOP 的一个很好的例子。

首先,我们需要一个可以完成繁重工作的IntroductionInterceptor。在这种情况下,我们扩展了org.springframework.aop.support.DelegatingIntroductionInterceptor 便利类。我们可以直接实现IntroductionInterceptor,但在大多数情况下使用DelegatingIntroductionInterceptor是最好的。

DelegatingIntroductionInterceptor旨在将介绍委托给所引入接口的实际实现,隐藏使用拦截来做到这一点。您可以使用构造函数参数将委托设置为任何对象。默认委托(使用无参数构造函数时)是this. 因此,在下一个示例中,委托是DelegatingIntroductionInterceptor的子类LockMixin 。给定一个委托(默认情况下,是它本身),一个DelegatingIntroductionInterceptor实例会查找委托实现的所有接口(除了 IntroductionInterceptor)并支持对其中任何一个的介绍。诸如子类LockMixin可以调用该suppressInterface(Class intf) 方法来抑制不应该暴露的接口。然而,无论IntroductionInterceptor准备支持多少接口,都应该使用 IntroductionAdvisor控制实际暴露的接口。引入的接口隐藏了目标对同一接口的任何实现。

因此,LockMixin扩展DelegatingIntroductionInterceptor并自身实现Lockable 了。超类会自动选择可以支持引入的Lockable,所以我们不需要指定。我们可以通过这种方式引入任意数量的接口。

注意locked实例变量的使用。这有效地为目标对象中保存的状态添加了额外的状态。

以下示例显示了LockMixin类:

public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {

    private boolean locked;

    public void lock() {
        this.locked = true;
    }

    public void unlock() {
        this.locked = false;
    }

    public boolean locked() {
        return this.locked;
    }

    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {
            throw new LockedException();
        }
        return super.invoke(invocation);
    }

}

通常,您不需要重写该invoke()方法。DelegatingIntroductionInterceptor的实现(如果方法被引入,则调用 delegate方法,否则向连接点接入)通常就足够了。在本例中,我们需要添加一个检查:如果处于锁定模式,则不能调用任何 setter 方法。

所需的引入只需要保存一个不同的 LockMixin实例并指定引入的接口(在这种情况下,只有 Lockable)。一个更复杂的示例可能会引用引入拦截器(将被定义为原型)。在这种情况下,没有与LockMixin相关的配置,因此我们使用new. 下面的例子展示了我们的LockMixinAdvisor类:

public class LockMixinAdvisor extends DefaultIntroductionAdvisor {

    public LockMixinAdvisor() {
        super(new LockMixin(), Lockable.class);
    }
}

我们可以非常简单地应用这个切面,因为它不需要配置。(但是,没有IntroductionAdvisor是不可能使用IntroductionInterceptor的 。)与引入一样,Advisor必须是每个实例的,因为它是有状态的。对于每个被切入的对象,我们需要一个不同的LockMixinAdvisor实例,因此需要 LockMixin。 Advisor 包含被切入对象状态的一部分。

我们可以通过使用 Advised.addAdvisor() 方法或(推荐的方式)在 XML 配置中以编程方式应用此advisor 程序,就像任何其他advisor 程序一样。下面讨论的所有代理创建选项,包括“自动代理创建器”,都可以正确处理引入和有状态混合。

上一页6.1. Spring中的切入点API下一页6.3. Spring 中的 Advisor API

最后更新于1年前

这有帮助吗?