spring中最重要的概念有2个,一个是IOC(inverse of control)和aop(面向切面编程),今天我们来聊聊aop面向切面编程;
基础概念这里就不做介绍了,今天我们主要来说说aop的实现,先来一个简单的例子:
public interface Dao { public void insert(); public void select(); } public class DaoImpl implements Dao { @Override public void insert() { System.out.println("Enter DaoImpl.insert()"); } @Override public void select() { System.out.println("Enter DaoImpl.select()"); } }
public class TimeHandler { public static void print(){ System.out.println("CurrentTime:" + System.currentTimeMillis()); } }
<bean id="daoImpl" class="controller.DaoImpl" /> <bean id="timeHandler" class="controller.TimeHandler" /> <aop:config proxy-target-class="true"> <aop:aspect id="time" ref="timeHandler"> <aop:pointcut id="addAllMethod" expression="execution(* controller.Dao.*(..))" /> <aop:before method="print" pointcut-ref="addAllMethod" /> <aop:after method="print" pointcut-ref="addAllMethod" /> </aop:aspect> </aop:config>
public class Application { public static void main(String[] args) { /* ConfigurableApplicationContext context = SpringApplication.run(Application.class,args); Dao dao =(Dao) context.getBean("daoImpl"); dao.insert(); dao.select();*/ ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml"); Dao dao =(Dao) context.getBean("daoImpl"); dao.insert(); dao.select(); } }
我们都知道aop的实现原理是jdk的动态代理(当实现接口的时候)和cglib代理,这2种技术都是通过代理对象来实现aop的,既然是通过代理对象,那么这个代理对象是什么时候生成的?答案就是bean初始化的时候,所以我们先从bean解析来看起:
BeanDefinitionDocumentReader
这是一个接口,他只有一个方法registerBeanDefinitions方法,这个方法的作用是从xml解析bean的配置文件并生成BeanDefinitions对象以便后面初始化bean的时候使用;
DefaultBeanDefinitionDocumentReader
这个是BeanDedfnitionDocumentReader类的唯一一个默认实现类;
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
/** * Register each bean definition within the given root {@code <beans/>} element. */ protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. //这是一个BeanDifinition的解析器,解析工作就由他来做 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); //是不是默认的命名空间,true,这里的root的namespace是http://www.springframework.org/schema/beans if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } //空方法 preProcessXml(root); //解析BeanDefinitions,这就是解析的入口方法 parseBeanDefinitions(root, this.delegate); //空方法 postProcessXml(root); this.delegate = parent; }
/** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { //获取root节点的所有子节点,这里是beans节点下的所有bean NodeList nl = root.getChildNodes(); //迭代所有的bean, 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)) { //判断bean是不是默认的namespace,像<bean id="daoImpl" class="controller.DaoImpl" />会走这个分支,解析成一个 //beanDefinition parseDefaultElement(ele, delegate); } else { //判断bean是不是默认的namespace,像<aop:config proxy-target-class="true">会走这个分支,解析成一个 //beanDefinition delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
先从正常的bean标签解析看起:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //解析import标签 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //解析alias标签 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //解析bean标签,这里走的是正常的解析bean标签 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //解析beans标签 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
进入正常的解析bean标签的方法:processBeanDefinition
/** * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //BeanDefinitionHolder看以看成是一个BeanDefinition的包装类,我们进去parseBeanDefinitionElement看看 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //修饰BeanDefinitionHolder bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //注册生成的BeanDefinitionbean 进factory BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. //发送一个注册事件,至此一个完整的beanDefinition的解析、生产、注册就已经完成乐 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
/** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); }
/** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { //获取bean的id,这里是timeHandler String id = ele.getAttribute(ID_ATTRIBUTE); //获取bean的name,这里是空值 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); //如果name不为空值,那么split后放进list别名集合 if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; //如果id为空,但是name部位不为空,那么取name的第一个集合对象赋值给beanName if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } //检查beanName是否唯一 if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } //生成BeanDefinition对象的方法 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); //返回BeanDefinitionHolder对象 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
/** * Parse the bean definition itself, without regard to name or aliases. May return * {@code null} if problems occurred during the parsing of the bean definition. */ public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); //获取class标签对象 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { //获取parent标签对象 String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } //生成BeanDefinition对象 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //设置beanDefinition的一般属性,比如scope,autowired等等 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //解析元数据信息 parseMetaElements(ele, bd); //解析bean的lookup-method标签 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //解析bean的replaced-method标签 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析bean的constructor-arg标签 parseConstructorArgElements(ele, bd); //解析property标签 parsePropertyElements(ele, bd); //解析qualifier标签 parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
/** * Create a bean definition for the given class name and parent name. * @param className the name of the bean class * @param parentName the name of the bean's parent bean * @return the newly created bean definition * @throws ClassNotFoundException if bean class resolution was attempted but failed */ protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); }
/** * Create a new GenericBeanDefinition for the given parent name and class name, * eagerly loading the bean class if a ClassLoader has been specified. * @param parentName the name of the parent bean, if any * @param className the name of the bean class, if any * @param classLoader the ClassLoader to use for loading bean classes * (can be {@code null} to just register bean classes by name) * @return the bean definition * @throws ClassNotFoundException if the bean class could not be loaded */ public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { //一般的Bean生成的都是 GenericBeanDefinition 对象 GenericBeanDefinition bd = new GenericBeanDefinition(); //设置parentName bd.setParentName(parentName); if (className != null) { //设置BeanClass的Class对象 if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; }
以上是正常的bean的解析流程,对于spingaop的标签<aop:config />走的是另一套方法分支parseCustomElement
public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { //获取aop的namespaceURI,这里是http://www.springframework.org/schema/aop String namespaceUri = getNamespaceURI(ele); //通过namespaceuri获取NamespaceHandler为AopNamespaceHandler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } //通过NamespaceHandler解析aop:config标签 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
/** * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is * registered for that {@link Element}. */ @Override public BeanDefinition parse(Element element, ParserContext parserContext) { //调用ConfigBeanDefinitionParser的parse方法 return findParserForElement(element, parserContext).parse(element, parserContext); } /** * Locates the {@link BeanDefinitionParser} from the register implementations using * the local name of the supplied {@link Element}. */ private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { //这里的localName=config String localName = parserContext.getDelegate().getLocalName(element); //通过localName获得Parse对象ConfigBeanDefinitionParser BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
ConfigBeanDefinitionParser
@Override public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); //创建自动代理对象的BeanDefinition,AspectJAwareAdvisorAutoProxyCreator和internalAutoProxyCreator configureAutoProxyCreator(parserContext, element); //解析aop:config标签 List<Element> childElts = DomUtils.getChildElements(element); for (Element elt: childElts) { //先解析aspect标签 String localName = parserContext.getDelegate().getLocalName(elt); if (POINTCUT.equals(localName)) { parsePointcut(elt, parserContext); } else if (ADVISOR.equals(localName)) { parseAdvisor(elt, parserContext); } //进入aspect标签解析 else if (ASPECT.equals(localName)) { parseAspect(elt, parserContext); } } parserContext.popAndRegisterContainingComponent(); return null; }
开始解析aspect标签:
private void parseAspect(Element aspectElement, ParserContext parserContext) { //aspect的id标签 String aspectId = aspectElement.getAttribute(ID); //ref标签 String aspectName = aspectElement.getAttribute(REF); try { this.parseState.push(new AspectEntry(aspectId, aspectName)); List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); List<BeanReference> beanReferences = new ArrayList<BeanReference>(); List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS); for (int i = METHOD_INDEX; i < declareParents.size(); i++) { Element declareParentsElement = declareParents.get(i); beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext)); } // We have to parse "advice" and all the advice kinds in one loop, to get the // ordering semantics right. //迭代aspect标签的所有子标签 NodeList nodeList = aspectElement.getChildNodes(); boolean adviceFoundAlready = false; for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); //判断是不是一个通知 if (isAdviceNode(node, parserContext)) { if (!adviceFoundAlready) { adviceFoundAlready = true; if (!StringUtils.hasText(aspectName)) { parserContext.getReaderContext().error( "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.", aspectElement, this.parseState.snapshot()); return; } beanReferences.add(new RuntimeBeanReference(aspectName)); } //主要看这个解析advice的方法 AbstractBeanDefinition advisorDefinition = parseAdvice( aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences); beanDefinitions.add(advisorDefinition); } } AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition( aspectElement, aspectId, beanDefinitions, beanReferences, parserContext); parserContext.pushContainingComponent(aspectComponentDefinition); List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); for (Element pointcutElement : pointcuts) { //解析pointcut标签 parsePointcut(pointcutElement, parserContext); } parserContext.popAndRegisterContainingComponent(); } finally { this.parseState.pop(); } }
判断是不是一个通知:主要有前置通知,后置通知,环绕通知,异常通知,返回通知五种类型 /** * Return {@code true} if the supplied node describes an advice type. May be one of: * '{@code before}', '{@code after}', '{@code after-returning}', * '{@code after-throwing}' or '{@code around}'. */ private boolean isAdviceNode(Node aNode, ParserContext parserContext) { if (!(aNode instanceof Element)) { return false; } else { String name = parserContext.getDelegate().getLocalName(aNode); return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) || AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name)); } }
/** * Parses one of '{@code before}', '{@code after}', '{@code after-returning}', * '{@code after-throwing}' or '{@code around}' and registers the resulting * BeanDefinition with the supplied BeanDefinitionRegistry. * @return the generated advice RootBeanDefinition */ private AbstractBeanDefinition parseAdvice( String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { try { this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement))); // create the method factory bean //创建一个方法工厂的bean,targetBeanName = TimeHandler,methodName = print RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class); methodDefinition.getPropertyValues().add("targetBeanName", aspectName); methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method")); methodDefinition.setSynthetic(true); // create instance factory definition //创建一个实例工厂的bean RootBeanDefinition aspectFactoryDef = new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName); aspectFactoryDef.setSynthetic(true); // register the pointcut //注册一个pointcut的BeanDefinition AbstractBeanDefinition adviceDef = createAdviceDefinition( adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, beanDefinitions, beanReferences); // configure the advisor RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class); advisorDefinition.setSource(parserContext.extractSource(adviceElement)); advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef); if (aspectElement.hasAttribute(ORDER_PROPERTY)) { advisorDefinition.getPropertyValues().add( ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY)); } // register the final advisor //注册完整的advisor,包含切点和切面 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); return advisorDefinition; } finally { this.parseState.pop(); } }
/** * Creates the RootBeanDefinition for a POJO advice bean. Also causes pointcut * parsing to occur so that the pointcut may be associate with the advice bean. * This same pointcut is also configured as the pointcut for the enclosing * Advisor definition using the supplied MutablePropertyValues. */ private AbstractBeanDefinition createAdviceDefinition( Element adviceElement, ParserContext parserContext, String aspectName, int order, RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef, List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { //解析before标签,返回一个AspectJMethodBeforeAdvice的RootBeanDefinition RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext)); adviceDefinition.setSource(parserContext.extractSource(adviceElement)); //配置通知类,这里是timeHandler adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName); //配置通知的方法,这里是print adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order); if (adviceElement.hasAttribute(RETURNING)) { adviceDefinition.getPropertyValues().add( RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING)); } if (adviceElement.hasAttribute(THROWING)) { adviceDefinition.getPropertyValues().add( THROWING_PROPERTY, adviceElement.getAttribute(THROWING)); } if (adviceElement.hasAttribute(ARG_NAMES)) { adviceDefinition.getPropertyValues().add( ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES)); } ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues(); cav.addIndexedArgumentValue(METHOD_INDEX, methodDef); Object pointcut = parsePointcutProperty(adviceElement, parserContext); if (pointcut instanceof BeanDefinition) { cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut); beanDefinitions.add((BeanDefinition) pointcut); } //解析pointcut的索引,这里是addAllMethod else if (pointcut instanceof String) { RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut); cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef); beanReferences.add(pointcutRef); } cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef); //返回的就是一个完整的切面的bizdefine,包含切点的索引和切面 return adviceDefinition; }
/** * Parses the supplied {@code <pointcut>} and registers the resulting * Pointcut with the BeanDefinitionRegistry. */ private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) { String id = pointcutElement.getAttribute(ID); String expression = pointcutElement.getAttribute(EXPRESSION); AbstractBeanDefinition pointcutDefinition = null; try { this.parseState.push(new PointcutEntry(id)); pointcutDefinition = createPointcutDefinition(expression); pointcutDefinition.setSource(parserContext.extractSource(pointcutElement)); String pointcutBeanName = id; if (StringUtils.hasText(pointcutBeanName)) { parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition); } else { pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition); } parserContext.registerComponent( new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression)); } finally { this.parseState.pop(); } return pointcutDefinition; }
整个解析到这就结束了!