文档章节

【Spring】Spring AOP 代理对象生成逻辑源码分析

ZeroneLove
 ZeroneLove
发布于 07/16 20:43
字数 1760
阅读 78
收藏 0

「深度学习福利」大神带你进阶工程师,立即查看>>>

1. spring aop案例(POJO注入)

1.0 被代理接口 TargetInterface

/**
 * 被代理的接口
 * @author Yang ZhiWei
 */
public interface TargetInterface {

    void show();

    String showName();
}

1.1 被代理对象

@Slf4j
public class TargetObject implements TargetInterface {

    @Override
    public void show() {
        log.info("show----->I am a TargetObject!");
    }

    @Override
    public String showName() {
        return "showName--->TargetObject !";
    }
}

1.2 通知 MyAdvice

@Slf4j
public class MyAdvice {

    public void takeSeat() {
        log.info("====> MethodBeforeAdvice:Take Seat!");
    }

    public void turnOffPhone() {
        log.info("==> MethodBeforeAdvice:turn Off Phone!");
    }

    public void applaud(Object res) { //xml配置返回值
        log.info("==> AfterReturning:applaud,returning=" + res);
    }

    public void demandRefund(Exception e) {
        log.info("==> AfterThrowing:demandRefund,Exception=" + e);
    }

    public void goHone() {
        log.info("After:go Home!");
    }
}

1.3 AOP配置 applicationContext-pojo.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd ">

    <!-- 配置目标对象 -->
    <bean id="targetObject" class="com.zhiwei.aop.pojo.TargetObject"/>

    <!-- 配置切面 -->
    <bean id="myAdvice" class="com.zhiwei.aop.pojo.MyAdvice"/>

    <!-- 通过配置xml将pojo暴露成切面 -->
    <aop:config>
        <!-- 配置切面, ref 配置切面关联的通知 -->
        <aop:aspect ref="myAdvice">

            <!-- 定义切点 -->
            <aop:pointcut id="definePointCut"
                    expression="execution(* com.zhiwei.aop.pojo.TargetInterface.showName(..)) and
                    within(com.zhiwei.aop.pojo.*)" />

            <!-- 通知织入切入点及关联通知 -->
            <aop:before method="takeSeat" pointcut-ref="definePointCut"/>
            <aop:before method="turnOffPhone" pointcut-ref="definePointCut"/>
            <aop:after-returning method="applaud" pointcut-ref="definePointCut" returning="res"/>
            <aop:after-throwing method="demandRefund" pointcut-ref="definePointCut" throwing="e"/>
            <aop:after method="goHone" pointcut-ref="definePointCut"/>
        </aop:aspect>
    </aop:config>
</beans>

1.4 测试效果

public class TestPojo {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-pojo.xml");
        TargetInterface targetInterface = applicationContext.getBean(TargetInterface.class);
        targetInterface.showName();
        targetInterface.show();
    }
}

日志:

INFO [main] - MyAdvice - ====> MethodBeforeAdvice:Take Seat!
INFO [main] - MyAdvice - ==> MethodBeforeAdvice:turn Off Phone!
INFO [main] - MyAdvice - ==> AfterReturning:applaud,returning=showName--->TargetObject !
INFO [main] - MyAdvice - After:go Home!
INFO [main] - TargetObject - show----->I am a TargetObject!

2. AOP代理对象生成逻辑

2.1 aop:config 解析

spring 标签解析器配置:META-INF/spring.handlers

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
分析:XML命名空间解析器:AopNamespaceHandler

AopNamespaceHandler:aop 命名空间解析器

public class AopNamespaceHandler extends NamespaceHandlerSupport {

	/**
	 * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
	 * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
	 * and '{@code scoped-proxy}' tags.
	 */
	@Override
	public void init() {
		// 主要关主aop:config 解析,主要注册AspectJAwareAdvisorAutoProxyCreator,用于创建代理对象
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}
}

ConfigBeanDefinitionParser: aop:config解析器

解析接口:org.springframework.aop.config.ConfigBeanDefinitionParser.parse

