Spring 自定义注解实现静态注入(@StaticAutowired,@StaticValue)

简述

当我在工具类中使用static修饰我要自动注入的类的时候,发现使用的时候会报空指针,为了解决这个问题,让工具类更完美,为了简单性,易用性,最好和 @Autowired 和 @Value 使用方式一致,我自定义的注解是 @StaticAutowired,@StaticValue 分别对标上面两个注解,实现了 @Autowired 和 @Value 的所有功能,外加支持自动注入静态属性

报错原因

@Autowired 实现原理

AutoWired实现依赖于他自己的后置处理器AutowiredAnnotationBeanPostProcessor,它的集成图如下

@Autowired 的Bean 后置处理器自动注入Bean的处理在这里

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

这populateBean中方法开始进入处理属性值

点进去看具体方法

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata

找到罪魁祸首

@Value的实现原理

org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver#findValue

在这个方法中去对@Value处理

找到我们探寻的地方之后开始构建我们自己的注解

@StaticAutowired,@StaticValue(构建思路抄Spring的然后改)

构建注解@StaticValue

```

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD})

@Documented

public @interface StaticValue {

    /**

    * 注入静态属性值

    */

    String value();

}

构建@StaticValue解析类

主要学习了这个方法是如何处理的

```

public class ExContextAnnotationAutowireCandidateResolver extends ContextAnnotationAutowireCandidateResolver {

    private Class<? extends Annotation> valueAnnotationType = StaticValue.class;

    @Override

    protected Object findValue(Annotation[] annotationsToSearch) {

        // 父类 对 @Value 的 value 值解析出来

        Object value = super.findValue(annotationsToSearch);

        if(value!=null){

            return value;

        }

        //父类解析之后去看这个字段上时候有我们自己的注解,然后拿到这个注解再学习父类那样去解析

        if (annotationsToSearch.length > 0) {

            AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);

            if (attr != null) {

                return this.extractValue(attr);

            }

        }

        return null;

    }

}

构建注解@StaticAutowired

```

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD})

@Documented

public @interface StaticAutowired{

    /**

    * 是否必须有

    */

    boolean required() default true;

}

构建@StaticAutowired解析类

这块的话主要是对AutowiredAnnotationBeanPostProcessor的一个学习然后好些方法都是从里面拿,主要思路就是从入口方法开始先拿,然后看入口方法里需要啥我们再拿一个,最后再是去修改

```

@Component

public class StaticAutowiredAnnotationBeanPostProcessor  implements SmartInstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {

    protected final Log logger = LogFactory.getLog(this.getClass());

    /**

    * 支持的注解

    */

    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet(4);

    private String requiredParameterName = "required";

    private boolean requiredParameterValue = true;

    private final ExContextAnnotationAutowireCandidateResolver

            exContextAnnotationAutowireCandidateResolver = new ExContextAnnotationAutowireCandidateResolver();

    @Nullable

    private DefaultListableBeanFactory beanFactory;

    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap(256);

    public StaticAutowiredAnnotationBeanPostProcessor() {

        this.autowiredAnnotationTypes.add(StaticAutowired.class);

        this.autowiredAnnotationTypes.add(StaticValue.class);

    }

    @Override

    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {

        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);

        AutowireCandidateResolver autowireCandidateResolver = beanFactory.getAutowireCandidateResolver();

        // 为了 解析 @StaticValue 必须使用 自定义的 ExContextAnnotationAutowireCandidateResolver

        boolean isExContextAnnotationAutowireCandidateResolver = autowireCandidateResolver instanceof ExContextAnnotationAutowireCandidateResolver;

        try {

            if (!isExContextAnnotationAutowireCandidateResolver) {

                beanFactory.setAutowireCandidateResolver(exContextAnnotationAutowireCandidateResolver);

            }

            metadata.inject(bean, beanName, pvs);

        }

        catch (BeanCreationException ex) {

            throw ex;

        }

        catch (Throwable ex) {

            throw new BeanCreationException(beanName, "Injection of static autowired dependencies failed", ex);

        }finally {

            // 设置回原来的

            if (!isExContextAnnotationAutowireCandidateResolver) {

                beanFactory.setAutowireCandidateResolver(autowireCandidateResolver);

            }

        }

