spring源码解读 AOP原理

    xiaoxiao2021-03-25  44

    本文主要分析通过<aop:config>这种标签来使用spring AOP的过程。Spring版本是4.1.7。在我看来Spring AOP主要分四个步骤,加载解析AOP标签,生成代理对象,拦截器的调用。下面就是通过这四个方面来分析Spring AOP的原理。

    一.容器初始化,解析AOP标签。

    1.先看一下我跟源码时关于AOP的配置 <aop:config> <aop:aspect ref="print"> <aop:pointcut expression="execution(* aop.*.do*(..))" id="pointcut" /> <aop:after method="printLog" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> 2.spring 在容器初始化时会通过一系列的BeanDefinitionParser将我们定义的内容解析成Spring内部的使用的数据结构BeanDefinition。spring 容器初始化的过程,不在多说,主要说明一下AOP标签解析的过程。AOP标签解析的入口 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { //解析除了Bean标签之外的其它标签 //AOP标签解析的入口 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } 在spring中bean标签是default,其它的任何标签都是custom。我们接着跟代码 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); } 获取NamespaceHandler的过程主要就是通过命名空间 http://www.springframework.org/schema/aop,找到定义标签的Handler文件,在spring-aop的jar包里META—INF里的spring.handlers,内容如下: http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler Spring对不同的命名空间都有相对应的NamespaceHandler。从上面的内容可以看出处理AOP命名空间的是AopNamespaceHandler,我们看一下AopNamespaceHandler里的内容。 public class AopNamespaceHandler extends NamespaceHandlerSupport { @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()); } }从中可以看出NameSpaceHandler主要是来注册用来解析标签的BeanDefitionParser,解析<aop:config>标签的是ConfigBeanDefitionParser,看一下主要的解析过程 public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); //解析<aop:config>标签 parserContext.pushContainingComponent(compositeDef); configureAutoProxyCreator(parserContext, element); List<Element> childElts = DomUtils.getChildElements(element); for (Element elt: childElts) { String localName = parserContext.getDelegate().getLocalName(elt); //解析<aop:pointcut>标签 if (POINTCUT.equals(localName)) { parsePointcut(elt, parserContext); } //解析<aop:padvisor>标签 else if (ADVISOR.equals(localName)) { parseAdvisor(elt, parserContext); //解析<aop:aspect>标签 else if (ASPECT.equals(localName)) { parseAspect(elt, parserContext); } } parserContext.popAndRegisterContainingComponent(); return null; } 在解析<aop:config>的子标签时都是生成BeanDefinition,在BeanFactory中有个重要属性beanDefinitionMap,里面保存着解析的结果,大家调试的时候可以看下里面除了你定义的bean之外,还有Aop标签的解析结果。在解析<aop:config>是有个重要的步骤,如下 public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source); } 向BeanFactory中AspectJAwareAdvisorAutoProxyCreator,这个其实就是个BeanPostProcessor,对spring了解的可以知道,这是spring对外暴露的扩展点,里面定义了俩个方法,postProcessBeforeInstantiation在bean初始化之前,postProcessAfterInitialization在Bean初始化之后 用。 AspectJAwareAdvisorAutoProxyCreator 这个东西就是我们要找的东西,因为有了它我们才会生成代理对象。

    二.生成代理对象。

    1.在通过getBean()触发依赖注入之后,spring先生成对象的实例,然后进行初始化,在完成初始化之后会调用BeanPostProcessor的 postProcessAfterInitialization()方法,这里就是生成代理对象的入口。上面我们说了spring在解析Aop标签时会向容器注入AspectJAwareAdvisorAutoProxyCreator,其postProcessAfterInitialization的方法在父类AbstractAutoProxyCreator里,我们看一下其方法的实现: public Object postProcessAfterInitialization(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 (beanName != null && 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; } //1.判断是否有advisor和当前bean的class匹配 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //2.来生成代理对象 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; } 其中1的主要逻辑在AopUtils中,我们看一下主要的过程 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new LinkedList<Advisor>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) { return false; } MethodMatcher methodMatcher = pc.getMethodMatcher(); IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } } return false; } 主要过程就是获取所有配置的advisor,然后循序校验,先判断类名是不是匹配,如果匹配则判断是不是有方法匹配。 生成代理对象有俩中策略,一种是JDK的动态代理,还有一种是Cglib,由于我并不是很了解Cglib我们看一下JDK动态的代理。 public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }很熟悉的东西。

    三.拦截器的调用。

    先看一下 CglibAopProxy里的i ntercept()方法 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Class<?> targetClass = null; Object target = null; try { if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } //获取目标类 target = getTarget(); if (target != null) { targetClass = target.getClass(); } //1.获取拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { //没有匹配的拦截器则直接执行目标方法 retVal = methodProxy.invoke(target, args); } else { //2.执行匹配的拦截器链 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null) { releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } 先看一下如何获取匹配的拦截器, @Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class<?> targetClass) { List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); //根据配置文件获取advisor集合,然后循环遍历 for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; //class是否匹配 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); //方法名是否匹配 if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { if (mm.isRuntime()) { for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; } 根据要执行的实例的类名,方法名循环遍历配置的advisor来判断。 我们最后在看一下是怎么执行的 public Object proceed() throws Throwable { // 判断是否到了链尾,如果是则执行目标方法,调用结束。 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 取出当前的Advisor; Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 判断是否需要动态判断参数,如果需要则执行如下操作;        // 参数验证通过则执行Advisor,否则跳过该Advisor; InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { return proceed(); } } else { // 如果不需要动态判断参数,则执行该Advisor,因为在之前已经验证通过了; return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } 在这里就分析完了。

    转载请注明原文地址: https://ju.6miu.com/read-26169.html

    最新回复(0)