Spring AOP编程官方文档解读之操作Advised对象


Spring AOP编程官方文档解读目录


文章目录


org.springframework.aop.framework.Advised是啥?看一下下面这个类结构图
无论是基于JDK动态代理还是基于
可以看到无论是ProxyFactoryBean还是ProxyFactory最终都实现了这个接口、这个接口中的方法非常的多,我们随便看一下

public interface Advised extends TargetClassAware {

	/**
	 * Return whether the Advised configuration is frozen,
	 * in which case no advice changes can be made.
	 */
	boolean isFrozen();

	/**
	 * Are we proxying the full target class instead of specified interfaces?
	 */
	boolean isProxyTargetClass();

	/**
	 * Return the interfaces proxied by the AOP proxy.
	 * <p>Will not include the target class, which may also be proxied.
	 */
	Class<?>[] getProxiedInterfaces();
    
    ...
}

是否非常熟悉?其实在Spring AOP中,无论是基于JDK动态代理的代理对象,还是基于CGLIB的代理对象,他们最终都实现了这个接口。通过这个接口可以很方便的针对代理对象进行编程。

在这里插入图片描述

比如

ProxyFactory factory = new ProxyFactory(new DemoServiceImpl());
factory.addAdvice(new SimpleBeforeAdvice());
DemoService demoService = (DemoService) factory.getProxy();
User user = demoService.findById(9527L);
System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
1.强制类型转换
Advised advised = (Advised) demoService;
advised.addAdvice(new AnotherBeforeAdvice());
advised.addAdvisor(new SimpleAdvisor());
demoService.findById(9527L);

在创建好了代理对象之后再通过Advised添加了AdviceAdvisor.
在这里插入图片描述
通过org.springframework.aop.framework.Advised#getAdvisors接口可以获取到所有的切面,在上面通过addAdvice添加的会自动包装为切点永远返回为true的 Advisor对象。
在这里插入图片描述
源码如下

@Override
public void addAdvice(Advice advice) throws AopConfigException {
	int pos = this.advisors.size();
	addAdvice(pos, advice);
}

/**
 * Cannot add introductions this way unless the advice implements IntroductionInfo.
 */
@Override
public void addAdvice(int pos, Advice advice) throws AopConfigException {
	Assert.notNull(advice, "Advice must not be null");
	if (advice instanceof IntroductionInfo) {
		// We don't need an IntroductionAdvisor for this kind of introduction:
		// It's fully self-describing.
		addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
	}
	else if (advice instanceof DynamicIntroductionAdvice) {
		// We need an IntroductionAdvisor for this kind of introduction.
		throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
	}
	else {
		addAdvisor(pos, new DefaultPointcutAdvisor(advice));
	}
}

@Override
public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
	if (advisor instanceof IntroductionAdvisor) {
		validateIntroductionAdvisor((IntroductionAdvisor) advisor);
	}
	addAdvisorInternal(pos, advisor);
}

private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
	Assert.notNull(advisor, "Advisor must not be null");
	if (isFrozen()) {
		throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
	}
	if (pos > this.advisors.size()) {
		throw new IllegalArgumentException(
				"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
	}
	this.advisors.add(pos, advisor);
	updateAdvisorArray();
	adviceChanged();
}

可以看到其实在内部维护了一个List数据结构的容器advisors

/**
 * List of Advisors. If an Advice is added, it will be wrapped
 * in an Advisor before being added to this List.
 */
private List<Advisor> advisors = new ArrayList<Advisor>();

在添加完成之后,会执行adviceChanged操作,然后清除内部的一个缓存methodCache.这是一个32个大小的ConcurrentHashMap对象。在构造代理对象的时候进行初始化。

/** Cache with Method as key and advisor chain List as value */
private transient Map<MethodCacheKey, List<Object>> methodCache;

public AdvisedSupport() {
	initMethodCache();
}

/**
 * Initialize the method cache.
 */
private void initMethodCache() {
	this.methodCache = new ConcurrentHashMap<MethodCacheKey, List<Object>>(32);
}

清除了这个缓存怎么会影响到代理对象的呢?
参考如下代码(org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice

/**
 * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
 * for the given method, based on this configuration.
 * @param method the proxied method
 * @param targetClass the target class
 * @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
 */
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	List<Object> cached = this.methodCache.get(cacheKey);
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

当清空缓存之后,会重新构造增强链。
在前面介绍代理方法执行的时候应该对这个方法不陌生。可以去查看源码org.springframework.aop.framework.JdkDynamicAopProxy#invoke。或者参考上一章关于动态匹配和静态匹配部分的内容。

这里的缓存看来不仅仅是为了性能问题,而且也方便在内部属性修改之后通过清除缓存来达到刷新的目的

By default, it’s possible to add or remove advisors or interceptors even once a proxy has been created. The only restriction is that it’s impossible to add or remove an introduction advisor, as existing proxies from the factory will not show the interface change. (You can obtain a new proxy from the factory to avoid this problem.)

根据创建代理的方式,通常可以设置一个冻结的标志,在这种情况下,Advised isFrozen()方法将返回true,并且通过添加或删除来修改建议的任何尝试都将导致AopConfigException。

Exception in thread "main" org.springframework.aop.framework.AopConfigException: Cannot add advisor: Configuration is frozen.
	at org.springframework.aop.framework.AdvisedSupport.addAdvisorInternal(AdvisedSupport.java:365)
	at org.springframework.aop.framework.AdvisedSupport.addAdvisor(AdvisedSupport.java:266)
	at org.springframework.aop.framework.AdvisedSupport.addAdvice(AdvisedSupport.java:415)
	at org.springframework.aop.framework.AdvisedSupport.addAdvice(AdvisedSupport.java:396)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:179)
	at com.sun.proxy.$Proxy0.addAdvice(Unknown Source)
	at com.example.aop.advice.TestMain.main(TestMain.java:36)

在这里插入图片描述

冻结Adviised对象状态的功能在某些情况下很有用,例如,防止调用代码删除安全拦截器。 如果已知不需要修改运行时建议。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值