Spring框架之Spring AOP

手写Spring框架之AOP 简介 手写Spring框架第一篇博客(必读): 手写Spring框架 前面两篇博客已经实现了Bean容器, IOC功能和MVC功能, 本篇博客来实现AOP功能和事务管理. 在看下面的内容之前, 一定要先回顾下Spring AOP和动态代理. Spring AOP 动态代理 handwritten-mvc-framwork 实现 定义注解 (1) 切面注解 @Target(ElementType.T... 阅读详情

AOP概念

让我们首先定义一些核心的AOP概念和术语:

  • Aspect:切面。一个跨越多个类的关注点的模块化。在Spring AOP中,切面是通过使用常规类(基于模式的方法)或使用@Aspect注解的常规类(@AspectJ风格)来实现的。
  • Join point:连接点。在程序执行过程中的一个点,例如一个方法的执行或一个异常的处理。在Spring AOP中,一个连接点总是代表一个方法的执行。
  • Advice:通知。一个切面在一个特定的连接点采取的行动。不同类型的Advice包括 "around"、"before "和 "after "的通知。(许多AOP框架,包括Spring,都将通知建模为一个拦截器,并在连接点周围维护一个拦截器链。
  • Pointcut:切点。带有通知的连接点,在程序中主要体现为书写Pointcut表达式。Spring默认使用AspectJ的切点表达式语言。
  • Introduction:代表一个类型声明额外的方法或字段。Spring AOP允许你为任何Advice的对象引入新的接口(以及相应的实现)。例如,你可以使用引入来使一个bean实现IsModified接口,以简化缓存。(Introduction在AspectJ社区中被称为类型间声明)。
  • Target object:目标对象。被一个或多个切面通知的对象。也被称为 "Advice对象"。由于Spring AOP是通过使用运行时代理来实现的,这个对象总是一个被代理的对象。
  • AOP proxy:AOP代理。一个由AOP框架创建的对象,以实现切面契约(通知方法执行等)。在Spring框架中,AOP代理是一个JDK动态代理或CGLIB代理。
  • Weaving:将aspect与其他应用类型或对象联系起来,以创建一个Advice对象。这可以在编译时(例如,使用AspectJ编译器)、加载时或运行时完成。Spring AOP和其他纯Java AOP框架一样,在运行时进行织入。

Spring AOP包括以下类型的Advice:

  • Before advice:在连接点之前运行的通知,但它没有能力阻止执行流进行到连接点(除非它抛出一个异常)。
  • After returning advice:在一个连接点正常完成后运行的Advice(例如,如果一个方法返回而没有抛出异常)。
  • After throwing advice:当一个方法通过抛出异常退出时要运行的Advice。
  • After (finally) advice:无论连接点以何种方式退出(正常或异常返回),都要运行Advice。
  • Around advice:围绕连接点的Advice,如方法调用。这是最强大的一种Advice。Around advice可以在方法调用之前和之后执行自定义行为。它还负责选择是否继续进行连接点,或者通过返回自己的返回值或抛出一个异常来缩短Advice方法的执行。

Around advice是最通用的一种Advice。由于Spring AOP和AspectJ一样,提供了全面的Advice类型,我们建议你使用功能最弱的Advice类型来实现所需的行为。例如,如果你只需要用一个方法的返回值来更新缓存,那么你最好实现一个After returning advice,而不是一个Around advice,尽管Around advice可以完成同样的事情。使用最具体的Advice类型可以提供一个更简单的编程模型,减少错误的可能性。

所有的Advice参数都是静态类型的,因此你可以使用适当类型的Advice参数(例如,方法执行的返回值的类型),而不是Object数组。

由切点匹配的连接点的概念是AOP的关键,它区别于只提供拦截的旧技术。Pointcuts使Advice能够独立于面向对象的层次结构而成为目标。例如,你可以将提供声明性事务管理的建议应用于跨越多个对象的一组方法(如服务层的所有业务操作)。

AOP Proxy

Spring AOP默认使用标准的JDK动态代理作为AOP代理。这使得任何接口(或一组接口)都可以被代理。

Spring AOP也可以使用CGLIB代理。这对于代理类(不是接口)来说是必要的。默认情况下,如果一个业务对象没有实现一个接口,就会使用CGLIB。由于对接口而不是类进行编程是很好的做法,业务类通常实现一个或多个业务接口。在那些(希望是罕见的)需要向未在接口上声明的方法提供Advice的情况下,或者需要将代理对象作为具体类型传递给方法的情况下,可以强制使用CGLIB。

@AspectJ

@AspectJ指的是将aspect作为带有注解的普通Java类来声明的一种风格。

启用@AspectJ

要在Spring配置中使用@AspectJ切面,需要启用Spring支持,以根据@AspectJ切面配置Spring AOP,并根据Bean是否被这些切面通知而自动代理。通过自动代理,我们的意思是,如果Spring确定一个Bean被一个或多个切面所通知,它会自动为该Bean生成一个代理,以拦截方法调用,并确保建议在需要时被运行。

@AspectJ支持可以通过XML或Java风格的配置来启用。在这两种情况下,你还需要确保AspectJ的aspectjweaver.jar库在你的应用程序的classpath上(版本1.8或更高)。

用Java配置启用@AspectJ 要通过Java @Configuration启用@AspectJ支持,请添加@EnableAspectJAutoProxy注解,如下例所示:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

}

Aspect声明

在启用@AspectJ的情况下,任何在你的应用程序上下文中定义的Bean,其类是@AspectJ切面(具有@Aspect注解),会被Spring自动检测到,并用于配置Spring AOP。接下来的两个例子显示了一个不怎么有用的切面所需的最小定义:

package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {

}
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public NotVeryUsefulAspect myAspect(){
       return new NotVeryUsefulAspect();
    }
}

