Spring系列-Spring AOP原理分析

本文详细探讨了Spring AOP的实现原理,包括Advice、Pointcut和Advisor的概念,以及Spring如何通过动态代理创建代理对象。核心逻辑在于将Advice转换为拦截器,通过拦截器在方法调用前后执行特定操作,实现面向切面编程。
摘要由CSDN通过智能技术生成

先了解一些AOP的概念:
1.Advice(通知)
定义在连接点做什么,为切面增强提供织入接口。比如BeforeAdvice,AfterAdvice等。可以定义在方法执行前或执行后需要做的操作。
在这里插入图片描述
2.Pointcut(切点)
定义Advice通知应该作用于哪个连接点。
在这里插入图片描述
比如这个JdkRegexpMethodPointcut,就是通过正则表达式是否匹配来判断是否作用于这个Adivce的。

3.Advisor(通知器)
Advisor是Advice和Pointcut的结合,定义了应该使用哪个Advice,并且定义了在哪个Pointcut使用。也就是说,定义了在哪个条件用哪个Advice。

Spring AOP的实现,用到了动态代理,所以还要对动态代理有个了解,我之前在一篇帖子中也总结过JDK动态代理的用法:动态代理总结

Java已经提供了Proxy类,一般情况下,我们通过Proxy.newProxyInstance方法,就可以创建一个代理对象了。

那Spring AOP的原理是啥呢,我们定义了Advisor之后,如何起作用呢。
先说下结论吧,我们用了Advisor,来定义了我们要为某个类在满足某些条件的时候增强,当我们在使用这个类的对象时候,Spring AOP就会为这个类生成一个代理对象,并且把我们在Advice里面定义的操作都封装成一个个的拦截器,当我们调用方法的时候,就会先经过这些拦截器,然后再通过反射来调用真正的方法。

Spring AOP模块关于生成代理对象时,会涉及到下面这些类。
在这里插入图片描述
对于需要使用AspectJ的AOP应用,AspectJProxyFactory就可以集成Spring和AspectJ,对于使用Spring AOP的应用,ProxyFactoryBean和ProxyFactory都提供了AOP的封装,不同的是,ProxyFactoryBean可以在IoC容器中完成声明式的配置,而ProxyFactory需要编程式的使用。

接下来看下ProxyFactoryBean,使用ProxyFactoryBean之前需要配置,定义使用的通知器Advisor,定义target等,这里就不再详细说明,关键去看代码。

接下来,看一下ProxyFactoryBean如何生成代理对象的,看ProxyFactoryBean类的代码,很明显可以看到一个getObject方法,注释写的是返回一个proxy,那就是它了:

/**
 * Return a proxy. Invoked when clients obtain beans from this factory bean.
 * Create an instance of the AOP proxy to be returned by this factory.
 * The instance will be cached for a singleton, and create on each call to
 * {@code getObject()} for a proxy.
 * @return a fresh AOP proxy reflecting the current state of this factory
 */
@Override
public Object getObject() throws BeansException {
	initializeAdvisorChain();
	if (isSingleton()) {
		return getSingletonInstance();
	}
	else {
		if (this.targetName == null) {
			logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
					"Enable prototype proxies by setting the 'targetName' property.");
		}
		return newPrototypeInstance();
	}
}

getObject里面,能够看到主要有三个方法,第一个是initializeAdvisorChain,这个是初始化Advisor链的,接下来,还需要判断一下,对于singleton和prototype来说,需要调用不同的方法来生成proxy。

那就先看下initializeAdvisorChain的逻辑:

/**
 * Create the advisor (interceptor) chain. Advisors that are sourced
 * from a BeanFactory will be refreshed each time a new prototype instance
 * is added. Interceptors added programmatically through the factory API
 * are unaffected by such changes.
 */
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
	// 判断通知器链是否已经初始化,如果已经初始化了,就直接返回。
	if (this.advisorChainInitialized) {
		return;
	}

	if (!ObjectUtils.isEmpty(this.interceptorNames)) {
		if (this.beanFactory == null) {
			throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
					"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
		}

		// Globals can't be last unless we specified a targetSource using the property...
		if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
				this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("Target required after globals");
		}

		// Materialize interceptor chain from bean names.
		for (String name : this.interceptorNames) {
			if (logger.isTraceEnabled()) {
				logger.trace("Configuring advisor or advice '" + name + "'");
			}

			if (name.endsWith(GLOBAL_SUFFIX)) {
				if (!(this.beanFactory instanceof ListableBeanFactory)) {
					throw new AopConfigException(
							"Can only use global advisors or interceptors with a ListableBeanFactory");
				}
				addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
						name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
			}

			else {
				// If we get here, we need to add a named interceptor.
				// We must check if it's a singleton or prototype.
				Object advice;
				if (this.singleton || this.beanFactory.isS
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值