
com.alicp.jetcache.anno.field.CreateCacheAnnotationBeanPostProcessor Maven / Gradle / Ivy
The newest version!
package com.alicp.jetcache.anno.field;
import com.alicp.jetcache.anno.CreateCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created on 2016/12/9.
*
* @author huangli
* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
*/
@SuppressWarnings("AliMissingOverrideAnnotation")
@Component // necessary when spring boot version <= 1.2.X
public class CreateCacheAnnotationBeanPostProcessor extends AutowiredAnnotationBeanPostProcessor {
private static Logger logger = LoggerFactory.getLogger(CreateCacheAnnotationBeanPostProcessor.class);
private ConfigurableListableBeanFactory beanFactory;
private final Map injectionMetadataCache = new ConcurrentHashMap();
private final ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
}
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
// removed in spring 6
//@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
return postProcessProperties(pvs, bean, beanName);
}
//@Override
//since 5.1
@SuppressWarnings("AliMissingOverrideAnnotation")
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
reentrantLock.lock();
try{
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
clear(metadata, pvs);
}
try {
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
"] for autowiring metadata: could not find class that it depends on", err);
}
}
}finally {
reentrantLock.unlock();
}
}
return metadata;
}
private volatile boolean clearInited = false;
private Method cleanMethod;
/**
* clear method not found in Spring 4.0.
* @param obj
* @param param
*/
private void clear(InjectionMetadata obj, PropertyValues param) {
if(!clearInited){
try {
cleanMethod = InjectionMetadata.class.getMethod("clear", PropertyValues.class);
} catch (NoSuchMethodException e) {
}
clearInited = true;
}
if (cleanMethod != null) {
try {
cleanMethod.invoke(obj, param);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
}
private InjectionMetadata buildAutowiringMetadata(final Class> clazz) {
LinkedList elements = new LinkedList();
Class> targetClass = clazz;
do {
final LinkedList currElements =
new LinkedList();
doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
CreateCache ann = field.getAnnotation(CreateCache.class);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
currElements.add(new AutowiredFieldElement(field, ann));
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
private void doWithLocalFields(Class clazz, ReflectionUtils.FieldCallback fieldCallback) {
Field fs[] = clazz.getDeclaredFields();
for (Field field : fs) {
try {
fieldCallback.doWith(field);
} catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
}
}
}
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
private Field field;
private CreateCache ann;
public AutowiredFieldElement(Field field, CreateCache ann) {
super(field, null);
this.field = field;
this.ann = ann;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
beanFactory.registerDependentBean(beanName, "globalCacheConfig");
CreateCacheWrapper wrapper = new CreateCacheWrapper(beanFactory, ann, field);
field.setAccessible(true);
field.set(bean, wrapper.getCache());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy