@target和@within之间的区别(Spring AOP) [英] Difference between @target and @within (Spring AOP)

查看:306
本文介绍了@target和@within之间的区别(Spring AOP)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Spring手册说:

Spring manual says:

目标所在的任何连接点(仅在Spring AOP中执行方法) 对象具有@Transactional批注: @target(org.springframework.transaction.annotation .Transactional)

any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation: @target(org.springframework.transaction.annotation .Transactional)

任何连接点(仅在Spring AOP中执行方法),其中 目标对象的声明类型具有@Transactional批注: @within(org.springframework.transaction.annotation .Transactional)

any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation: @within(org.springframework.transaction.annotation .Transactional)

但我看不出它们之间有什么区别!

But I not see any difference between them!

我试图用Google搜索它:

I tried to Google it:

两者之间的区别是@within()是静态匹配的,要求相应的注释类型仅具有 CLASS保留.而@target()在运行时匹配, 要求同样具有RUNTIME保留时间.除此之外, 在Spring的上下文中,联接之间没有区别 点被两个选择.

One difference between the two is that @within() is matched statically, requiring the corresponding annotation type to have only the CLASS retention. Whereas, @target() is matched at runtime, requiring the same to have the RUNTIME retention. Other than that, within the context of Spring, here is no difference between the join points selected by two.

所以我试图添加保留 CLASS 的自定义注释,但是Spring抛出异常(因为注释必须具有 RUNTIME 保留)

So I tried to add custom annotation with CLASS retention, but Spring throw an Exception (because annotation must have RUNTIME retention)

推荐答案

您没有注意到任何区别,因为使用AspectJ语法的Spring AOP实际上仅模拟其功能的有限子集.因为Spring AOP基于动态代理,所以它仅提供对公共,非静态方法执行的拦截. (使用CGLIB代理时,您还可以拦截程序包作用域和受保护的方法.)但是AspectJ也可以拦截方法调用(不仅是执行),成员字段访问(静态和非静态),构造函数调用/执行,静态类.初始化等等.

You are noticing no difference because Spring AOP, while using AspectJ syntax, actually only emulates a limited subset of its functionality. Because Spring AOP is based on dynamic proxies, it only provides interception of public, non-static method execution. (When using CGLIB proxies, you can also intercept package-scoped and protected methods.) AspectJ however can also intercept method calls (not just executions), member field access (both static and non-static), constructor call/execution, static class initialisation and a few more.

因此,让我们构造一个非常简单的AspectJ示例:

So let us construct a very simple AspectJ sample:

标记注释:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

驱动程序应用程序:

package de.scrum_master.app;

@MyAnnotation
public class Application {
  private int nonStaticMember;
  private static int staticMember;

  public void doSomething() {
    System.out.println("Doing something");
    nonStaticMember = 11;
  }

  public void doSomethingElse() {
    System.out.println("Doing something else");
    staticMember = 22;
  }

  public static void main(String[] args) {
    Application application = new Application();
    application.doSomething();
    application.doSomethingElse();
  }
}

方面:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspect {
  @Before("@within(de.scrum_master.app.MyAnnotation) && execution(public !static * *(..))")
  public void adviceAtWithin(JoinPoint thisJoinPoint) {
    System.out.println("[@within] " + thisJoinPoint);
  }

  @Before("@target(de.scrum_master.app.MyAnnotation) && execution(public !static * *(..))")
  public void adviceAtTarget(JoinPoint thisJoinPoint) {
    System.out.println("[@target] " + thisJoinPoint);
  }
}

请注意,我在这里通过向两个切入点添加&& execution(public !static * *(..))来模拟Spring AOP行为.

Please note that I am emulating Spring AOP behaviour here by adding && execution(public !static * *(..)) to both pointcuts.

控制台日志:

[@within] execution(void de.scrum_master.app.Application.doSomething())
[@target] execution(void de.scrum_master.app.Application.doSomething())
Doing something
[@within] execution(void de.scrum_master.app.Application.doSomethingElse())
[@target] execution(void de.scrum_master.app.Application.doSomethingElse())
Doing something else

这里不足为奇.这正是您在Spring AOP中也会看到的.现在,如果您从两个切入点中删除了&& execution(public !static * *(..))部分,则在Spring AOP中的输出仍然相同,但是在AspectJ中(例如,如果您在Spring中激活了AspectJ LTW),它将更改为:

No surprise here. This is exactly what you would also see in Spring AOP. Now if you remove the && execution(public !static * *(..)) part from both pointcuts, in Spring AOP the output is still the same, but in AspectJ (e.g. also if you activate AspectJ LTW in Spring) it changes to:

