package com.ctrip.framework.apollo.spring.annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.ReflectionUtils; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigChangeListener; import com.ctrip.framework.apollo.ConfigService; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.google.common.base.Preconditions; /** * Apollo Annotation Processor for Spring Application * * @author Jason Song(song_s@ctrip.com) */ public class ApolloAnnotationProcessor implements BeanPostProcessor, PriorityOrdered { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class clazz = bean.getClass(); processFields(bean, clazz.getDeclaredFields()); processMethods(bean, clazz.getDeclaredMethods()); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } private void processFields(Object bean, Field[] declaredFields) { for (Field field : declaredFields) { ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class); if (annotation == null) { continue; } Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()), "Invalid type: %s for field: %s, should be Config", field.getType(), field); String namespace = annotation.value(); Config config = ConfigService.getConfig(namespace); ReflectionUtils.makeAccessible(field); ReflectionUtils.setField(field, bean, config); } } private void processMethods(final Object bean, Method[] declaredMethods) { for (final Method method : declaredMethods) { ApolloConfigChangeListener annotation = AnnotationUtils.findAnnotation(method, ApolloConfigChangeListener.class); if (annotation == null) { continue; } Class<?>[] parameterTypes = method.getParameterTypes(); Preconditions.checkArgument(parameterTypes.length == 1, "Invalid number of parameters: %s for method: %s, should be 1", parameterTypes.length, method); Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]), "Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", parameterTypes[0], method); ReflectionUtils.makeAccessible(method); String[] namespaces = annotation.value(); for (String namespace : namespaces) { Config config = ConfigService.getConfig(namespace); config.addChangeListener(new ConfigChangeListener() { @Override public void onChange(ConfigChangeEvent changeEvent) { ReflectionUtils.invokeMethod(method, bean, changeEvent); } }); } } } @Override public int getOrder() { //make it as late as possible return Ordered.LOWEST_PRECEDENCE; } }