        return pvs;

    }

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {

        String cacheKey = StringUtils.hasLength(beanName) ? beanName : clazz.getName();

        InjectionMetadata metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);

        if (InjectionMetadata.needsRefresh(metadata, clazz)) {

            synchronized(this.injectionMetadataCache) {

                metadata = (InjectionMetadata)this.injectionMetadataCache.get(cacheKey);

                if (InjectionMetadata.needsRefresh(metadata, clazz)) {

                    if (metadata != null) {

                        metadata.clear(pvs);

                    }

                    metadata = this.buildAutowiringMetadata(clazz);

                    this.injectionMetadataCache.put(cacheKey, metadata);

                }

            }

        }

        return metadata;

    }

    private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {

        List<InjectionMetadata.InjectedElement> elements = new ArrayList();

        Class targetClass = clazz;

        do {

            List<InjectionMetadata.InjectedElement> currElements = new ArrayList();

            ReflectionUtils.doWithLocalFields(targetClass, (field) -> {

                AnnotationAttributes ann = this.findAutowiredAnnotation(field);

                // 这里改动

                if (ann != null) {

                    if (Modifier.isStatic(field.getModifiers())) {

                        if (logger.isInfoEnabled()) {

                            logger.info("StaticAutowired annotation is supported on static fields: " + field);

                        }

                    }

                    // 这里也有改动让其用我们自己的去处理

                    boolean required = this.determineRequiredStatus(ann);

                    currElements.add(new StaticAutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));

                }

            });

            elements.addAll(0, currElements);

            targetClass = targetClass.getSuperclass();

        } while(targetClass != null && targetClass != Object.class);

        return new InjectionMetadata(clazz, elements);

    }

    protected boolean determineRequiredStatus(AnnotationAttributes ann) {

        return !ann.containsKey(this.requiredParameterName) || this.requiredParameterValue == ann.getBoolean(this.requiredParameterName);

    }

    @Nullable

    private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {

        if (ao.getAnnotations().length > 0) {

            Iterator var2 = this.autowiredAnnotationTypes.iterator();

            while(var2.hasNext()) {

                Class<? extends Annotation> type = (Class)var2.next();

                AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);

                if (attributes != null) {

                    return attributes;

                }

            }

        }

        return null;

    }

    @Nullable

    private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {

        if (cachedArgument instanceof DependencyDescriptor) {

            DependencyDescriptor descriptor = (DependencyDescriptor)cachedArgument;

            Assert.state(this.beanFactory != null, "No BeanFactory available");

            return this.beanFactory.resolveDependency(descriptor, beanName, (Set)null, (TypeConverter)null);

        } else {

            return cachedArgument;

        }

    }

    private void registerDependentBeans(@Nullable String beanName, Set<String> autowiredBeanNames) {

        if (beanName != null) {

            Iterator var3 = autowiredBeanNames.iterator();

            while(var3.hasNext()) {

                String autowiredBeanName = (String)var3.next();

                if (this.beanFactory != null && this.beanFactory.containsBean(autowiredBeanName)) {

                    this.beanFactory.registerDependentBean(autowiredBeanName, beanName);

                }

                if (this.logger.isDebugEnabled()) {

                    this.logger.debug("Autowiring by type from bean name '" + beanName + "' to bean named '" + autowiredBeanName + "'");

                }

            }

        }

    }

    @Override

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

        if (!(beanFactory instanceof DefaultListableBeanFactory)) {

            throw new IllegalArgumentException("StaticAutowiredAnnotationBeanPostProcessor requires a DefaultListableBeanFactory: " + beanFactory);

        } else {

            this.beanFactory = (DefaultListableBeanFactory) beanFactory;

        }

    }

    @Override

    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {

        InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);

        metadata.checkConfigMembers(beanDefinition);

    }

    @Override

    public int getOrder() {

        return Ordered.LOWEST_PRECEDENCE - 2;

    }

    private static class ShortcutDependencyDescriptor extends DependencyDescriptor {

        private final String shortcut;

        private final Class<?> requiredType;

        public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {

            super(original);

            this.shortcut = shortcut;

            this.requiredType = requiredType;

        }

        @Override

        public Object resolveShortcut(BeanFactory beanFactory) {

            return beanFactory.getBean(this.shortcut, this.requiredType);

        }

    }

    private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {

        private final boolean required;

        private volatile boolean cached = false;

        @Nullable

        private volatile Object cachedFieldValue;

        public AutowiredFieldElement(Field field, boolean required) {

            super(field, (PropertyDescriptor)null);

            this.required = required;

        }

        @Override

        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

            Field field = (Field)this.member;

            // 把数组改成了的那个元素

            Object value;

            if (this.cached) {

                value = resolvedCachedArgument(beanName, this.cachedFieldValue);

            } else {

                DependencyDescriptor desc = new DependencyDescriptor(field, this.required);

                desc.setContainingClass(bean.getClass());

                Set<String> autowiredBeanNames = new LinkedHashSet(1);

                Assert.state(beanFactory != null, "No BeanFactory available");

                TypeConverter typeConverter = beanFactory.getTypeConverter();

                try {

                    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);

                } catch (BeansException var12) {

                    throw new UnsatisfiedDependencyException((String)null, beanName, new InjectionPoint(field), var12);

                }

                synchronized(this) {

                    if (!this.cached) {

                        if (value == null && !this.required) {

                            this.cachedFieldValue = null;

                        } else {

                            this.cachedFieldValue = desc;

                            registerDependentBeans(beanName, autowiredBeanNames);

                            if (autowiredBeanNames.size() == 1) {

                                String autowiredBeanName = (String)autowiredBeanNames.iterator().next();

                                if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {

                                    this.cachedFieldValue = new StaticAutowiredAnnotationBeanPostProcessor.ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());

                                }

                            }

                        }

                        this.cached = true;

                    }

                }

            }

            if (value != null) {

                ReflectionUtils.makeAccessible(field);

                field.set(bean, value);

            }

        }

    }

}

总结

从解析的入口方法开始,从AutowiredAnnotationBeanPostProcessor缺啥拿啥

buildAutowiringMetadata中去掉了对静态属性的直接退出

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容