001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.scheduling.config; 018 019import org.w3c.dom.Element; 020 021import org.springframework.aop.config.AopNamespaceUtils; 022import org.springframework.beans.factory.config.BeanDefinition; 023import org.springframework.beans.factory.config.BeanDefinitionHolder; 024import org.springframework.beans.factory.parsing.BeanComponentDefinition; 025import org.springframework.beans.factory.parsing.CompositeComponentDefinition; 026import org.springframework.beans.factory.support.BeanDefinitionBuilder; 027import org.springframework.beans.factory.support.BeanDefinitionRegistry; 028import org.springframework.beans.factory.xml.BeanDefinitionParser; 029import org.springframework.beans.factory.xml.ParserContext; 030import org.springframework.lang.Nullable; 031import org.springframework.util.StringUtils; 032 033/** 034 * Parser for the 'annotation-driven' element of the 'task' namespace. 035 * 036 * @author Mark Fisher 037 * @author Juergen Hoeller 038 * @author Ramnivas Laddad 039 * @author Chris Beams 040 * @author Stephane Nicoll 041 * @since 3.0 042 */ 043public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { 044 045 private static final String ASYNC_EXECUTION_ASPECT_CLASS_NAME = 046 "org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"; 047 048 049 @Override 050 @Nullable 051 public BeanDefinition parse(Element element, ParserContext parserContext) { 052 Object source = parserContext.extractSource(element); 053 054 // Register component for the surrounding <task:annotation-driven> element. 055 CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); 056 parserContext.pushContainingComponent(compDefinition); 057 058 // Nest the concrete post-processor bean in the surrounding component. 059 BeanDefinitionRegistry registry = parserContext.getRegistry(); 060 061 String mode = element.getAttribute("mode"); 062 if ("aspectj".equals(mode)) { 063 // mode="aspectj" 064 registerAsyncExecutionAspect(element, parserContext); 065 } 066 else { 067 // mode="proxy" 068 if (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) { 069 parserContext.getReaderContext().error( 070 "Only one AsyncAnnotationBeanPostProcessor may exist within the context.", source); 071 } 072 else { 073 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( 074 "org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor"); 075 builder.getRawBeanDefinition().setSource(source); 076 String executor = element.getAttribute("executor"); 077 if (StringUtils.hasText(executor)) { 078 builder.addPropertyReference("executor", executor); 079 } 080 String exceptionHandler = element.getAttribute("exception-handler"); 081 if (StringUtils.hasText(exceptionHandler)) { 082 builder.addPropertyReference("exceptionHandler", exceptionHandler); 083 } 084 if (Boolean.parseBoolean(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) { 085 builder.addPropertyValue("proxyTargetClass", true); 086 } 087 registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME); 088 } 089 } 090 091 if (registry.containsBeanDefinition(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)) { 092 parserContext.getReaderContext().error( 093 "Only one ScheduledAnnotationBeanPostProcessor may exist within the context.", source); 094 } 095 else { 096 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( 097 "org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor"); 098 builder.getRawBeanDefinition().setSource(source); 099 String scheduler = element.getAttribute("scheduler"); 100 if (StringUtils.hasText(scheduler)) { 101 builder.addPropertyReference("scheduler", scheduler); 102 } 103 registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME); 104 } 105 106 // Finally register the composite component. 107 parserContext.popAndRegisterContainingComponent(); 108 109 return null; 110 } 111 112 private void registerAsyncExecutionAspect(Element element, ParserContext parserContext) { 113 if (!parserContext.getRegistry().containsBeanDefinition(TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)) { 114 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ASYNC_EXECUTION_ASPECT_CLASS_NAME); 115 builder.setFactoryMethod("aspectOf"); 116 String executor = element.getAttribute("executor"); 117 if (StringUtils.hasText(executor)) { 118 builder.addPropertyReference("executor", executor); 119 } 120 String exceptionHandler = element.getAttribute("exception-handler"); 121 if (StringUtils.hasText(exceptionHandler)) { 122 builder.addPropertyReference("exceptionHandler", exceptionHandler); 123 } 124 parserContext.registerBeanComponent(new BeanComponentDefinition(builder.getBeanDefinition(), 125 TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)); 126 } 127 } 128 129 private static void registerPostProcessor( 130 ParserContext parserContext, BeanDefinitionBuilder builder, String beanName) { 131 132 builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 133 parserContext.getRegistry().registerBeanDefinition(beanName, builder.getBeanDefinition()); 134 BeanDefinitionHolder holder = new BeanDefinitionHolder(builder.getBeanDefinition(), beanName); 135 parserContext.registerComponent(new BeanComponentDefinition(holder)); 136 } 137 138}