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