如果需要在Spring中使用AOP是非常简单的,只需要在Bean上加上@AspectJ,在方法上加@PointCut、@Before等注解就可以实现你想要的逻辑,最后在XML配置文件中加入<aop:aspectj-autoproxy>
即可。
那么Spring是如何实现的呢?
动态AOP标签
我们从AopNamespaceHandler中的init()方法开始分析:
1.配置文件中在遇到aspectj-autoproxy标签的时候我们会采用AspectJAutoProxyBeanDefinitionParser解析器
2.进入AspectJAutoProxyBeanDefinitionParser的parse方法,它将请求给了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去处理
3.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中,先调用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法完成注册或者升级AnnotationAwareAspectJAutoProxyCreator类。对于AOP的实现,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@point注解定义的切点来代理相匹配的bean。
4.接下来会调用useClassProxyingIfNecessary() 处理proxy-target-class以及expose-proxy属性
5.最后的调用registerComponentIfNecessary 方法,注册组建并且通知便于监听器做进一步处理。
2.创建AOP代理
AOP主要是依靠AnnotationAwareAspectJAutoProxyCreator的实现的。那么AnnotationAwareAspectJAutoProxyCreator是如何完成的?
AnnotationAwareAspectJAutoProxyCreator的层次结构:
AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor接口,那就意味着这个类在spring加载实例化前会调用postProcessAfterInitialization方法。
public Object <strong>postProcessAfterInitialization</strong>(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
逻辑:
1.根据bean的class和name生成一个key。
2.如果适合代理就执行wrapIfNecessary(bean, beanName, cacheKey)。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.containsKey(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;
}
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;
}