[@within] staticinitialization(de.scrum_master.app.Application.<clinit>)
[@within] execution(void de.scrum_master.app.Application.main(String[]))
[@within] call(de.scrum_master.app.Application())
[@within] preinitialization(de.scrum_master.app.Application())
[@within] initialization(de.scrum_master.app.Application())
[@target] initialization(de.scrum_master.app.Application())
[@within] execution(de.scrum_master.app.Application())
[@target] execution(de.scrum_master.app.Application())
[@within] call(void de.scrum_master.app.Application.doSomething())
[@target] call(void de.scrum_master.app.Application.doSomething())
[@within] execution(void de.scrum_master.app.Application.doSomething())
[@target] execution(void de.scrum_master.app.Application.doSomething())
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something
[@within] set(int de.scrum_master.app.Application.nonStaticMember)
[@target] set(int de.scrum_master.app.Application.nonStaticMember)
[@within] call(void de.scrum_master.app.Application.doSomethingElse())
[@target] call(void de.scrum_master.app.Application.doSomethingElse())
[@within] execution(void de.scrum_master.app.Application.doSomethingElse())
[@target] execution(void de.scrum_master.app.Application.doSomethingElse())
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something else
[@within] set(int de.scrum_master.app.Application.staticMember)

详细查看此内容时,您会发现拦截了更多的@within()连接点,但也拦截了另外的@target()个连接点,例如前面提到的call()连接点,还有set()表示非静态字段和对象initialization()的连接点,它们是在构造函数执行之前发生的.

When looking at this in detail you see that a lot more @within() joinpoints get intercepted, but also a few more @target() ones, e.g. the call() joinpoints mentioned before, but also set() for non-static fields and object initialization() happening before constructor execution.

仅查看@target()时,我们会看到以下内容:

When only looking at @target() we see this:

[@target] initialization(de.scrum_master.app.Application())
[@target] execution(de.scrum_master.app.Application())
[@target] call(void de.scrum_master.app.Application.doSomething())
[@target] execution(void de.scrum_master.app.Application.doSomething())
Doing something
[@target] set(int de.scrum_master.app.Application.nonStaticMember)
[@target] call(void de.scrum_master.app.Application.doSomethingElse())
[@target] execution(void de.scrum_master.app.Application.doSomethingElse())
Doing something else

对于每一个方面的输出线,我们还看到相应的@within()匹配项.现在,让我们专注于不一样的地方,过滤输出是否存在差异:

For each of these aspect output lines we also see a corresponding @within() match. Now let's concentrate on what is not the same, filtering the output for differences:

[@within] staticinitialization(de.scrum_master.app.Application.<clinit>)
[@within] execution(void de.scrum_master.app.Application.main(String[]))
[@within] call(de.scrum_master.app.Application())
[@within] preinitialization(de.scrum_master.app.Application())
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something else
[@within] set(int de.scrum_master.app.Application.staticMember)

在这里,您会看到

  • 静态类初始化,
  • 静态方法执行,
  • 构造函数调用(尚未执行!)
  • 构造对象预初始化
  • 另一个类(System.out)中的成员变量访问,
  • 从另一个类(PrintStream.println(String))调用方法,
  • 设置静态类成员.
  • static class initialisation,
  • static method execution,
  • constructor call (not execution yet!),
  • constructed object pre-initialisation,
  • member variable access in another class (System.out),
  • calling a method from another class (PrintStream.println(String)),
  • setting a static class member.

所有这些切入点有什么共同点?没有目标对象,因为我们正在谈论静态方法或成员,静态类初始化,对象预初始化(尚未定义this)或从不带有我们此处针对的注释的其他类中调用/访问东西.

What do all of those pointcuts have in common? There is no target object, because either we are talking about static methods or members, static class initialisation, object pre-initialisation (no this defined yet) or calling/accessing stuff from other classes not bearing the annotation we are targeting here.

因此,您看到在AspectJ中,两个切入点之间存在显着差异,在Spring AOP中,由于它们的局限性,它们并不明显.

So you see that in AspectJ there are significant differences between the two pointcuts, in Spring AOP they are just not noticeable because of its limitations.

我的建议是,如果您打算拦截目标对象实例内的非静态行为,请使用@target().如果您决定在Spring中激活AspectJ模式,甚至将一些代码移植到未启用Spring的,启用Aspect的应用程序中,都将使切换到AspectJ更加容易.

My advice for you is to use @target() if your intention is to intercept non-static behaviour within a target object instance. It will make switching to AspectJ easier if you ever decide to activate the AspectJ mode in Spring or even port some code to a non-Spring, aspect-enabled application.

这篇关于@target和@within之间的区别(Spring AOP)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