Pointcut声明

Pointcuts确定连接点,从而使我们能够控制Advice的运行时间。Spring AOP只支持Spring Bean的方法执行连接点,所以你可以把pointcut看作是与Spring Bean上的方法执行相匹配。一个切点声明有两个部分:一个由名称和任何参数组成的签名,以及一个切点表达式,它决定了我们到底对哪些方法的执行感兴趣。在AOP的@AspectJ注解式中,一个pointcut签名是由一个常规的方法定义提供的,而pointcut表达式是通过使用@Pointcut注解来表示的(作为pointcut签名的方法必须有一个void返回类型)。

@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature

Pointcut表达式

Spring AOP支持以下AspectJ的切点表达式,以便在切点表达式中使用:

  • execution:用于匹配方法执行的连接点。这是在使用Spring AOP时要使用的主要切点指定符。
  • within:将匹配限制在某些类型的连接点上(当使用Spring AOP时,在匹配类型中声明的方法的执行)。
  • this:限制匹配到连接点(使用Spring AOP时方法的执行),其中Bean引用(Spring AOP代理)是给定类型的实例。
  • target:限制对连接点的匹配(使用Spring AOP时方法的执行),目标对象(被代理的应用程序对象)是给定类型的实例。
  • args:限制对连接点的匹配(使用Spring AOP时方法的执行),参数是给定类型的实例。
  • @target:限制对连接点的匹配(使用Spring AOP时方法的执行),其中执行对象的类有一个给定类型的注释。
  • @args:限制对连接点的匹配(使用Spring AOP时方法的执行),其中实际传递的参数的运行时间类型有给定类型的注释。
  • @within:限制匹配到具有给定注释的类型中的连接点(使用Spring AOP时,执行在具有给定注释的类型中声明的方法)。
  • @annotation:限制匹配到连接点的主体(在Spring AOP中被运行的方法)具有给定注释的连接点。

Pointcut表达式组合

你可以通过使用&&、||和!来组合pointcut表达式。你也可以通过名字来引用pointcut表达式。下面的例子显示了三个切点表达式:

@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {} 
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {} 
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}

共享通用pointcut定义

在处理企业应用程序时,开发人员经常想从几个方面来引用应用程序的模块和特定的操作集。我们建议定义一个CommonPointcuts切面,它可以为这个目的捕获通用的pointcut表达。

package com.xyz.myapp;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class CommonPointcuts {
    /**
     * A join point is in the web layer if the method is defined
     * in a type in the com.xyz.myapp.web package or any sub-package
     * under that.
     */
    @Pointcut("within(com.xyz.myapp.web..*)")
    public void inWebLayer() {}
    /**
     * A join point is in the service layer if the method is defined
     * in a type in the com.xyz.myapp.service package or any sub-package
     * under that.
     */
    @Pointcut("within(com.xyz.myapp.service..*)")
    public void inServiceLayer() {}
    /**
     * A join point is in the data access layer if the method is defined
     * in a type in the com.xyz.myapp.dao package or any sub-package
     * under that.
     */
    @Pointcut("within(com.xyz.myapp.dao..*)")
    public void inDataAccessLayer() {}
    /**
     * A business service is the execution of any method defined on a service
     * interface. This definition assumes that interfaces are placed in the
     * "service" package, and that implementation types are in sub-packages.
     *
     * If you group service interfaces by functional area (for example,
     * in packages com.xyz.myapp.abc.service and com.xyz.myapp.def.service) then
     * the pointcut expression "execution(* com.xyz.myapp..service.*.*(..))"
     * could be used instead.
     *
     * Alternatively, you can write the expression using the 'bean'
     * PCD, like so "bean(*Service)". (This assumes that you have
     * named your Spring service beans in a consistent fashion.)
     */
    @Pointcut("execution(* com.xyz.myapp..service.*.*(..))")
    public void businessService() {}
    /**
     * A data access operation is the execution of any method defined on a
     * dao interface. This definition assumes that interfaces are placed in the
     * "dao" package, and that implementation types are in sub-packages.
     */
    @Pointcut("execution(* com.xyz.myapp.dao.*.*(..))")
    public void dataAccessOperation() {}
}

Advice声明

Advice与一个切点表达式相关联,在切点匹配的方法执行之前、之后或around 运行。该切点表达式可以是对一个命名的切点的简单引用,也可以是一个就地声明的切点表达式。

Before Advice

你可以通过使用@Before注解在一个切面声明before advice:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
    @Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }
}

如果我们使用pointcut表达式,我们可以把前面的例子改写成下面的例子:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
    @Before("execution(* com.xyz.myapp.dao.*.*(..))")
    public void doAccessCheck() {
        // ...
    }

After Returning Advice

当一个匹配的方法执行正常返回时,返回后的Advice会运行。你可以通过使用@AfterReturning注解来声明它:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
    @AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doAccessCheck() {
        // ...
    }
}

有时,你需要访问Advice中返回的值。你可以使用绑定返回值的@AfterReturning的形式来获得这种访问权,如下例所示:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
    @AfterReturning(
        pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
        returning="retVal")
    public void doAccessCheck(Object retVal) {
        // ...
    }
}

After Throwing Advice

当一个匹配的方法的执行因抛出异常而退出时,After Throwing Advice会运行。你可以通过使用@AfterThrowing注解来声明它,如下例所示:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
    @AfterThrowing("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doRecoveryActions() {
        // ...
    }
}

通常情况下,你希望Advice只在给定类型的异常被抛出时运行,而且你也经常需要在Advice中访问被抛出的异常。你可以使用throwing属性来限制匹配(如果需要的话--否则使用Throwable作为异常类型),并将抛出的异常绑定到advice参数上。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
    @AfterThrowing(
        pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
        throwing="ex")
    public void doRecoveryActions(DataAccessException ex) {
        // ...
    }
}

After (Finally) Advice

当一个匹配的方法执行退出时,After (Finally) Advice会运行。它是通过使用@After注解来声明的。After通知必须准备好处理正常和异常的返回条件。它通常用于释放资源和类似的目的。下面的例子展示了如何使用after finally通知:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
    @After("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    public void doReleaseLock() {
        // ...
    }
}

Around Advice

最后一种advice是Around Advice。Around Advice是一个与匹配的方法的执行而运行。它有机会在方法运行之前和之后进行工作,并决定何时、如何、甚至是否真正运行该方法。如果你需要以线程安全的方式分享方法执行前后的状态,例如启动和停止一个定时器,那么Around Advice经常被使用。

Around Advice是通过用@Around注解来声明一个方法的。该方法应该声明Object为其返回类型,并且该方法的第一个参数必须是ProceedingJoinPoint类型。在Advice中,你必须在ProceedingJoinPoint上调用proceed(),以使底层方法运行。在没有参数的情况下调用proceed()将导致调用者的原始参数在底层方法被调用时被提供给它。对于高级用例,有一个重载的 proceed() 方法,它接受一个参数数组(Object[] )。当底层方法被调用时,数组中的值将被用作该方法的参数。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
    @Around("com.xyz.myapp.CommonPointcuts.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }
}

Advice Parameters

Spring提供了完全类型化的Advice,这意味着你可以在Advice签名中声明你需要的参数(就像我们在前面看到的返回和抛出的例子那样),而不是一直使用Object[]数组。我们将在本节后面看到如何使参数和其他上下文值对Advice主体可用。首先,我们看一下如何编写通用Advice,它可以找出advice当前所通知的方法。

访问当前连接点

任何Advice方法都可以声明一个org.aspectj.lang.JoinPoint类型的参数,作为它的第一个参数。请注意,aroud advice需要声明一个ProceedingJoinPoint类型的第一个参数,它是JoinPoint的一个子类。

JoinPoint接口提供了许多有用的方法:

  • getArgs():返回方法的参数。
  • getThis():返回代理对象。
  • getTarget():返回目标对象。
  • getSignature():返回正在被通知方法的描述。
  • toString():打印被通知的方法的有用描述。

向advice传递参数我们已经看到了如何绑定返回值或异常值(使用返回后和抛出后建议)。为了使参数值对advice主体可用,你可以使用args的绑定形式。如果你在args表达式中使用参数名来代替类型名,那么当advice被调用时,相应参数的值将作为参数值被传递。一个例子可以让我们更清楚地了解这一点。假设你想advice执行将一个帐户对象作为第一个参数的DAO操作,并且你需要在advice中访问该帐户。你可以写如下内容:

@Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account) {
    // ...
}

pointcut表达式args(account,..)部分有两个目的。首先,它将匹配限制在方法的执行上,即方法至少需要一个参数,并且传递给该参数的参数是一个账户的实例。其次,它使实际的账户对象通过账户参数对advice可用。

另一种写法是声明一个pointcut,当它与一个连接点匹配时 "提供 "账户对象的值,然后从advice中引用这个命名的pointcut:

@Pointcut("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
    // ...
}

Advice参数和泛型Spring AOP可以处理类声明和方法参数中使用的泛型。假设你有一个像下面这样的泛型:

public interface Sample<T> {
    void sampleGenericMethod(T param);
    void sampleGenericCollectionMethod(Collection<T> param);
}

你可以将方法类型的拦截限制在某些参数类型上,办法是将advice参数与你想拦截方法的参数类型联系起来:

@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
    // Advice implementation
}

指定参数名称Advice调用中的参数绑定依赖于将pointcut表达式中使用的名称与advice和pointcut方法签名中声明的参数名称相匹配。参数名称无法通过Java反射获得,因此Spring AOP使用以下策略来确定参数名称。

如果用户已经明确指定了参数名,则使用指定的参数名。Advice和pointcut注解都有一个可选的argNames属性,你可以用它来指定被注解方法的参数名。这些参数名在运行时是可用的。下面的例子展示了如何使用argNames属性:

@Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",
        argNames="bean,auditable")
public void audit(Object bean, Auditable auditable) {
    AuditCode code = auditable.value();
    // ... use code and bean
}

如果第一个参数是JoinPoint、ProceedingJoinPoint或JoinPoint.StaticPart类型,你可以从argNames属性的值中省略参数的名称。例如,如果你修改前面的advice以接收连接点对象,argNames属性不需要包括它:

@Before(value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",
        argNames="bean,auditable")
public void audit(JoinPoint jp, Object bean, Auditable auditable) {
    AuditCode code = auditable.value();
    // ... use code, bean, and jp
}

带参数的进程我们在前面说过,我们将描述如何编写一个在Spring AOP和AspectJ中一致运行的带参数的继续调用。解决方案是确保advice签名按顺序绑定每个方法参数。下面的例子展示了如何做到这一点:

@Around("execution(List<Account> find*(..)) && " +
        "com.xyz.myapp.CommonPointcuts.inDataAccessLayer() && " +
        "args(accountHolderNamePattern)")
public Object preProcessQueryPattern(ProceedingJoinPoint pjp,
        String accountHolderNamePattern) throws Throwable {
    String newPattern = preProcess(accountHolderNamePattern);
    return pjp.proceed(new Object[] {newPattern});
}

Advice排序

当多个advice都想在同一个连接点运行时,会发生什么?Spring AOP遵循与AspectJ相同的优先级规则来决定advice的执行顺序。优先级最高的advice在 "进入 "时首先运行。从一个连接点 "出来 "时,优先级最高的advice最后运行。

Introductions

Introductions(在AspectJ中被称为类型间声明)使一个切面能够声明advice对象实现一个给定的接口,并代表这些对象提供该接口的实现。

你可以通过使用@DeclareParents注解来做一个Introductions。这个注解被用来声明匹配的类型有一个新的父类(因此得名)。例如,给定一个名为UsageTracked的接口和一个名为DefaultUsageTracked的接口的实现,下面这个切面声明所有服务接口的实现者也实现UsageTracked接口(例如,通过JMX进行统计):

@Aspect
public class UsageTracking {
    @DeclareParents(value="com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class)
    public static UsageTracked mixin;
    @Before("com.xyz.myapp.CommonPointcuts.businessService() && this(usageTracked)")
    public void recordUsage(UsageTracked usageTracked) {
        usageTracked.incrementUseCount();
    }
}

切面实例模型

默认情况下,每个切面在应用上下文中都有一个实例。AspectJ把这称为单例实例模型。我们可以用其他的生命周期来定义方面。Spring支持AspectJ的perthis和pertarget实例化模型;目前不支持percflow、percflowbelow和pertypewithin。你可以通过在@Aspect注解中指定一个perthis子句来声明一个perthis方面。请看下面的例子:

@Aspect("perthis(com.xyz.myapp.CommonPointcuts.businessService())")
public class MyAspect {
    private int someState;
    @Before("com.xyz.myapp.CommonPointcuts.businessService()")
    public void recordServiceUsage() {
        // ...
    }
}

AOP demo

业务服务的执行有时会因为并发性问题而失败(例如,死锁失败者)。如果该操作被重试,那么它很可能在下一次尝试中成功。对于在这种情况下适合重试的业务服务(不需要回到用户那里解决冲突的idempotent操作),我们希望透明地重试操作,以避免客户端看到PessimisticLockingFailureException。这是一个明显跨越服务层中多个服务的需求,因此,非常适合通过一个切面来实现。

因为我们想重试操作,所以我们需要使用around advice,以便我们可以多次调用Proceed。下面的列表显示了切面基本的实现。

@Aspect
public class ConcurrentOperationExecutor implements Ordered {
    private static final int DEFAULT_MAX_RETRIES = 2;
    private int maxRetries = DEFAULT_MAX_RETRIES;
    private int order = 1;
    public void setMaxRetries(int maxRetries) {
        this.maxRetries = maxRetries;
    }
    public int getOrder() {
        return this.order;
    }
    public void setOrder(int order) {
        this.order = order;
    }
    @Around("com.xyz.myapp.CommonPointcuts.businessService()")
    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
        int numAttempts = 0;
        PessimisticLockingFailureException lockFailureException;
        do {
            numAttempts++;
            try {
                return pjp.proceed();
            }
            catch(PessimisticLockingFailureException ex) {
                lockFailureException = ex;
            }
        } while(numAttempts <= this.maxRetries);
        throw lockFailureException;
    }
}

注意,这个方面实现了Ordered接口,这样我们就可以把切面的优先级设置得比事务advice高(我们希望每次重试都是一个新的事务)。maxRetries和order属性都是由Spring配置的。主要的动作发生在around advice的doConcurrentOperation中。请注意,就目前而言,我们将重试逻辑应用于每个businessService()。我们尝试进行,如果失败了,出现PessimisticLockingFailureException,我们就再试一次,除非我们已经用尽了所有的重试尝试。

<aop:aspectj-autoproxy/>
<bean id="concurrentOperationExecutor" class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
    <property name="maxRetries" value="3"/>
    <property name="order" value="100"/>
</bean>

为了细化这个切面,使它只重试幂等操作,我们可以定义下面的幂等注解:

@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
    // marker annotation
}

然后我们可以使用注解来注解服务操作的实现。对只重试幂等操作切面的修改涉及到细化pointcut表达式,以便只有@Idempotent操作可以匹配,如下所示:

@Around("com.xyz.myapp.CommonPointcuts.businessService() && " +
        "@annotation(com.xyz.myapp.service.Idempotent)")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
    // ...
}
Spring框架中AOP应用的入门案例 面向切面编程(AOP)是软件开发中的一种编程范式,它通过分离横切关注点(cross-cutting concerns)来增加模块化。在Spring框架中,AOP被广泛应用于事务管理、安全检查、日志记录和缓存等方面。它允许开发者定义方法执行前后以及抛出异常时需要执行的代码(通知),而不需要修改原有业务逻辑。Spring AOP利用动态代理机制来实现AOP,支持方法级别的拦截。接下来,本文将深入探讨AOP的核心概念,包括切面、通知、连接点、织入等,并比较Spring AOP与其他AOP实现的不同之处。 阅读详情

相关推荐

如何在Spring Boot中使用@AfterReturning注解

在本文中,我们介绍了Spring Boot AOP中的@AfterReturning注解,它用于定义在目标方法成功返回后执行的切面逻辑。我们通过一个图书管理系统的实例演示了@AfterReturning的使用方式,并在成功查询图书时记录了查询的时间和返回的结果。 AOP的强大之处在于它允许我们在不修改原有业务逻辑代码的情况下,将横切关注点(如日志记录、安全检查等)与业务逻辑分离。这样,我们可以更好地实现代码的复用和模块化,提高了应用程序的可维护性和可扩展性。 总体而言,Spring Boot AOP为我们提供了一个优雅且强大的方式来管理代码中的横切关注点,使得我们可以更专注于业务逻辑的实现,而不必担心这些横切关注点的具体实现。

@AfterReturning配置

AfterReturning和before,after,around不同是可以获取织入函数的返回值,配置复杂一点。 如果切入点如下: [java] view plaincopyprint? package com.leanyu.lcsystem.pointcut;      import org.aspectj.lang.annotat

z69183787的专栏 9160

Java 简易版 UDP 多人聊天室

【代码】Java 简易版 UDP 多人聊天室。

nmy15570188135的博客 1187

Spring Aop AfterReturning接收返回值

包结构: Spring.xml UserDao.java 测试类Main方法 LogAspect.java 测试结果: @AfterReturning标签属性分析: value值: 可以写Aop的表达式,如execution、args、within等,多个之间使用&& || ...

aar49191的博客 2445

静态时序分析(Static Timing Analysis, STA):简介及内容导航

静态时序分析(简称STA)是用来验证数字设计时序的技术之一,另外一种验证时序的方法是时序仿真,时序仿真可以同时验证功能和时序。“时序分析”这个术语就是用来指代“静态时序分析“或”时序仿真“这两种方法之一,简单来说,时序分析的目的就是为了解决设计中的各种时序问题。STA被称为静态的原因是其对于设计的分析是静态地执行的,并不依赖于施加在输入端口上的激励。相比之下,时序仿真则可以被视作动态地执行对设计的分析,具体过程描述如下:施加一组激励,观察在这组激励下电路行为是否符合要求,然后换一组激。

Starry__的博客 1992

手把手教你用支付宝密钥工具生成RSA2密钥对(含Windows/Mac操作截图)

本文详细介绍了如何使用支付宝密钥工具生成RSA2密钥对,包括Windows和Mac平台的操作步骤与截图。从工具下载、安装到密钥生成、配置支付宝平台,再到开发环境集成实战,手把手教你完成支付宝支付接口对接。特别强调密钥安全管理和最佳实践,帮助开发者避免常见安全隐患。

mongodb5scout的博客 257

Spring框架知识总结

Spring介绍 Spring核心是Ioc和Aop Ioc就是把对象放入容器中(xml配置文件,使用bean标签,注解),从容器中获取使用,都是单例对象比如dao类 service类 controller类 工具类 不需要放入容器中:实体类,servlet和listener(过滤器)和filter(监听器) spring是一个容器,管理对象,给属性赋值,底层是创建对象,使用的是反射机制 ioc和aop:减少对代码的改动,也能实现不同的功能,实现解耦合 pom.xml配置文件中加入依赖 id.

Chonglin 1126

19-5 ACC 自适应巡航控制系统需求

本专题由深圳季连AIgraphX李博及团队出品,主要讲解ACC自适应巡航控制系统的开发与仿真测试。具体说来,包括ACC标准/法规分析、系统需求、系统架构、软件需求、软件架构、算法建模、验证场景分析、仿真实验搭建等内容。 本节主要讲ACC系统需求。

AIgraphX 1089

Spring框架AOP学习总结(下)

文章目录1、 AOP 的概述1、1 为什么学习 AOP1、2 AOP底层实现: 代理机制(了解)2、 Spring 的基于 AspectJ 的 AOP 开发(XML 的方式)2.1 AOP 的开发中的相关术语:2.2 Spring 使用 AspectJ 进行 AOP 的开发入门(XML 的方式):2.2.1 引入相应的 jar 包2.2.2 引入 Spring 的配置文件2.2.3 编写目标类...

宜春 1万+

ComfyUI节点流实战:用Wan2.1制作电商短视频全流程(附人物/商品模板)

本文提供了一份详尽的ComfyUI实战教程,指导用户如何利用通义万相Wan2.1图生视频模型,高效制作适用于抖音等平台的电商短视频。内容涵盖从环境部署、核心工作流搭建,到针对服装、3C数码等品类的高级提示词模板与参数调优,旨在帮助电商从业者快速生成高质量、高保真商品展示视频,显著提升内容生产效率。

potato的博客 1281

【通俗易懂】Windows系统安装TensorRT

NVIDIA TensorRT是一个由NVIDIA公司开发的用于深度学习推理的高性能SDK。它专门设计用于在NVIDIA GPU上进行高效的神经网络推理,能够大幅度提升深度学习模型的推理速度和效率。TensorRT的主要特点包括:模型优化:TensorRT通过层融合、精度校准、动态形状等技术优化模型,减少推理时的计算量和内存占用。多精度推理:支持多种精度推理,包括FP32、FP16、INT8等,以平衡性能和精度。

王尼莫的博客 1587

Spring 框架之 AOP 原理剖析

前言 AOP(Aspect Oriented Programming)面向切面编程是 Spring 框架最核心的组件之一,它通过对程序结构的另一种考虑,补充了 OOP(Object-Oriented Programming)面向对象编程。在 OOP 中模块化的关键单元是类,而在 AOP 中,模块化单元是切面。也就是说 AOP 关注的不再是类,而是一系列类里面需要共同能力的行为。 本文内容主要包括:...

优快云 官方博客 6594

Silvaco TCAD实战 | SiC MOSFET工艺仿真与关键参数DOE分析

本文详细介绍了使用Silvaco TCAD进行SiC MOSFET工艺仿真与关键参数DOE分析的实战方法。通过外延生长建模、离子注入工艺调试等步骤,结合DOE分析优化器件性能,帮助工程师在设计阶段预判电学特性,提升产品可靠性。文章还分享了网格划分、界面态建模等实用技巧,助力实现从仿真到产品的闭环验证。

weixin_30235225的博客 507

Spring框架--AOP框架

什么是 AOP 的技术? 在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程 AOP:面向切面编程.(思想.---解决 OOP 遇到一些问题)AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存) 为什么要学习 AOP--可以在不修改源代码的前提下,对程序进行增强。运行期间,不修改源代码的情况下对已有的方法进行增强 优势(1)JDK 的动态代理技术 (2)cglib 代理技术 Joinpoint(连接点) 所谓连

2301_81535770的博客 822

PreScan快速入门到精通第二十一讲驾驶员模型之驾驶员在环

请注意,操纵杆的输出角度是以度为单位的,而方向盘执行器希望其输入是以弧度为单位的。当选择一个支持的方向盘时,PreScan会自动将按钮映射到正确的功能上(如换挡),并设置轴的正确范围(如转向角度)。该系统中的所有其他组件都是为了提供正确的按钮映射,并为所选的方向盘设置正确的范围。对于每一个额外连接的控制器,它们的ID会增加一个,例如第二个控制器的设备ID为1,第三个控制器的设备ID为2,等等。由于所有的方向盘最初放在编译表上的设备ID都是0,所以用户应该先进行正确的调整,将每个控制器设置为正确的设备ID。.

小明师兄的博客 1423

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Spring框架中对于AOP的理解

Spring AOP 通过切面封装横切关注点,实现了业务逻辑与非业务逻辑的解耦,提高了代码的复用性和可维护性。其核心是通过动态代理在目标方法执行过程中嵌入切面逻辑,常用注解式配置,广泛应用于日志、事务、安全等场景。理解 AOP 是掌握 Spring 框架的关键。

Z123C456H的博客 742

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Spring 框架的 AOP

Spring 框架的 AOP Spring 框架的一个关键组件是面向方面的编程(AOP)框架。面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样的常见的很好的方面的例子,如日志记录、审计、声明式事务、安全性和缓存等。 在 OOP 中,关键单元模块度是类,而在 AOP 中单元模块度是方面。依赖注入帮助你对应用程序对象相互解耦和 AOP 可以帮助你从它们所影响的对象中对横切关注点解耦。AOP 是像

qq_42918433的博客 146

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Spring框架-AOP

Asperct Oriented Programming 面向切面编程。是一种利用“横切”的技术(底层实现就是动态代理),对原有的业务逻辑进行拦截,并且可以在拦截的横切面上添加特定的业务逻辑,对原有的业务进行增强。基于动态代理实现在不改变原有业务的情况下,对业务逻辑进行增强。

f135917h的博客 763

【Spring框架】AOP

文章目录AOP简介AOP相关术语AOP的设计原理和思想1、AOP横向抽象技术的介绍2、使用代理模式的Java程序执行流3、Spring AOP的工作原理AOP的使用1、引入AOP需要的相关jar包2、配置XML文件3、写出相关实例(实现类和增强类)(1)基于XML配置型的实现4、配置切入点5、使用AOP(2)基于注解的方式实现4、配置XML文件5、在增强类上添加注解6、使用AOP AOP简介 AOP(全称Aspect Oriented Programming) 即:面向切面编程。 通过预编译方式和运行期间

Super_Powerbank的博客 612

Spring框架的AOP使用方法

本文介绍了AOP(面向切面编程)的概念、原理及实现方式。AOP通过动态代理在不修改源代码的情况下增强业务逻辑,降低耦合度。底层实现分为JDK动态代理(针对有接口的情况)和CGLIB动态代理(无接口情况)。文章详细讲解了AOP术语(连接点、切入点、通知、切面)和五种通知类型(@Before、@After、@AfterReturning、@Around、@AfterThrowing)。重点阐述了基于AspectJ的两种AOP实现方式:注解方式(推荐)和XML配置方式,包括切入点表达式语法和增强类优先级设置。

MyNAMS的博客 1015

Spring框架AOP思想

Spring框架AOP思想 一、AOP简介 1、AOP概念:面向切面编程,通过预编译方式和运行期动态代理,实现程序功能的统一维护的一种技术;利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 2、AOP功能:Aop的功能主要是为了拦截或者实现日志安全检查,一些检查的工作,aop也常用于事务管理,防止垃圾数据进入数据库。 3...

xfj_csdn的博客 257

spring框架中Aop

1,基本介绍 Spring 框架的一个关键组件是面向方面的编程(AOP)框架。面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样的常见的很好的方面的例子,如日志记录、审计、声明式事务、安全性和缓存等。 在 OOP 中,关键单元模块度是类,而在 AOP 中单元模块度是方面。依赖注入帮助...

weixin_45491031的博客 320

关于Spring框架AOP的理解

关于Spring框架AOP的个人理解 1.AOP的概念: 百度结果: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 个人理解: AOP是在不通过修改原有业务的基础上,为了增强某些业务的功能而诞生的一种编程思想,至于这个切面我希望可以通过下面的图示来说明。 AOP切面开发的理解: 正常代码是纵向开发的,然而为了解决在更改代码时防止对代码实现误改和其他原因导致源码出问题,则要在每个类都添加一个代理

qq_41978509的博客 455

Spring框架中的核心技术之AOP

Spring框架的核心技术之AOP,面向切面编程,动态代理,Spring面试必问

weixin_44362089的博客 5855

Spring框架——IOC与AOP

Spring 框架两大核心机制(IoC、AOP) IoC(控制反转)/ DI(依赖注入) AOP(面向切面编程) Spring 是一个企业级开发框架,是软件设计层面的框架,优势在于可以将应用程序进行分层,开发者可以自主选择组件。 MVC:Struts2、Spring MVC ORMapping:Hibernate、MyBatis、Spring Data 如何使用 IoC 创建 Maven 工...

追求幸福,探索未知的博客 651
上一篇: 超快微服务:当Microstream遇上Wildfly
下一篇: 如何在 Vue 项目中,通过点击 DOM 自动定位VSCode中的代码行?
JavaMonsterr
博客等级 码龄4年 211粉丝 481原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值