@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);

        // 配置代理对象自动创建器
		configureAutoProxyCreator(parserContext, element);

		List<Element> childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			if (POINTCUT.equals(localName)) {
				parsePointcut(elt, parserContext);
			}
			else if (ADVISOR.equals(localName)) {
				parseAdvisor(elt, parserContext);
			}
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
		}

		parserContext.popAndRegisterContainingComponent();
		return null;
	}

configureAutoProxyCreator(parserContext, element); 调用栈

org.springframework.aop.config.ConfigBeanDefinitionParser.configureAutoProxyCreator
org.springframework.aop.config.AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary
org.springframework.aop.config.AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary

@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
        BeanDefinitionRegistry registry, @Nullable Object source) {
    // 注入AspectJAwareAdvisorAutoProxyCreator Bean
    return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}

aop:config: 主要作用就是注入AspectJAwareAdvisorAutoProxyCreator,用于后续创建代理对象

2.2 BeanPostProcessor(预备知识)

作用:Bean后置处理器,在Bean属性封装完成后,在对Bean进行额外操作,Spring AOP代理对象也是在此声明周期间完成代理对象创建工作

public interface BeanPostProcessor {

	
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

方法在Bean声明周期执行顺序如下(忽略其他细节):
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean -->
BeanPostProcessor.postProcessBeforeInitialization -->
org.springframework.beans.factory.InitializingBean.afterPropertiesSet --》
Bean.init-method(bean自定义初始化方法) --> 
BeanPostProcessor.postProcessAfterInitialization --> 
生成Bean实例放入IOC容器,最终放入一级缓存(singletonObjects)

调用链:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean

Bean初始化:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
            // 包含Bean生命周期接口
            // BeanNameAware: 获取Bean注册IOC容器标识
            // BeanClassLoaderAware: 获取Bean类加载器
            // BeanFactoryAware: 获取Bean工厂
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // 重点:BeanPostProcessor 完成实例化前置处理
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // 声明周期接口
            // InitializingBean: Bean属性封装完成后执行接口
            // init-method: 对象初始化初始化方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
            // 重点:BeanPostProcessor 完成实例化前置处理,代理对象生成是最后处理步骤,因此代理对象生成逻辑一般在后置处理逻辑
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

2.3 AspectJAwareAdvisorAutoProxyCreator 后置处理器

源码:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    // IOC容器默认配置多个BeanPostProcessor,多个处理器顺序处理,这里只关注前面aop:config注入的AspectJAwareAdvisorAutoProxyCreator
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

父类:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

实际处理逻辑:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// XML配置多种通知,这里根据AOP切点去匹配Bean是否属于拦截范围,若属于则返回有效拦截通知:After、AfterThrowing、AfterReturning、Before
        // 注意:通知拦截包含对象ExposeInvocationInterceptor,主要是用于调用代理对象方法时再调用各种通知处理,类似AQS的等待队列,1个通知处理完自动唤醒下1个通知处理
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 创建代理对象
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

创建AOP代理对象:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

        // 暴露目标类:这里主要时维护代理对象的基础类,放到BeanDefinition维护(属性名:AutoProxyUtils.originalTargetClass)
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

        //构建代理类工厂
		ProxyFactory proxyFactory = new ProxyFactory();

        // 复制AOP配置
		proxyFactory.copyFrom(this);

        // 判断是否是类代理,spring AOP默认接口代理
		if (!proxyFactory.isProxyTargetClass()) {
            // 进一步判断是否应该类代理,若是则设置类代理标识true
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
                //评估代理接口,剔除回调、Groovy、cglib等无用接口,并将最终被代理的接口维护到proxyFactory
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

        // 将通知转换为Advisor,里面包含通知信息
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
        // 设置被带离对象源
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
        // 创建AOP代理对象,并返回最终的代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}

2.4 创建代理对象:DefaultAopProxyFactory#createAopProxy

接口:org.springframework.aop.framework.DefaultAopProxyFactory.createAopProxy

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // AOP Proxy优化、类代理、没有被代理的合理接口 (例如:DisposableBean、Groovy、Cglib等无用接口)
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        // 如果是接口代理或接口是Proxy的继承接口,则JDK动态代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // Cglib 类代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        // 默认JDK动态代理
        return new JdkDynamicAopProxy(config);
    }
}

JdkDynamicAopProxy

实现接口:AopProxy(AOP代理对象获取接口)、InvocationHandler(JDK动态代理类处理逻辑接口)

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    }
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

    // JDK动态代理对象生成,这里InvocationHandler为this,说白了最后代理对象又转回JdkDynamicAopProxy
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

回到 return proxyFactory.getProxy(getProxyClassLoader()); 定位到 org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(java.lang.ClassLoader), 最终Spring AOP将JdkDynamicAopProxy作为代理对象返回最终到IOC容器, 至此整个Spring AOP代理对象创建完成,以后引用该对象即引用其代理对象

ZeroneLove
粉丝 6
博文 188
码字总数 177580
作品 0
深圳
高级程序员
私信 提问
加载中
请先登录后再评论。
Netty那点事(三)Channel与Pipeline

Channel是理解和使用Netty的核心。Channel的涉及内容较多,这里我使用由浅入深的介绍方法。在这篇文章中,我们主要介绍Channel部分中Pipeline实现机制。为了避免枯燥,借用一下《盗梦空间》的...

黄亿华
2013/11/24
2W
22
访问安全控制解决方案

本文是《轻量级 Java Web 框架架构设计》的系列博文。 今天想和大家简单的分享一下,在 Smart 中是如何做到访问安全控制的。也就是说,当没有登录或 Session 过期时所做的操作,会自动退回到...

黄勇
2013/11/03
3.5K
8
Flappy Bird(安卓版)逆向分析(一)

更改每过一关的增长分数 反编译的步骤就不介绍了,我们直接来看反编译得到的文件夹 方法1:在smali目录下,我们看到org/andengine/,可以知晓游戏是由andengine引擎开发的。打开/res/raw/at...

enimey
2014/03/04
6.1K
18
beego API开发以及自动化文档

beego API开发以及自动化文档 beego1.3版本已经在上个星期发布了,但是还是有很多人不了解如何来进行开发,也是在一步一步的测试中开发,期间QQ群里面很多人都问我如何开发,我的业余时间实在...

astaxie
2014/06/25
2.7W
22
程序猿媛一:Android滑动翻页+区域点击事件

滑动翻页+区域点击事件 ViewPager+GrideView 声明:博文为原创,文章内容为,效果展示,思路阐述,及代码片段。文尾附注源码获取途径。 转载请保留原文出处“http://my.oschina.net/gluoyer...

花佟林雨月
2013/11/09
4.2K
1

没有更多内容

加载失败,请刷新页面

加载更多

华为大危机!余承东:麒麟芯片告罄,今年或许是高端芯片最后一代

     大数据文摘出品   作者:牛婉杨   美国制裁下,华为麒麟芯片即将告罄。   华为消费者业务CEO余承东称,由于来自美国的持续经济压力,华为下个月将无法生产自己的麒麟芯片组。...

osc_qmxpov5s
18分钟前
0
0
狂神说Java多线程详解(二)

狂神的视频截图作为学习记录:线程同步和线程协作。 本文分享自微信公众号 - Android架构师成长之路(gh_07f996f00d9b)。 如有侵权,请联系 support@oschina.cn 删除。 本文参与“OSC源创计...

datoushiwoma
07/13
0
0
英特尔20GB数据泄漏!包含未发芯片文件,内部密码多为intel123

     大数据文摘出品   来源:Arstechnica   近日,英特尔发生了一起重大的数据泄漏事故,超过20GB的专有数据和源代码被放在了网上。   这20GB的泄漏数据不仅量大,而且包含的内容...

osc_tjee7sjs
19分钟前
9
0
postgresql 主键 id 设置自增

创建自增序列(起始值必须大于 0 ) CREATE SEQUENCE standard_detail_id_seq START 1; 主键 ID 默认设置为 nextval('standard_detail_id_seq'::regclass)...

青苗
19分钟前
0
0
Ubuntu-16.04安装 VS code

安装微软Visual Studio Code 首先需要安装Ubuntu Make。虽然Ubuntu Make存在Ubuntu15.04官方库中,但是需要Ubuntu Make 0.7以上版本才能安装Visual Studio。所以,需要通过官方PPA更新到最新...

贪狼lyb
2019/11/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部