在Spring中可以通过xml方式,或者注解方式来实现Aop,如果通过注解方式则需要在xml中配置
代码语言:javascript复制<aop:aspectj-autoproxy/>
这篇文章详细讲解一下注解方式是如何来实现Aop的。
一、注册beanDefinitionParser
AopNamespaceHandler是aop命名空间的处理类
它注册了解析config、aspectj-autoproxy、scoped-proxy标签的BeanDefinitionParser,spring-configured标签从2.1开始就被移动了context命名空间中。
代码语言:javascript复制 @Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
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());
}
我们直接来看AspectJAutoProxyBeanDefinitionParser的代码:
二、aspectj-autoproxy解析入口
解析分成两项工作
1.注册AspectJAnnotationAutoProxyCreator
2.获取子标签,注册到beanDefinition
代码语言:javascript复制@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
三、注册AspectJAnnotationAutoProxyCreator
1.如果要代理的类实现了接口,则默认使用jdk动态代理否则将使用cglib进行代理
2.如果配置了proxy-target-class为true,将强制使用cglib进行代理
代码语言:javascript复制 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册registerAspectJAnnotationAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 处理xml中配置的aspectj-autoproxy中的proxy-target-class 和 expose-proxy属性
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册组件
registerComponentIfNecessary(beanDefinition, parserContext);
}
顾名思义注册或者升级AspectJAnnotationAutoProxyCreator,如果有优先级更高的AspectJAnnotationAutoProxyCreator,那么升级为优先级更高的AspectJAnnotationAutoProxyCreator,这里不进行详细解释
代码语言:javascript复制public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
完成了上述工作,AnnotationAwareAspectJAutoProxyCreator就已经在IOC容器中注册完毕了。
四、AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator它层级实现了InstantiationAwareBeanPostProcessor
,学习过Spring IOC容器源码的童鞋应该知道它的postProcessor方法将会在IOC容器中bean的实例化,初始化等等时候被调用。aop的核心也就是在此。
在AbstractAutoProxyCreator类中对这些方法进行了重写:
代码语言:javascript复制public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// 在className和beanName中用"_"连接 例:cn.blingfeng.Test_test
Object cacheKey = getCacheKey(beanClass, beanName);
// 如果beanName为空或者bean还未被处理过
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
// 如果不需要代理
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 如果为Advisor Advice AopInfrastructureBean 类的实现类 或者 为pointCut则不需要处理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
if (beanName != null) {
// 获取定制的targetSource,可以通过子类重写此方法,来实现不同的机制
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
// 获取增强方法
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 创建代理
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// bena进行包装
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
代码语言:javascript复制protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果bean还未被处理
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// bean不需要增强
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果为Advisor Advice AopInfrastructureBean 类的实现类 或者 为pointCut则不需要处理
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;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
isInfrastructureClass()方法具体实现,如果为Advice或Advisor或AopInfrastrutureBean的实现则返回true
代码语言:javascript复制 protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
if (retVal && logger.isTraceEnabled()) {
logger.trace("Did not attempt to auto-proxy infrastructure class [" beanClass.getName() "]");
}
return retVal;
}
shouldSkip()方法具体实现,
首先获取所有的增强,可以看到上面有一个todo注释:考虑缓存aspect names,因为findCandidateAdvisors()这个方法,我们在后面的获取增强方法,进行代理,还要用到,所以弄一个Set集合进行缓存可以提升性能。
然后遍历增强,如果为AspectJPointcutAdvisor派生类则返回true
代码语言:javascript复制@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor) {
if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
return true;
}
}
}
return super.shouldSkip(beanClass, beanName);
}
获取增强
代码语言:javascript复制@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
1.首先获取所有的增强
2.寻找适用于该bean的增强
代码语言:javascript复制protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 1.
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2.
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
我们虽使用了注解来使用aop,但是xml仍可以进行配置,因此需要获取xml和注解配置的增强
代码语言:javascript复制@Override
protected List<Advisor> findCandidateAdvisors() {
// 获取xml中配置的增强
List<Advisor> advisors = super.findCandidateAdvisors();
// 获取注解配置的增强
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}
xml和注解获取增强不详细描述,xml无非就是进行解析获取。注解的话就是获取所有的beanName,然后扫描这些bean的Aspect注解,然后获取切点,增强等等。
然后根据xml或者注解中配置的表达式获取适用于此bean的增强。下篇进行代理创建的分析