001/* 002 * Copyright 2012-2013 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 * http://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.boot.context.config; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.List; 022 023import org.springframework.beans.BeanUtils; 024import org.springframework.context.ApplicationContextException; 025import org.springframework.context.ApplicationContextInitializer; 026import org.springframework.context.ConfigurableApplicationContext; 027import org.springframework.core.GenericTypeResolver; 028import org.springframework.core.Ordered; 029import org.springframework.core.annotation.AnnotationAwareOrderComparator; 030import org.springframework.core.env.ConfigurableEnvironment; 031import org.springframework.util.Assert; 032import org.springframework.util.ClassUtils; 033import org.springframework.util.StringUtils; 034 035/** 036 * {@link ApplicationContextInitializer} that delegates to other initializers that are 037 * specified under a {@literal context.initializer.classes} environment property. 038 * 039 * @author Dave Syer 040 * @author Phillip Webb 041 */ 042public class DelegatingApplicationContextInitializer implements 043 ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered { 044 045 // NOTE: Similar to org.springframework.web.context.ContextLoader 046 047 private static final String PROPERTY_NAME = "context.initializer.classes"; 048 049 private int order = 0; 050 051 @Override 052 public void initialize(ConfigurableApplicationContext context) { 053 ConfigurableEnvironment environment = context.getEnvironment(); 054 List<Class<?>> initializerClasses = getInitializerClasses(environment); 055 if (!initializerClasses.isEmpty()) { 056 applyInitializerClasses(context, initializerClasses); 057 } 058 } 059 060 private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) { 061 String classNames = env.getProperty(PROPERTY_NAME); 062 List<Class<?>> classes = new ArrayList<Class<?>>(); 063 if (StringUtils.hasLength(classNames)) { 064 for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) { 065 classes.add(getInitializerClass(className)); 066 } 067 } 068 return classes; 069 } 070 071 private Class<?> getInitializerClass(String className) throws LinkageError { 072 try { 073 Class<?> initializerClass = ClassUtils.forName(className, 074 ClassUtils.getDefaultClassLoader()); 075 Assert.isAssignable(ApplicationContextInitializer.class, initializerClass); 076 return initializerClass; 077 } 078 catch (ClassNotFoundException ex) { 079 throw new ApplicationContextException( 080 "Failed to load context initializer class [" + className + "]", ex); 081 } 082 } 083 084 private void applyInitializerClasses(ConfigurableApplicationContext context, 085 List<Class<?>> initializerClasses) { 086 Class<?> contextClass = context.getClass(); 087 List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>(); 088 for (Class<?> initializerClass : initializerClasses) { 089 initializers.add(instantiateInitializer(contextClass, initializerClass)); 090 } 091 applyInitializers(context, initializers); 092 } 093 094 private ApplicationContextInitializer<?> instantiateInitializer(Class<?> contextClass, 095 Class<?> initializerClass) { 096 Class<?> requireContextClass = GenericTypeResolver.resolveTypeArgument( 097 initializerClass, ApplicationContextInitializer.class); 098 Assert.isAssignable(requireContextClass, contextClass, 099 String.format( 100 "Could not add context initializer [%s]" 101 + " as its generic parameter [%s] is not assignable " 102 + "from the type of application context used by this " 103 + "context loader [%s]: ", 104 initializerClass.getName(), requireContextClass.getName(), 105 contextClass.getName())); 106 return (ApplicationContextInitializer<?>) BeanUtils 107 .instantiateClass(initializerClass); 108 } 109 110 @SuppressWarnings({ "unchecked", "rawtypes" }) 111 private void applyInitializers(ConfigurableApplicationContext context, 112 List<ApplicationContextInitializer<?>> initializers) { 113 Collections.sort(initializers, new AnnotationAwareOrderComparator()); 114 for (ApplicationContextInitializer initializer : initializers) { 115 initializer.initialize(context); 116 } 117 } 118 119 public void setOrder(int order) { 120 this.order = order; 121 } 122 123 @Override 124 public int getOrder() { 125 return this.order; 126 } 127 128}