Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor

本文主要是介绍Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Advisor介绍

Advisor是Spring AOP的顶层抽象,用来管理AdvicePointcutPointcutAdvisor和切点有关,但IntroductionAdvisor和切点无关

注意:Advice是aopalliance对通知(增强器)的顶层抽象,请注意区分~~
Pointcut是Spring AOP对切点的抽象。切点的实现方式有多种,其中一种就是AspectJ

public interface Advisor {//@since 5.0 Spring5以后才有的  空通知  一般当作默认值Advice EMPTY_ADVICE = new Advice() {};// 该Advisor 持有的通知器Advice getAdvice();// 这个有点意思:Spring所有的实现类都是return true(官方说暂时还没有应用到)// 注意:生成的Advisor是单例还是多例不由isPerInstance()的返回结果决定,而由自己在定义bean的时候控制// 理解:和类共享(per-class)或基于实例(per-instance)相关  类共享:类比静态变量   实例共享:类比实例变量boolean isPerInstance();}

它的继承体系主要有如下两个:PointcutAdvisorIntroductionAdvisor

IntroductionAdvisor与PointcutAdvisor最本质上的区别就是,IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice。
而不能像PointcutAdvisor那样,可以使用任何类型的Pointcut,以及几乎任何类型的Advice

PointcutAdvisor:和切点有关的Advisor

顾名思义,它和Pointcu有关。在上一篇博文:【小家Spring】Spring AOP核心类Pointcut解析,对PointcutExpression切点表达式解析原理分析(以AspectJExpressionPointcut为例)
其实我们已经介绍了好几个PointcutAdvisor。比如:RegexpMethodPointcutAdvisorNameMatchMethodPointcutAdvisor,它哥俩都位于org.springframework.aop.support此包。当然还要介绍过AspectJExpressionPointcutAdvisor

PointcutAdvisor它的实现类非常的多:

public interface PointcutAdvisor extends Advisor {Pointcut getPointcut();}1.2.3.

AbstractPointcutAdvisor:抽象实现
// 实现了 Ordered接口public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable {// 调用者可以手动来指定Orderpublic void setOrder(int order) {this.order = order;}@Overridepublic int getOrder() {if (this.order != null) {return this.order;}// 若调用者没有指定Order,那就拿advice的order为准(若有),否则LOWEST_PRECEDENCE表示最后执行Advice advice = getAdvice();if (advice instanceof Ordered) {return ((Ordered) advice).getOrder();}return Ordered.LOWEST_PRECEDENCE;}// Spring还没有使用该属性 永远返回true了@Overridepublic boolean isPerInstance() {return true;}...}

AbstractGenericPointcutAdvisor 一般的、通用的PointcutAdvisor
public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {private Advice advice = EMPTY_ADVICE;public void setAdvice(Advice advice) {this.advice = advice;}@Overridepublic Advice getAdvice() {return this.advice;}...}
DefaultPointcutAdvisor 通用的,最强大的Advisor

它是Spring提供的通用的,也被认为是最强大的Advisor。它可以把任意的两个Advice和Pointcut放在一起:

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {private Pointcut pointcut = Pointcut.TRUE;public DefaultPointcutAdvisor() {}// 若没有指定advice,默认Pointcut.TRUE,也就是说会匹配所有的方法的执行public DefaultPointcutAdvisor(Advice advice) {this(Pointcut.TRUE, advice);}// 显然,这个构造函数式非常强大的~~public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {this.pointcut = pointcut;setAdvice(advice);}}

AbstractBeanFactoryPointcutAdvisor:和bean工厂有关的PointcutAdvisor

从命名也能看出来,它和BeanFactory有关。

// 实现了BeanFactoryAware接口,若在Bean容器里注册可议注入BeanFactory~~~从而访问里面的实例public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {// 我们发现这两个都是@Nullable,所以他们脱离容器使用也是可以的@Nullableprivate String adviceBeanName;@Nullableprivate BeanFactory beanFactory;@Nullableprivate transient volatile Advice advice;public void setAdviceBeanName(@Nullable String adviceBeanName) {this.adviceBeanName = adviceBeanName;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;// 若在Spring环境下,会给AdviceMonitor重新赋值为:getSingletonMutex()resetAdviceMonitor();}// 此处加锁public void setAdvice(Advice advice) {synchronized (this.adviceMonitor) {this.advice = advice;}}// 这是它最重要的方法,获取增强器@Overridepublic Advice getAdvice() {Advice advice = this.advice;// 非Spring环境一般手动set进来,所以就直接返回吧if (advice != null) {return advice;}// 显然进来Spring容器环境了,bean工厂和beanName都是不能为null的Assert.state(this.adviceBeanName != null, "'adviceBeanName' must be specified");Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");// 若bean是单例的  那就没什么好说的  直接去工厂里拿出来就完事了(Advice.class)  有可能返回null哦if (this.beanFactory.isSingleton(this.adviceBeanName)) {advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);this.advice = advice;return advice;}// 若是多例的,就加锁  然后调用getBean()给他生成一个新的实例即可else {synchronized (this.adviceMonitor) {//这步赋值和判断不能省~~~确保万无一失advice = this.advice;if (advice == null) {advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);this.advice = advice;}return advice;}}}}
DefaultBeanFactoryPointcutAdvisor:通用的BeanFactory的Advisor

这个是和Bean工厂关联的,通用的PointcutAdvisor

public class DefaultBeanFactoryPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor {private Pointcut pointcut = Pointcut.TRUE;// 若传进来为null,还是选择 Pointcut.TRUE 匹配所有public void setPointcut(@Nullable Pointcut pointcut) {this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);}@Overridepublic Pointcut getPointcut() {return this.pointcut;}}

在Spring事务相关里,你会看到这个类

位于org.springframework.aop.support包内

BeanFactoryCacheOperationSourceAdvisor:和Cache有关

Spring Cache的@Cachable等注解的拦截,就是采用了它。该类位于:org.springframework.cache.interceptor,显然它和cache相关了。Jar包属于:Spring-context.jar

// @since 3.1  毕竟Spring的整个org.springframework.cache.Cache体系都是从这里开始的。(@Cacheable...等等)public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {// 显然它最重要的是持有这个引用(Cache章节详细介绍了它)@Nullableprivate CacheOperationSource cacheOperationSource;// Pointcut使用的是CacheOperationSourcePointcutprivate final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {@Override@Nullableprotected CacheOperationSource getCacheOperationSource() {return cacheOperationSource;}};public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {this.cacheOperationSource = cacheOperationSource;}public void setClassFilter(ClassFilter classFilter) {this.pointcut.setClassFilter(classFilter);}@Overridepublic Pointcut getPointcut() {return this.pointcut;}}

AsyncAnnotationAdvisor:和@Async有关

位于包为:org.springframework.scheduling.annotation,所属jar包为spring-context.jar

public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {// 处理异步发生的异常的====private AsyncUncaughtExceptionHandler exceptionHandler;private Advice advice;private Pointcut pointcut;// 构造函数们public AsyncAnnotationAdvisor() {this(null, null);}// executor:可以自己指定异步任务的执行器// exceptionHandler:异步异常的处理器public AsyncAnnotationAdvisor(@Nullable Executor executor, @Nullable AsyncUncaughtExceptionHandler exceptionHandler) {Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);asyncAnnotationTypes.add(Async.class);// 支持EJB的注解:@Asynchronoustry {asyncAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));} catch (ClassNotFoundException ex) {// If EJB 3.1 API not present, simply ignore.}if (exceptionHandler != null) {this.exceptionHandler = exceptionHandler;} else {// SimpleAsyncUncaughtExceptionHandler:只是一个简单的logger.error的输入打印this.exceptionHandler = new SimpleAsyncUncaughtExceptionHandler();}// buildAdvice: new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler)   它是个MethodInterceptor  环绕通知器this.advice = buildAdvice(executor, this.exceptionHandler);// 把asyncAnnotationTypes交给buildPointcut,它最终是个ComposablePointcut,会把这两种注解都支持。union起来 或者的关系this.pointcut = buildPointcut(asyncAnnotationTypes);}public void setTaskExecutor(Executor executor) {this.advice = buildAdvice(executor, this.exceptionHandler);}...}

AbstractAspectJAdvice的实现类如下:这5个实现类完完整整的对应着我们AspectJ的那5个注解。


AspectJPointcutAdvisor

显然是和AspectJ相关的,使用得很是广泛。注意它和AspectJExpressionPointcutAdvisor的区别。有名字也能看出来,AspectJExpressionPointcutAdvisor和表达式语言的切点相关的,而AspectJPointcutAdvisor是无关的。它哥俩都位于包org.springframework.aop.aspectj里。

public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {// AbstractAspectJAdvice通知:它的子类看下面截图,就非常清楚了private final AbstractAspectJAdvice advice;// 可以接受任意的Pointcut,可谓非常的通用(当然也包含切点表达式啦)private final Pointcut pointcut;@Nullableprivate Integer order;// 只有这一个构造函数,包装一个advicepublic AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;// 然后pointcut根据advice直接给生成了一个。这是AbstractAspectJAdvice#buildSafePointcut的方法this.pointcut = advice.buildSafePointcut();}}

InstantiationModelAwarePointcutAdvisor

它是PointcutAdvisor的一个子接口。

// 由SpringAOP顾问包装AspectJ实现的接口 可能具有延迟初始化策略的方面。// 例如,一个PerThis实例化模型意味着对建议的初始化太慢public interface InstantiationModelAwarePointcutAdvisor extends PointcutAdvisor {// 该Advisor是否需要懒加载boolean isLazy();// 判断此Advisor它所拥有的Advice是否已经初始化了boolean isAdviceInstantiated();}

它的唯一实现类:InstantiationModelAwarePointcutAdvisorImpl

// 默认的访问权限,显然是Spring内部自己用的class InstantiationModelAwarePointcutAdvisorImplimplements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {private static final Advice EMPTY_ADVICE = new Advice() {};// 和AspectJExpressionprivate final AspectJExpressionPointcut declaredPointcut;..// 通知方法private transient Method aspectJAdviceMethod;private final AspectJAdvisorFactory aspectJAdvisorFactory;private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;@Nullableprivate Advice instantiatedAdvice;@Nullableprivate Boolean isBeforeAdvice;@Nullableprivate Boolean isAfterAdvice;...@Overridepublic boolean isPerInstance() {return (getAspectMetadata().getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON);}@Overridepublic synchronized Advice getAdvice() {if (this.instantiatedAdvice == null) {this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);}return this.instantiatedAdvice;}// advice 由aspectJAdvisorFactory去生产  懒加载的效果private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,this.aspectInstanceFactory, this.declarationOrder, this.aspectName);return (advice != null ? advice : EMPTY_ADVICE);}@Overridepublic boolean isBeforeAdvice() {if (this.isBeforeAdvice == null) {determineAdviceType();}return this.isBeforeAdvice;}@Overridepublic boolean isAfterAdvice() {if (this.isAfterAdvice == null) {determineAdviceType();}return this.isAfterAdvice;}// 这里解释根据@Aspect方法上标注的注解,来区分这两个字段的值的private void determineAdviceType() {AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.aspectJAdviceMethod);if (aspectJAnnotation == null) {this.isBeforeAdvice = false;this.isAfterAdvice = false;}else {switch (aspectJAnnotation.getAnnotationType()) {case AtAfter:case AtAfterReturning:case AtAfterThrowing:this.isAfterAdvice = true;this.isBeforeAdvice = false;break;case AtAround:case AtPointcut:this.isAfterAdvice = false;this.isBeforeAdvice = false;break;case AtBefore:this.isAfterAdvice = false;this.isBeforeAdvice = true;}}}}

这个Advisor是在Spring解析被 @AspectJ注解注释的类时生成的 Advisor,。

而这个 Advisor中的 PointcutAdvice都是由ReflectiveAspectJAdvisorFactory 来解析生成的(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice,
Pointcut 则是AspectJExpressionPointcut), 解析的步骤是:

自动代理创建器:AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors() ->
Bean工厂相关的Advisor构建器:BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors() ->
ReflectiveAspectJAdvisorFactory.getAdvisors() ->
ReflectiveAspectJAdvisorFactory.getAdvisor() 最终生成了InstantiationModelAwarePointcutAdvisorImpl(当然包括里面的 Pointcutadvice 也都是由 ReflectiveAspectJAdvisorFactory 解析生成的)


IntroductionAdvisor:引介切面

Spring中有五种增强:BeforeAdvide(前置增强)、AfterAdvice(后置增强)、ThrowsAdvice(异常增强)、RoundAdvice(环绕增强)、IntroductionAdvice(引入增强)

RoundAdvice(环绕增强):就是BeforeAdvide(前置增强)、AfterAdvice(后置增强)的组合使用叫环绕增强。前四种都比较简单。。。

引入增强(Introduction Advice)的概念:一个Java类,没有实现A接口,在不修改Java类的情况下,使其具备A接口的功能。(非常强大有木有,A不需要动代码,就能有别的功能,吊炸天有木有)

IntroductionAdvisor纯粹就是为Introduction而生的。

IntroductionAdvisorPointcutAdvisor接口不同,它仅有一个类过滤器ClassFilter 而没有 MethodMatcher,这是因为 `引介切面 的切点是类级别的,而 Pointcut 的切点是方法级别的(细粒度更细,所以更加常用)。

为了更好的了解IntroductionAdvisor,我先有必要讲解下IntroductionInfoIntroductionInterceptor

Introduction可以在不改动目标类定义的情况下,为目标类增加新的属性和行为。

IntroductionInfo:引介信息

IntroductionInfo 接口描述了目标类需要实现的新接口。

// 提供描述引言所需信息的接口// IntroductionAdvisor必须实现这个接口。若`org.aopalliance.aop.Advice`直接实现了此接口,// 它可议独立的当作introduction来使用而不用依赖IntroductionAdvisor。这种情况下,这个advice可议自描述,不仅提供。。。public interface IntroductionInfo {//Return the additional interfaces introduced by this Advisor or Advice.// 返回额外给Advisor 或者 advice实现的接口们Class<?>[] getInterfaces();}

它的继承结构如下:

IntroductionInterceptor:引介拦截器

在Spring中,为目标对象添加新的属性和行为必须声明相应的接口以及相应的实现。这样,再通过特定的拦截器将新的接口定义以及实现类中的逻辑附加到目标对象上。然后,目标对象(确切的说,是目标对象的代理对象)就拥有了新的状态和行为

这里面介绍这个非常强大的拦截器:IntroductionInterceptor

// IntroductionInterceptor它是对MethodInterceptor的一个扩展,同时他还继承了接口DynamicIntroductionAdvicepublic interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {}

DynamicIntroductionAdvice

public interface DynamicIntroductionAdvice extends Advice {boolean implementsInterface(Class<?> intf);}

通过DynamicIntroductionAdvice,可以界定当前的 IntroductionInterceptor为哪些接口提供相应的拦截功能。通过MethodInterceptor,IntroductionInterceptor 就可以处理新添加的接口上的方法调用了

打个比方

如果把每个目标对象实例看作盒装牛奶生产线上的那一盒盒牛奶的话,那么生产合格证就是新的Introduction逻辑,而introductionInterceptor 就是把这些生产合格证贴到一盒盒牛奶上的那个人

要对目标对象进行拦截并添加Introduction的逻辑,我们可以直接扩展IntroductionInterceptor,然后在子类的invoke方法中实现所有的拦截逻辑

除非特殊情况下需要直接扩展IntroductionInterceptor,大多数时候,直接使用Spring提供的两个现成的实现类就可以了DelegatingIntroductionInterceptor 和 DelegatePerTargetObjectIntroductionInterceptor

例子

下面使用一个例子,加深一下对引介增强的了解:

// 定义一个新的行为接口,这个行为准备作用在目标对象上public interface IOtherInte {void doOther();}// 自己定义一个IntroductionInterceptor来实现IntroductionInterceptor接口// 注意:此处也实现了接口IOtherInte(这是类似于增强器部分)  相当于这个interptor目前就只处理 IOtherIntepublic class SomeInteIntroductionInterceptor implements IntroductionInterceptor, IOtherInte {/*** 判断调用的方法是否为指定类中的方法* 如果Method代表了一个方法 那么调用它的invoke就相当于执行了它代表的这个方法*/@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {if (implementsInterface(invocation.getMethod().getDeclaringClass())) {System.out.println("我是引介增强的方法体~~~invoke");return invocation.getMethod().invoke(this, invocation.getArguments());}return invocation.proceed();}/*** 判断clazz是否为给定接口IOtherBean的实现*/@Overridepublic boolean implementsInterface(Class clazz) {return clazz.isAssignableFrom(IOtherInte.class);}@Overridepublic void doOther() {System.out.println("给人贴标签 doOther...");}}// 方法测试public static void main(String[] args) {ProxyFactory factory = new ProxyFactory(new Person());factory.setProxyTargetClass(true); // 强制私用CGLIB 以保证我们的Person方法也能正常调用// 此处采用IntroductionInterceptor 这个引介增强的拦截器Advice advice = new SomeInteIntroductionInterceptor();// 切点+通知(注意:此处放的是复合切面)Advisor advisor = new DefaultIntroductionAdvisor((DynamicIntroductionAdvice) advice, IOtherInte.class);//Advisor advisor = new DefaultPointcutAdvisor(cut, advice);factory.addAdvisor(advisor);IOtherInte otherInte = (IOtherInte) factory.getProxy();otherInte.doOther();System.out.println("===============================");// Person本身自己的方法  也得到了保留Person p = (Person) factory.getProxy();p.run();p.say();}输出:我是引介增强的方法体~~~invoke给人贴标签 doOther...===============================我在run...我在say...

我们发现,我们没有更改过Person类的任何代码,它竟然就有了doOther()方法的功能,这就是引介增强的强大功能。此处使用的AdvisorDefaultIntroductionAdvisor。它也是我们最常用的Advisor:

// 它是一个Advisor,同时也是一个IntroductionInfo public interface IntroductionAdvisor extends Advisor, IntroductionInfo {// 它只有ClassFilter,因为它只能作用在类层面上ClassFilter getClassFilter();// 判断这些接口,是否真的能够增强。  DynamicIntroductionAdvice#implementsInterface()方法void validateInterfaces() throws IllegalArgumentException;}// 它直接事IntroductionAdvisor的实现类。同时也是一个ClassFilterpublic class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFilter, Ordered, Serializable {private final Advice advice;private final Set<Class<?>> interfaces = new LinkedHashSet<>();private int order = Ordered.LOWEST_PRECEDENCE;// 构造函数们public DefaultIntroductionAdvisor(Advice advice) {this(advice, (advice instanceof IntroductionInfo ? (IntroductionInfo) advice : null));}// 如果IntroductionInfo 不等于null,就会把接口都add进去/// IntroductionInfo 的实现类有常用的:DelegatingIntroductionInterceptor和DelegatePerTargetObjectIntroductionInterceptorpublic DefaultIntroductionAdvisor(Advice advice, @Nullable IntroductionInfo introductionInfo) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;if (introductionInfo != null) {Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();if (introducedInterfaces.length == 0) {throw new IllegalArgumentException("IntroductionAdviceSupport implements no interfaces");}for (Class<?> ifc : introducedInterfaces) {addInterface(ifc);}}}//当然你也可以不使用IntroductionInfo,而自己手动指定了这个接口public DefaultIntroductionAdvisor(DynamicIntroductionAdvice advice, Class<?> intf) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;addInterface(intf);}...@Overridepublic void validateInterfaces() throws IllegalArgumentException {for (Class<?> ifc : this.interfaces) {if (this.advice instanceof DynamicIntroductionAdvice &&!((DynamicIntroductionAdvice) this.advice).implementsInterface(ifc)) {throw new IllegalArgumentException("DynamicIntroductionAdvice [" + this.advice + "] " +"does not implement interface [" + ifc.getName() + "] specified for introduction");}}}}
DelegatingIntroductionInterceptor和DelegatePerTargetObjectIntroductionInterceptor

这两个类是 Spring AOP 中为 IntroductionInterceptor 介面所提供的实作类别,我们可以直接继承他俩,然后扩展我们自己的行为状态。

public class DelegatingIntroductionInterceptor extends IntroductionInfoSupportimplements IntroductionInterceptor {// 需要被代理的那个对象。因为这个类需要子类继承使用,所以一般都是thid@Nullableprivate Object delegate;/*** Construct a new DelegatingIntroductionInterceptor.* The delegate will be the subclass, which must implement* additional interfaces.* 访问权限事protected,显然就是说子类必须去继承这个类,然后提供空构造函数。代理类就是this*/protected DelegatingIntroductionInterceptor() {init(this);}// 当然,你也可以手动指定delegatepublic DelegatingIntroductionInterceptor(Object delegate) {init(delegate);}private void init(Object delegate) {Assert.notNull(delegate, "Delegate must not be null");this.delegate = delegate;implementInterfacesOnObject(delegate);// 移除调这些内部标记的接口们// We don't want to expose the control interfacesuppressInterface(IntroductionInterceptor.class);suppressInterface(DynamicIntroductionAdvice.class);}// 如果你要自定义一些行为:比如环绕通知之类的,子类需要复写此方法(否则没有必要了)@Override@Nullablepublic Object invoke(MethodInvocation mi) throws Throwable {// 判断是否是引介增强if (isMethodOnIntroducedInterface(mi)) {Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments());// 如果返回值就是delegate 本身,那就把本身返回出去if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) {Object proxy = ((ProxyMethodInvocation) mi).getProxy();if (mi.getMethod().getReturnType().isInstance(proxy)) {retVal = proxy;}}return retVal;}return doProceed(mi);}}

因此,上面的例子Demo,我用DelegatingIntroductionInterceptor改造一下(只需要改造SomeInteIntroductionInterceptor即可):

// 因为我们继承自DelegatingIntroductionInterceptor,所以若我们不做环绕通知个性化,只需要实现接口的方法即可public class SomeInteIntroductionInterceptor extends DelegatingIntroductionInterceptor implements IOtherInte {@Overridepublic void doOther() {System.out.println("给人贴标签 doOther...");}}

继承此类,确实少了不少事呢。

DelegatePerTargetObjectIntroductionInterceptor

DelegatingIntroductionInterceptor不同,DelegatePerTargetObjectIntroductionInterceptor会在内部持有一个目标对象与相应Introduction逻辑实现类之间的映射关系

当每个目标对象上的新定义的接口方法被调用的时候,它会拦截这些调用。然后以目标对象实例作为键,到它持有的那个映射关系中取得对应当前目标对象实例的Introduction实现类实例。 使用起来和DelegatingIntroductionInterceptor没有太大区别,主要在构造函数上:

1: 可以删除掉SomeInteIntroductionInterceptor类了2:单独实现引介接口public class OtherImpl implements IOtherInte {@Overridepublic void doOther() {System.out.println("我是OtherImpl");}}main方法里修改如下:这样就ok了Advice advice = new DelegatePerTargetObjectIntroductionInterceptor(OtherImpl.class, IOtherInte.class);

备注:若你需要复写invoke方法的逻辑,请扩展它即可~~~(它的优点是:每次执行目标对象的时候,都可议缓存起来,提高一点效率吧)

这篇关于Spring AOP之Advisor、PointcutAdvisor、IntroductionAdvisor、IntroductionInterceptor的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/312986

相关文章

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.