com.tencent.trpc.spring.context.AnnotationInjectedBeanPostProcessor Maven / Gradle / Ivy
/*
* Tencent is pleased to support the open source community by making tRPC available.
*
* Copyright (C) 2023 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* If you have downloaded a copy of the tRPC source code from Tencent,
* please note that tRPC source code is licensed under the Apache 2.0 License,
* A copy of the Apache 2.0 License can be found in the LICENSE file.
*/
package com.tencent.trpc.spring.context;
import static com.tencent.trpc.spring.util.AnnotationUtils.getMergedAttributes;
import com.tencent.trpc.core.logger.Logger;
import com.tencent.trpc.core.logger.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Stream;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* An {@link BeanPostProcessor} implementation that perform annotation-driven injections.
*/
public abstract class AnnotationInjectedBeanPostProcessor implements InstantiationAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware, BeanClassLoaderAware,
EnvironmentAware, DisposableBean {
private static final Logger logger = LoggerFactory.getLogger(AnnotationInjectedBeanPostProcessor.class);
private static final int CACHE_SIZE = 32;
private final Class extends Annotation>[] annotationTypes;
/**
* Cache for injected beans
*/
private final ConcurrentMap injectedObjectsCache = new ConcurrentHashMap<>(CACHE_SIZE);
/**
* Cache for {@link InjectionMetadata}
*/
private final ConcurrentMap injectionMetadataCache = new ConcurrentHashMap<>(CACHE_SIZE);
private final Object lock = new Object();
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader classLoader;
/**
* AnnotationInjectedBeanPostProcessor Constructor
*
* @param annotationTypes annotation types that requires processing
*/
@SafeVarargs
public AnnotationInjectedBeanPostProcessor(Class extends Annotation>... annotationTypes) {
Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
this.annotationTypes = annotationTypes;
}
/**
* Implements {@link InstantiationAwareBeanPostProcessor#postProcessProperties(PropertyValues, Object, String)}
* to perform bean injection.
*
* @param pvs the property values that the factory is about to apply (never {@code null})
* @param bean the bean instance created, but whose properties have not yet been set
* @param beanName the name of the bean
* @return the actual property values to apply to the given bean
* @throws BeansException in case of errors
*/
@Override
public PropertyValues postProcessProperties(@NonNull PropertyValues pvs, Object bean, @NonNull String beanName)
throws BeansException {
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationTypes()[0].getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
/**
* Post-process the given merged bean definition for the specified bean.
*
* @param beanDefinition the merged bean definition for the bean
* @param beanType the actual type of the managed bean instance
* @param beanName the name of the bean
*/
@Override
public void postProcessMergedBeanDefinition(@NonNull RootBeanDefinition beanDefinition,
@NonNull Class> beanType,
@NonNull String beanName) {
InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
/**
* shutdown hook for AnnotationInjectedBeanPostProcessor
*
* @throws Exception in case of shutdown errors
*/
@Override
public void destroy() throws Exception {
for (Object object : injectedObjectsCache.values()) {
if (logger.isInfoEnabled()) {
logger.info(object + " was destroying!");
}
if (object instanceof DisposableBean) {
((DisposableBean) object).destroy();
}
}
injectionMetadataCache.clear();
injectedObjectsCache.clear();
logger.info("{} was destroying!", getClass());
}
/**
* Get the order value of this object.
* Higher values are interpreted as lower priority. As a consequence,
* the object with the lowest value has the highest priority (somewhat analogous to Servlet {@code load-on-startup}
* values).
* Same order values will result in arbitrary sort positions for the
* affected objects.
*
* @return the order value
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
@Override
public int getOrder() {
// Make sure higher priority than {@link AutowiredAnnotationBeanPostProcessor}
return Ordered.LOWEST_PRECEDENCE - 3;
}
@Override
public void setBeanClassLoader(@NonNull ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setEnvironment(@NonNull Environment environment) {
this.environment = environment;
}
@Override
public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
"AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory");
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
protected Environment getEnvironment() {
return environment;
}
protected ClassLoader getClassLoader() {
return classLoader;
}
protected ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
* Gets all injected beans.
*
* @return non-null {@link Collection}
*/
protected Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy