- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
上一篇文章主要对Pointcut,Advice和Joinpoint做了分析,详情看下面这篇文章:
Spring读源码系列之AOP–01—aop基本概念扫盲—上
本文主要针对AOP最后一块盲区进行讲解,即Advisor,然后再讲解一下Spring如何整合这些组件的
Advisor是Spring AOP的顶层抽象,用来管理Advice和Pointcut(PointcutAdvisor和切点有关,但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();
}
它的继承体系主要有如下两个:PointcutAdvisor和IntroductionAdvisor
IntroductionAdvisor与PointcutAdvisor最本质上的区别就是,IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice。
而不能像PointcutAdvisor那样,可以使用任何类型的Pointcut,以及几乎任何类型的Advice。
PointcutAdvisor它的实现类非常的多:
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
// 实现了 Ordered接口
public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable {
// 调用者可以手动来指定Order
public void setOrder(int order) {
this.order = order;
}
@Override
public 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了
@Override
public boolean isPerInstance() {
return true;
}
...
}
public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {
private Advice advice = EMPTY_ADVICE;
public void setAdvice(Advice advice) {
this.advice = advice;
}
@Override
public Advice getAdvice() {
return this.advice;
}
...
}
它是Spring提供的通用的,也被认为是最强大的Advisor。它可以把任意的两个Advice和Pointcut放在一起,除了introductions类型的Advice
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
private Pointcut pointcut = Pointcut.TRUE;
public DefaultPointcutAdvisor() {
}
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
setAdvice(advice);
}
public void setPointcut(@Nullable Pointcut pointcut) {
this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
...
}
// 实现了BeanFactoryAware接口,若在Bean容器里注册可以注入BeanFactory~~~从而访问里面的实例
public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
// 我们发现这两个都是@Nullable,所以他们脱离容器使用也是可以的
@Nullable
private String adviceBeanName;
@Nullable
private BeanFactory beanFactory;
@Nullable
private transient volatile Advice advice;
public void setAdviceBeanName(@Nullable String adviceBeanName) {
this.adviceBeanName = adviceBeanName;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
// 若在Spring环境下,会给AdviceMonitor重新赋值为:getSingletonMutex()
resetAdviceMonitor();
}
// 此处加锁
public void setAdvice(Advice advice) {
synchronized (this.adviceMonitor) {
this.advice = advice;
}
}
// 这是它最重要的方法,获取增强器
@Override
public 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;
}
}
}
}
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);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
在Spring事务相关里,你会看到这个类
位于org.springframework.aop.support包内
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系列会详细讲解
@Nullable
private CacheOperationSource cacheOperationSource;
// Pointcut使用的是CacheOperationSourcePointcut
private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
@Override
@Nullable
protected CacheOperationSource getCacheOperationSource() {
return cacheOperationSource;
}
};
public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {
this.cacheOperationSource = cacheOperationSource;
}
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
位于包为: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的注解:@Asynchronous
try {
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个注解。
AbstractAspectJAdvice内部维护了一个AspectJExpressionPointcut pointcut
显然是和AspectJ相关的,使用得很是广泛。注意它和AspectJExpressionPointcutAdvisor的区别。
有名字也能看出来,AspectJExpressionPointcutAdvisor和表达式语言的切点相关的,而AspectJPointcutAdvisor是无关的。它哥俩都位于包org.springframework.aop.aspectj里。
public class AspectJPointcutAdvisor implements PointcutAdvisor, Ordered {
//AbstractAspectJAdvice通知:它的子类看下面截图,就非常清楚了
private final AbstractAspectJAdvice advice;
//可以接受任意的Pointcut,可谓非常的通用(当然也包含切点表达式啦)
private final Pointcut pointcut;
@Nullable
private Integer order;
//只有这一个构造函数,包装一个advice
public AspectJPointcutAdvisor(AbstractAspectJAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
// 然后pointcut根据advice直接给生成了一个。这是AbstractAspectJAdvice#buildSafePointcut的方法
this.pointcut = advice.buildSafePointcut();
}
...
}
public final Pointcut buildSafePointcut() {
//拿到AbstractAspectJAdvice内部维护的AspectJExpressionPointcut pointcut
Pointcut pc = getPointcut();
MethodMatcher safeMethodMatcher = MethodMatchers.intersection(
new AdviceExcludingMethodMatcher(this.aspectJAdviceMethod), pc.getMethodMatcher());
return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher);
}
它是PointcutAdvisor的一个子接口。
// 由SpringAOP顾问包装AspectJ实现的接口 可能具有延迟初始化策略的方面。
// 例如,一个PerThis实例化模型意味着对建议的初始化太慢
public interface InstantiationModelAwarePointcutAdvisor extends PointcutAdvisor {
// 该Advisor是否需要懒加载
boolean isLazy();
// 判断此Advisor它所拥有的Advice是否已经初始化了
boolean isAdviceInstantiated();
}
它的唯一实现类:InstantiationModelAwarePointcutAdvisorImpl
// 默认的访问权限,显然是Spring内部自己用的
class InstantiationModelAwarePointcutAdvisorImpl
implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {
private static final Advice EMPTY_ADVICE = new Advice() {};
// 和AspectJExpression
private final AspectJExpressionPointcut declaredPointcut;
..
// 通知方法
private transient Method aspectJAdviceMethod;
private final AspectJAdvisorFactory aspectJAdvisorFactory;
private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
@Nullable
private Advice instantiatedAdvice;
@Nullable
private Boolean isBeforeAdvice;
@Nullable
private Boolean isAfterAdvice;
...
@Override
public boolean isPerInstance() {
return (getAspectMetadata().getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON);
}
@Override
public synchronized Advice getAdvice() {
//第一次获取Adivce时,才去创建---懒加载
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);
}
@Override
public boolean isBeforeAdvice() {
if (this.isBeforeAdvice == null) {
determineAdviceType();
}
return this.isBeforeAdvice;
}
@Override
public 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中的 Pointcut与Advice都是由ReflectiveAspectJAdvisorFactory 来解析生成的
(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice,Pointcut 则是AspectJExpressionPointcut),
解析的步骤是:
Spring中有五种增强:BeforeAdvide(前置增强)、AfterAdvice(后置增强)、ThrowsAdvice(异常增强)、RoundAdvice(环绕增强)、IntroductionAdvice(引入增强)
引入增强(Introduction Advice)的概念:一个Java类,没有实现A接口,在不修改Java类的情况下,使其具备A接口的功能。
IntroductionAdvisor纯粹就是为Introduction而生的。
IntroductionAdvisor 和 PointcutAdvisor接口不同,它仅有一个类过滤器ClassFilter 而没有 MethodMatcher,这是因为 `引介切面 的切点是类级别的,而 Pointcut 的切点是方法级别的(细粒度更细,所以更加常用)。
为了更好的了解IntroductionAdvisor,我先有必要讲解下IntroductionInfo和IntroductionInterceptor;
Introduction可以在不改动目标类定义的情况下,为目标类增加新的属性和行为。
//This interface cannot be implemented directly;
//subinterfaces must provide the advice type implementing the introduction.
//Introduction is the implementation of additional interfaces (not implemented by a target) via AOP advice
//重点在最后一句话: Introduction才是这些附加接口的实现类,而不是目标对象通过增强方法去实现
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
/**
* Return the filter determining which target classes this introduction
* should apply to.
* This represents the class part of a pointcut. Note that method
* matching doesn't make sense to introductions.
*/
ClassFilter getClassFilter();
/**
* Can the advised interfaces be implemented by the introduction advice?
* Invoked before adding an IntroductionAdvisor.
*/
void validateInterfaces() throws IllegalArgumentException;
}
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();
}
它的继承结构如下:
在Spring中,为目标对象添加新的属性和行为必须声明相应的接口以及相应的实现。这样,再通过特定的拦截器将新的接口定义以及实现类中的逻辑附加到目标对象上。然后,目标对象(确切的说,是目标对象的代理对象)就拥有了新的状态和行为
这里面介绍这个非常强大的拦截器:IntroductionInterceptor
// IntroductionInterceptor它是对MethodInterceptor的一个扩展,
//同时他还继承了接口DynamicIntroductionAdvice
public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {
}
public interface DynamicIntroductionAdvice extends Advice {
boolean implementsInterface(Class<?> intf);
}
通过DynamicIntroductionAdvice,可以界定当前的 IntroductionInterceptor为哪些接口提供相应的拦截功能。通过MethodInterceptor,IntroductionInterceptor 就可以处理新添加的接口上的方法调用了
要对目标对象进行拦截并添加Introduction的逻辑,我们可以直接扩展IntroductionInterceptor,然后在子类的invoke方法中实现所有的拦截逻辑
除非特殊情况下需要直接扩展IntroductionInterceptor,大多数时候,直接使用Spring提供的两个现成的实现类就可以了:DelegatingIntroductionInterceptor 和 DelegatePerTargetObjectIntroductionInterceptor
// 定义一个新的行为接口,这个行为准备作用在目标对象上
public interface IOtherInte {
void doOther();
}
// 自己定义一个IntroductionInterceptor来实现IntroductionInterceptor接口
// 注意:此处也实现了接口IOtherInte(这是类似于增强器部分) 相当于这个interptor目前就只处理 IOtherInte
public class SomeInteIntroductionInterceptor implements IntroductionInterceptor, IOtherInte {
/**
* 判断调用的方法是否为指定类中的方法
* 如果Method代表了一个方法 那么调用它的invoke就相当于执行了它代表的这个方法
*/
@Override
public 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的实现
*/
@Override
public boolean implementsInterface(Class clazz) {
return clazz.isAssignableFrom(IOtherInte.class);
}
@Override
public 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()方法的功能,这就是引介增强的强大功能。此处使用的Advisor为DefaultIntroductionAdvisor。它也是我们最常用的Advisor:
// 它是一个Advisor,同时也是一个IntroductionInfo
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
// 它只有ClassFilter,因为它只能作用在类层面上
ClassFilter getClassFilter();
// 判断这些接口,是否真的能够增强。 DynamicIntroductionAdvice#implementsInterface()方法
void validateInterfaces() throws IllegalArgumentException;
}
// 它直接事IntroductionAdvisor的实现类。同时也是一个ClassFilter
public 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和DelegatePerTargetObjectIntroductionInterceptor
public 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);
}
...
@Override
public void validateInterfaces() throws IllegalArgumentException {
for (Class<?> ifc : this.interfaces) {
if (this.advice instanceof DynamicIntroductionAdvice &&
//advice来实现interfaces---这里是IntroductionInterceptor
!((DynamicIntroductionAdvice) this.advice).implementsInterface(ifc)) {
throw new IllegalArgumentException("DynamicIntroductionAdvice [" + this.advice + "] " +
"does not implement interface [" + ifc.getName() + "] specified for introduction");
}
}
}
...
}
public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport
implements IntroductionInterceptor {
/**
* Object that actually implements the interfaces.
* May be "this" if a subclass implements the introduced interfaces.
*/
@Nullable
private Object delegate;
/**
* Construct a new DelegatingIntroductionInterceptor.
* The delegate will be the subclass, which must implement
* additional interfaces.
* 访问权限事protected,显然就是说子类必须去继承这个类,然后提供空构造函数。代理类就是this
*/
protected DelegatingIntroductionInterceptor() {
init(this);
}
// Construct a new DelegatingIntroductionInterceptor,
//providing a delegate that implements the interfaces to be introduced.
public 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 interface
suppressInterface(IntroductionInterceptor.class);
suppressInterface(DynamicIntroductionAdvice.class);
}
// 如果你要自定义一些行为:比如环绕通知之类的,子类需要复写此方法(否则没有必要了)
@Override
@Nullable
public 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 {
@Override
public void doOther() {
System.out.println("给人贴标签 doOther...");
}
}
与DelegatingIntroductionInterceptor不同,DelegatePerTargetObjectIntroductionInterceptor会在内部持有一个目标对象与相应Introduction逻辑实现类之间的映射关系。
当每个目标对象上的新定义的接口方法被调用的时候,它会拦截这些调用。然后以目标对象实例作为键,到它持有的那个映射关系中取得对应当前目标对象实例的Introduction实现类实例。 使用起来和DelegatingIntroductionInterceptor没有太大区别,主要在构造函数上:
1: 可以删除掉SomeInteIntroductionInterceptor类了
2:单独实现引介接口
public class OtherImpl implements IOtherInte {
@Override
public void doOther() {
System.out.println("我是OtherImpl");
}
}
main方法里修改如下:这样就ok了
Advice advice = new DelegatePerTargetObjectIntroductionInterceptor(OtherImpl.class, IOtherInte.class);
备注:若你需要复写invoke方法的逻辑,请扩展它即可~~~(它的优点是:每次执行目标对象的时候,都能缓存起来,提高一点效率吧)
IntroductionAdvisor因为只能实现类级别的过滤,所以只需要一个ClassFilter即可。
DefaultIntroductionAdvisor实现了ClassFilter接口,因此也就有了PointCut的职责,即通过ClassFilter来选择joinpoint,只不过此时joinpoint是类级别的。
讲到这里,会发现advisor管理的pointcut有了,但是advice在哪里呢?
IntroductionInterceptor是advice的拦截器分支,可以通过拦截器的形式完成功能增强。
IntroductionInterceptor这里就是需要被IntroductionAdvisor管理的增强器了。
DelegatingIntroductionInterceptor和DelegatePerTargetObjectIntroductionInterceptor是上面拦截器增强器的两个实现类。
这两个实现类实现思路类似,都是在拦截器的invoke方法中进行方法拦截,判断当前被调用方法是否是目标对象新增接口中的方法,如果是,则调用保存好的,实现了这些新增接口的代理对象中的方法。
我尝试阅读有关 Spring BOM、Spring Boot 和 Spring IO 的文档。 但是没有说明,我们应该如何一起使用它们? 在我的项目中,我们已经有了自己的 Parent POM ,所以
我正在开发的很酷的企业应用程序正在转向 Spring。这对所有团队来说都是非常酷和令人兴奋的练习,但也是一个巨大的压力源。我们所做的是逐渐将遗留组件移至 Spring 上下文。现在我们有一个 huuu
我正在尝试使用 @Scheduled 运行 Spring 批处理作业注释如下: @Scheduled(cron = "* * * * * ?") public void launchMessageDi
我对这两个概念有点困惑。阅读 Spring 文档,我发现,例如。 bean 工厂是 Spring 容器。我还读到“ApplicationContext 是 BeanFactory 的完整超集”。但两者
我们有一个使用 Spring BlazeDS 集成的应用程序。到目前为止,我们一直在使用 Spring 和 Flex,它运行良好。我们现在还需要添加一些 Spring MVC Controller 。
假设我有一个类(class) Person带属性name和 age ,它可以像这样用 Spring 配置: 我想要一个自定义的 Spring 模式元素,这很容易做到,允许我在我的 Sp
如何在 Java 中以编程方式使用 Spring Data 创建 MongoDB 复合索引? 使用 MongoTemplate 我可以创建一个这样的索引:mongoTemplate.indexOps(
我想使用 spring-complex-task 执行我的应用程序,并且我已经构建了复杂的 spring-batch Flow Jobs,它执行得非常好。 你能解释一下spring批处理流作业与spr
我实现了 spring-boot 应用程序,现在我想将它用作非 spring 应用程序的库。 如何初始化 lib 类,以便 Autowiring 的依赖项按预期工作?显然,如果我使用“new”创建类实
我刚开始学习 spring cloud security,我有一个基本问题。它与 Spring Security 有何不同?我们是否需要在 spring boot 上构建我们的应用程序才能使用 spr
有很多人建议我使用 Spring Boot 而不是 Spring 来开发 REST Web 服务。我想知道这两者到底有什么区别? 最佳答案 总之 Spring Boot 减少了编写大量配置和样板代码的
您能向我解释一下如何使用 Spring 正确构建 Web 应用程序吗?我知道 Spring 框架的最新版本是 4.0.0.RELEASE,但是 Spring Security 的最新版本是 3.2.0
我如何才能知道作为 Spring Boot 应用程序的一部分加载的所有 bean 的名称?我想在 main 方法中有一些代码来打印服务器启动后加载的 bean 的详细信息。 最佳答案 如spring-
我有一个使用 Spring 3.1 构建的 RESTful API,也使用 Spring Security。我有一个 Web 应用程序,也是一个 Spring 3.1 MVC 应用程序。我计划让移动客
升级到 Spring 5 后,我在 Spring Rabbit 和 Spring AMQP 中遇到错误。 两者现在都设置为 1.5.6.RELEASE 有谁知道哪些版本应该与 Spring 5 兼容?
我现在已经使用 Spring Framework 3.0.5 和 Spring Security 3.0.5 多次了。我知道Spring框架使用DI和AOP。我还知道 Spring Security
我收到错误 Unable to Location NamespaceHandler when using context:annotation-config running (java -jar) 由
在 Spring 应用程序中嵌入唯一版本号的策略是什么? 我有一个使用 Spring Boot 和 Spring Web 的应用程序。 它已经足够成熟,我想对其进行版本控制并在运行时看到它显示在屏幕上
我正在使用 spring data jpa 进行持久化。如果存在多个具有相同名称的实体,是否有一种方法可以将一个实体标记为默认值。类似@Primary注解的东西用来解决多个bean的依赖问题 @Ent
我阅读了 Spring 框架的 DAOSupport 类。但是我无法理解这些 DAOSuport 类的优点。在 DAOSupport 类中,我们调用 getXXXTemplate() 方法来获取特定的
我是一名优秀的程序员,十分优秀!