如何通过注解注入一个自定义的FactoryBean

一、引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.30</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.34</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.12.1</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

二、定义一个注解

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyReference {
}

三、创建一个FactoryBean

@Slf4j
public class MyFactoryBean<Service> implements FactoryBean<Service> {
    /**
     * 缓存
     */
    private final ConcurrentMap<String, Service> factoryBeanCache = new ConcurrentHashMap<>(32);


    private final Class<Service> serviceClass;

    public MyFactoryBean(Class<Service> serviceClass) {
        this.serviceClass = serviceClass;
    }

    public static <T> MyFactoryBean<T> of(Class<T> serviceClass) {
        return new MyFactoryBean<>(serviceClass);
    }

    @Override
    public Service getObject() throws Exception {
        log.info("create my factoryBean, serviceClass={}", serviceClass.getName());
        String key = getObjectType().getName();
        Service bean = this.factoryBeanCache.get(key);
        if (bean == null) {
            synchronized (this.factoryBeanCache) {
                bean = this.factoryBeanCache.get(key);
                if (bean == null) {
                    // 创建对象
                    bean = createObject();
                    this.factoryBeanCache.put(key, bean);
                }
            }
        }
        return bean;
    }

    private Service createObject() {
        return (Service) Proxy.newProxyInstance(this.getObjectType().getClassLoader(),
                new Class[]{serviceClass},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        log.info("myFactoryBean proxy before, method name={}", method.getName());
                        log.info("myFactoryBean proxy after");
                        return null;
                    }
                });
    }

    @Override
    public Class<?> getObjectType() {
        return this.serviceClass;
    }
}

四、创建一个BeanPostProcessor

@Slf4j
public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
        BeanFactoryAware, EnvironmentAware, DisposableBean, ApplicationListener, ApplicationContextAware {
    private static final int CACHE_SIZE = Integer.getInteger("", 32);

    /**
     * 需要扫描的注解集合
     */
    private final Class<? extends Annotation>[] annotationTypes;

    /**
     * 是否以Spring IoC容器中Bean优先
     * true:如果Spring IoC容器中存在,直接注入,多个注入第一个
     */
    private final Boolean isSpringIoCBeanPreferred;

    private final ConcurrentMap<String, AnnotatedInjectionMetadata> injectionMetadataCache =
            new ConcurrentHashMap<String, AnnotatedInjectionMetadata>(CACHE_SIZE);

    private final ConcurrentMap<String, MyFactoryBean<?>> injectedObjectsCache = new ConcurrentHashMap<>(CACHE_SIZE);

    private ConfigurableListableBeanFactory beanFactory;

    private Environment environment;

    private ApplicationContext applicationContext;
    private int order = Ordered.LOWEST_PRECEDENCE - 3;
    private boolean classValuesAsString = true;
    private boolean nestedAnnotationsAsMap = true;
    private boolean ignoreDefaultValue = true;
    private boolean tryMergedAnnotation = true;

    private static Map<String, TreeSet<String>> referencedBeanNameIdx = new HashMap<>();
    private final ConcurrentMap<String, MyFactoryBean<?>> factoryBeanCache =
            new ConcurrentHashMap<>(CACHE_SIZE);

    private final ConcurrentMap<InjectionMetadata.InjectedElement, MyFactoryBean<?>> injectedFieldMyFactoryBeanCache =
            new ConcurrentHashMap<>(CACHE_SIZE);

    private final ConcurrentMap<InjectionMetadata.InjectedElement, MyFactoryBean<?>> injectedMethodMyFactoryBeanCache =
            new ConcurrentHashMap<>(CACHE_SIZE);

    public ReferenceAnnotationBeanPostProcessor(Class<? extends Annotation>[] annotationTypes) {
        this(annotationTypes, true);
    }

    public ReferenceAnnotationBeanPostProcessor(Class<? extends Annotation>[] annotationTypes, Boolean isSpringIoCBeanPreferred) {
        Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
        Assert.notEmpty(annotationTypes, "The argument of isSpringIoCBeanPreferred must not empty");
        this.annotationTypes = annotationTypes;
        this.isSpringIoCBeanPreferred = isSpringIoCBeanPreferred;
    }


    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds,
                                                    Object bean, String beanName) throws BeanCreationException {
        // 查找注入元数据
        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 @" + bean.getClass().getSimpleName()
                    + " dependencies is failed", ex);
        }
        return pvs;
    }


    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        /**
         * 执行的时间节点是bean刚刚初始化完 但在属性填充之前;
         * spring会为每个beanDefinition依次调用实现了MergedBeanDefinitionPostProcessor接口的PostProcessor的改方法
         */
        if (beanType == null) {
            return;
        }
        // 查找注入元数据
        InjectionMetadata metadata = this.findInjectionMetadata(beanName, beanType, (PropertyValues) null);
        metadata.checkConfigMembers(beanDefinition);
    }

    /**
     * 查找注入元数据
     *
     * @param beanName
     * @param clazz
     * @param pvs
     * @return
     */
    private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
        String cacheKey = StringUtils.hasLength(beanName) ? beanName : clazz.getName();
        AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                // double check
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }

                    try {
                        // build
                        metadata = this.buildAnnotatedMetadata(clazz);
                        this.injectionMetadataCache.put(cacheKey, metadata);
                    } catch (NoClassDefFoundError e) {
                        throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() + "] for annotation metadata: could not find class that it depends on", e);
                    }
                }
            }
        }

        return metadata;
    }

    private AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
        // field
        Collection<AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
        // method
        Collection<AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
        return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
    }

    private List<AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {
        final List<AnnotatedMethodElement> elements = new LinkedList<AnnotatedMethodElement>();
        ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
            @Override
            public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                Method bridgedMethod = findBridgedMethod(method);
                if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }

                for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
                    AnnotationAttributes attributes = doGetAnnotationAttributes(bridgedMethod, annotationType);
                    if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
                        if (Modifier.isStatic(method.getModifiers())) {
                            if (log.isWarnEnabled()) {
                                log.warn("@" + annotationType.getName() + " annotation is not supported on static methods: " + method);
                            }
                            return;
                        }
                        if (method.getParameterTypes().length == 0) {
                            if (log.isWarnEnabled()) {
                                log.warn("@" + annotationType.getName() + " annotation should only be used on methods with parameters: " +
                                        method);
                            }
                        }
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
                        elements.add(new AnnotatedMethodElement(method, pd, attributes, applicationContext));
                    }
                }
            }
        });
        return elements;
    }

    protected AnnotationAttributes doGetAnnotationAttributes(AnnotatedElement annotatedElement,
                                                             Class<? extends Annotation> annotationType) {
        return AnnotationUtils.getAnnotationAttributes(annotatedElement, annotationType, this.environment,
                classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, tryMergedAnnotation);
    }

    protected final Class<? extends Annotation>[] getAnnotationTypes() {
        return annotationTypes;
    }

    private List<AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
        final List<AnnotatedFieldElement> elements = new LinkedList<AnnotatedFieldElement>();
        ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
            @Override
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
                    AnnotationAttributes attributes = doGetAnnotationAttributes(field, annotationType);
                    if (attributes != null) {
                        // 非静态方法
                        if (Modifier.isStatic(field.getModifiers())) {
                            if (log.isWarnEnabled()) {
                                log.warn("@" + annotationType.getName() + " is not supported on static fields: " + field);
                            }
                            return;
                        }
                        elements.add(new AnnotatedFieldElement(field, attributes, applicationContext));
                    }
                }
            }
        });

        return elements;

    }

    @Override
    public int getOrder() {
        return this.order;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
                "AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory");
        this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
    }

    @Override
    public void destroy() throws Exception {
        for (Object object : injectedObjectsCache.values()) {
            if (log.isInfoEnabled()) {
                log.info(object + " was destroying!");
            }

            if (object instanceof DisposableBean) {
                ((DisposableBean) object).destroy();
            }
        }

        this.injectedObjectsCache.clear();
        injectionMetadataCache.clear();
        injectedObjectsCache.clear();

        if (log.isInfoEnabled()) {
            log.info(getClass() + " was destroying success!");
        }

    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    protected MyFactoryBean<?> getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
                                                 InjectionMetadata.InjectedElement injectedElement) throws Exception {
        String cacheKey = this.buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
        MyFactoryBean<?> injectedObject = this.injectedObjectsCache.get(cacheKey);
        if (injectedObject == null) {
            synchronized (this.injectedObjectsCache) {
                // double check
                injectedObject = this.injectedObjectsCache.get(cacheKey);
                if (injectedObject == null) {
                    // 获取需要注入的Bean
                    injectedObject = this.doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
                    this.injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
                }
            }
        }
        return injectedObject;
    }

    protected MyFactoryBean<?> doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
                                                 InjectionMetadata.InjectedElement injectedElement) throws Exception {
        log.info("doGetInjectedBean bean={}, beanName={}", bean.getClass().getName(), beanName);
        // String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
        /**
         * The name of bean that is declared by {@link Reference @MyReference} annotation injection
         */
        String factoryBeanName = getMyFactoryBeanName(attributes, injectedType);

        referencedBeanNameIdx.computeIfAbsent(factoryBeanName, k -> new TreeSet<String>()).add(factoryBeanName);

        MyFactoryBean<?> factoryBean = buildMyFactoryBeanIfAbsent(factoryBeanName, attributes, injectedType);

        if (!isSpringIoCBeanPreferred) {
            // 注入 Bean 到spring IoC 中
            registerMyFactoryBean(factoryBean, factoryBeanName);
        }

        // 缓存
        cacheInjectedReferenceBean(factoryBean, injectedElement);

        // 执行初始化后应用Bean后处理器
        return (MyFactoryBean<?>) getBeanFactory().applyBeanPostProcessorsAfterInitialization(factoryBean, factoryBeanName);
    }

    private void cacheInjectedReferenceBean(MyFactoryBean<?> factoryBean,
                                            InjectionMetadata.InjectedElement injectedElement) {
        if (injectedElement.getMember() instanceof Field) {
            injectedFieldMyFactoryBeanCache.put(injectedElement, factoryBean);
        } else if (injectedElement.getMember() instanceof Method) {
            injectedMethodMyFactoryBeanCache.put(injectedElement, factoryBean);
        }
    }

    private void registerMyFactoryBean(MyFactoryBean<?> factoryBean, String beanName) {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsBean(beanName)) {
            Object bean = beanFactory.getBean(beanName);
            if (!Objects.equals(bean.getClass().getName(), factoryBean.getObjectType().getName())) {
                throw new RuntimeException("bean name '" + beanName + "' is exists in the container");
            }
        } else {
            beanFactory.registerSingleton(beanName, factoryBean);
        }
    }

    protected ConfigurableListableBeanFactory getBeanFactory() {
        return beanFactory;
    }

    private MyFactoryBean<?> buildMyFactoryBeanIfAbsent(String referenceBeanName, AnnotationAttributes attributes,
                                                        Class<?> referencedType) throws Exception {
        MyFactoryBean<?> factoryBean = factoryBeanCache.get(referenceBeanName);
        if (factoryBean == null) {
            factoryBean = MyFactoryBean.of(referencedType);
            factoryBeanCache.putIfAbsent(referenceBeanName, factoryBean);
        }
        return factoryBeanCache.get(referenceBeanName);
    }

    private String getMyFactoryBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
        String beanName = AnnotationUtils.getAttribute(attributes, "id");
        if (!hasText(beanName)) {
            beanName = generateMyFactoryBeanName(attributes, interfaceClass);
        }
        return beanName;
    }

    private String generateMyFactoryBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
        StringBuilder beanNameBuilder = new StringBuilder("@MyReference");

        if (!attributes.isEmpty()) {
            beanNameBuilder.append('(');
            for (Map.Entry<String, Object> entry : attributes.entrySet()) {
                String value;
                if ("parameters".equals(entry.getKey())) {
                    ArrayList<String> pairs = getParameterPairs(entry);
                    value = convertAttribute(pairs.stream().sorted().toArray());
                } else {
                    value = convertAttribute(entry.getValue());
                }
                beanNameBuilder.append(entry.getKey())
                        .append('=')
                        .append(value)
                        .append(',');
            }
            // replace the latest "," to be ")"
            beanNameBuilder.setCharAt(beanNameBuilder.lastIndexOf(","), ')');
        }

        beanNameBuilder.append(" ").append(interfaceClass.getName());

        return beanNameBuilder.toString();
    }

    private String convertAttribute(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof Annotation) {
            AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes((Annotation) obj, true);
            for (Map.Entry<String, Object> entry : attributes.entrySet()) {
                entry.setValue(convertAttribute(entry.getValue()));
            }
            return String.valueOf(attributes);
        } else if (obj.getClass().isArray()) {
            Object[] array = ObjectUtils.toObjectArray(obj);
            String[] newArray = new String[array.length];
            for (int i = 0; i < array.length; i++) {
                newArray[i] = convertAttribute(array[i]);
            }
            return Arrays.toString(Arrays.stream(newArray).sorted().toArray());
        } else {
            return String.valueOf(obj);
        }
    }

    private ArrayList<String> getParameterPairs(Map.Entry<String, Object> entry) {
        String[] entryValues = (String[]) entry.getValue();
        ArrayList<String> pairs = new ArrayList<>();
        // parameters spec is {key1,value1,key2,value2}
        for (int i = 0; i < entryValues.length / 2 * 2; i = i + 2) {
            pairs.add(entryValues[i] + "=" + entryValues[i + 1]);
        }
        return pairs;
    }

    protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes, Object bean, String beanName,
                                                 Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) {
        return buildReferencedBeanName(attributes, injectedType) +
                "#source=" + (injectedElement.getMember()) +
                "#attributes=" + AnnotationUtils.getAttributes(attributes, getEnvironment());
    }

    private String buildReferencedBeanName(AnnotationAttributes attributes, Class<?> serviceInterfaceType) {
        ServiceBeanNameBuilder serviceBeanNameBuilder = create(attributes, serviceInterfaceType, getEnvironment());
        return serviceBeanNameBuilder.build();
    }

    public static ServiceBeanNameBuilder create(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
        return new ServiceBeanNameBuilder(attributes, defaultInterfaceClass, environment);
    }

    private static <T> Collection<T> combine(Collection<? extends T>... elements) {
        List<T> allElements = new ArrayList<T>();
        for (Collection<? extends T> e : elements) {
            allElements.addAll(e);
        }
        return allElements;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            referencedBeanNameIdx.entrySet().stream().filter(e -> e.getValue().size() > 1).forEach(e -> {
                String logPrefix = e.getKey() + " has " + e.getValue().size() + " reference instances, there are: ";
                log.warn(e.getValue().stream().collect(Collectors.joining(", ", logPrefix, "")));
            });
            referencedBeanNameIdx.clear();
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private class AnnotatedInjectionMetadata extends InjectionMetadata {
        private final Collection<AnnotatedFieldElement> fieldElements;
        private final Collection<AnnotatedMethodElement> methodElements;

        public AnnotatedInjectionMetadata(Class<?> targetClass, Collection<AnnotatedFieldElement> fieldElements, Collection<AnnotatedMethodElement> methodElements) {
            super(targetClass, ReferenceAnnotationBeanPostProcessor.combine(fieldElements, methodElements));
            this.fieldElements = fieldElements;
            this.methodElements = methodElements;
        }

        public Collection<AnnotatedFieldElement> getFieldElements() {
            return this.fieldElements;
        }

        public Collection<AnnotatedMethodElement> getMethodElements() {
            return this.methodElements;
        }
    }

    public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {
        private final Field field;
        private final AnnotationAttributes attributes;
        private volatile Object bean;
        private ApplicationContext applicationContext;

        protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes, ApplicationContext applicationContext) {
            super(field, (PropertyDescriptor) null);
            this.field = field;
            this.attributes = attributes;
            this.applicationContext = applicationContext;
        }

        @Override
        protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
            Class<?> injectedType = this.resolveInjectedType(bean, this.field);
            ReflectionUtils.makeAccessible(this.field);
            MyFactoryBean<?> injectedObject = getInjectedObject(this.attributes, bean, beanName, injectedType, this);
            String factoryBeanName = getMyFactoryBeanName(attributes, injectedType);
            // 注入
            this.field.set(bean, getFinallyInjectedBean(injectedObject, factoryBeanName));
        }

        private Class<?> resolveInjectedType(Object bean, Field field) {
            Type genericType = field.getGenericType();
            return genericType instanceof Class ? field.getType() : GenericTypeResolver.resolveTypeArgument(AopUtils.getTargetClass(bean), field.getDeclaringClass());
        }
    }

    private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement {
        private final Method method;
        private final AnnotationAttributes attributes;
        private volatile Object object;
        private ApplicationContext applicationContext;

        protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, AnnotationAttributes attributes, ApplicationContext applicationContext) {
            super(method, pd);
            this.method = method;
            this.attributes = attributes;
            this.applicationContext = applicationContext;
        }

        @Override
        protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
            Class<?> injectedType = this.pd.getPropertyType();
            // 获取需要注入的Bean
            MyFactoryBean<?> injectedObject = ReferenceAnnotationBeanPostProcessor.this.getInjectedObject(this.attributes, bean, beanName, injectedType, this);
            ReflectionUtils.makeAccessible(this.method);
            String factoryBeanName = getMyFactoryBeanName(attributes, injectedType);
            // 注入
            this.method.invoke(bean, getFinallyInjectedBean(injectedObject, factoryBeanName));
        }
    }

    /**
     * 获取最终需要注入的Bean
     *
     * @param factoryBean
     * @param beanName
     * @return
     * @throws Exception
     */
    private Object getFinallyInjectedBean(MyFactoryBean<?> factoryBean, String beanName) throws Exception {
        if (!isSpringIoCBeanPreferred) {
            return factoryBean.getObject();
        }
        Object injected = null;
        String[] beanNames = this.applicationContext.getBeanNamesForType(factoryBean.getObjectType());
        if (beanNames.length >= 1) {
            // find first
            injected = this.applicationContext.getBean(beanNames[0]);
        }
        if (injected == null) {
            injected = factoryBean.getObject();
            // 注入到spring Ioc容器中
            registerMyFactoryBean(factoryBean, beanName);
        }
        return injected;
    }

    public Environment getEnvironment() {
        return this.environment;
    }
}

4.1 其他关联类

AnnotationUtils

public class AnnotationUtils {
    public static final String ANNOTATED_ELEMENT_UTILS_CLASS_NAME = "org.springframework.core.annotation.AnnotatedElementUtils";

    public static <T> T getAttribute(Map<String, Object> attributes, String attributeName) {
        return getAttribute(attributes, attributeName, false);
    }

    public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, boolean required) {
        T value = getAttribute(attributes, attributeName, null);
        if (required && value == null) {
            throw new IllegalStateException("The attribute['" + attributeName + "] is required!");
        }
        return value;
    }

    public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, T defaultValue) {
        T value = (T) attributes.get(attributeName);
        return value == null ? defaultValue : value;
    }

    public static String resolveInterfaceName(AnnotationAttributes attributes, Class<?> defaultInterfaceClass) {
        Boolean generic = getAttribute(attributes, "generic");
        if (generic != null && generic) {
            // it's a generic reference
            String interfaceClassName = getAttribute(attributes, "interfaceName");
            Assert.hasText(interfaceClassName,
                    "@Reference interfaceName() must be present when reference a generic service!");
            return interfaceClassName;
        }
        return resolveServiceInterfaceClass(attributes, defaultInterfaceClass).getName();
    }

    public static Class<?> resolveServiceInterfaceClass(AnnotationAttributes attributes, Class<?> defaultInterfaceClass)
            throws IllegalArgumentException {
        ClassLoader classLoader = defaultInterfaceClass != null ? defaultInterfaceClass.getClassLoader() : Thread.currentThread().getContextClassLoader();
        Class<?> interfaceClass = getAttribute(attributes, "interfaceClass");

        if (void.class.equals(interfaceClass)) { // default or set void.class for purpose.

            interfaceClass = null;

            String interfaceClassName = getAttribute(attributes, "interfaceName");

            if (hasText(interfaceClassName)) {
                if (ClassUtils.isPresent(interfaceClassName, classLoader)) {
                    interfaceClass = resolveClassName(interfaceClassName, classLoader);
                }
            }

        }

        if (interfaceClass == null && defaultInterfaceClass != null) {
            // Find all interfaces from the annotated class
            Class<?>[] allInterfaces = getAllInterfacesForClass(defaultInterfaceClass);

            if (allInterfaces.length > 0) {
                interfaceClass = allInterfaces[0];
            }
        }

        return interfaceClass == null ? defaultInterfaceClass : interfaceClass;
    }

    public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
                                                               Class<? extends Annotation> annotationType,
                                                               PropertyResolver propertyResolver,
                                                               boolean classValuesAsString,
                                                               boolean nestedAnnotationsAsMap,
                                                               boolean ignoreDefaultValue,
                                                               boolean tryMergedAnnotation,
                                                               String... ignoreAttributeNames) {

        AnnotationAttributes attributes = null;

        if (tryMergedAnnotation) {
            attributes = tryGetMergedAnnotationAttributes(annotatedElement, annotationType, propertyResolver,
                    classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
        }

        if (attributes == null) {
            attributes = getAnnotationAttributes(annotatedElement, annotationType, propertyResolver,
                    classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
        }

        return attributes;
    }

    public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
                                                               Class<? extends Annotation> annotationType,
                                                               PropertyResolver propertyResolver,
                                                               boolean classValuesAsString,
                                                               boolean nestedAnnotationsAsMap,
                                                               boolean ignoreDefaultValue,
                                                               String... ignoreAttributeNames) {
        Annotation annotation = annotatedElement.getAnnotation(annotationType);
        return annotation == null ? null : getAnnotationAttributes(annotation, propertyResolver,
                classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
    }

    public static Annotation tryGetMergedAnnotation(AnnotatedElement annotatedElement,
                                                    Class<? extends Annotation> annotationType,
                                                    boolean classValuesAsString,
                                                    boolean nestedAnnotationsAsMap) {

        Annotation mergedAnnotation = null;

        ClassLoader classLoader = annotationType.getClassLoader();

        if (ClassUtils.isPresent(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader)) {
            Class<?> annotatedElementUtilsClass = resolveClassName(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader);
            // getMergedAnnotation method appears in the Spring Framework 4.2
            Method getMergedAnnotationMethod = findMethod(annotatedElementUtilsClass, "getMergedAnnotation",
                    AnnotatedElement.class, Class.class, boolean.class, boolean.class);
            if (getMergedAnnotationMethod != null) {
                mergedAnnotation = (Annotation) invokeMethod(getMergedAnnotationMethod, null,
                        annotatedElement, annotationType, classValuesAsString, nestedAnnotationsAsMap);
            }
        }

        return mergedAnnotation;
    }

    public static AnnotationAttributes tryGetMergedAnnotationAttributes(AnnotatedElement annotatedElement,
                                                                        Class<? extends Annotation> annotationType,
                                                                        PropertyResolver propertyResolver,
                                                                        boolean classValuesAsString,
                                                                        boolean nestedAnnotationsAsMap,
                                                                        boolean ignoreDefaultValue,
                                                                        String... ignoreAttributeNames) {
        Annotation annotation = tryGetMergedAnnotation(annotatedElement, annotationType, classValuesAsString, nestedAnnotationsAsMap);
        return annotation == null ? null : getAnnotationAttributes(annotation, propertyResolver,
                classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
    }

    public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean ignoreDefaultValue,
                                                               String... ignoreAttributeNames) {
        return getAnnotationAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames);
    }

    public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, PropertyResolver propertyResolver,
                                                               boolean ignoreDefaultValue, String... ignoreAttributeNames) {
        return getAnnotationAttributes(annotation, propertyResolver, false, false, ignoreDefaultValue, ignoreAttributeNames);
    }

    public static AnnotationAttributes getAnnotationAttributes(Annotation annotation,
                                                               PropertyResolver propertyResolver,
                                                               boolean classValuesAsString,
                                                               boolean nestedAnnotationsAsMap,
                                                               boolean ignoreDefaultValue,
                                                               String... ignoreAttributeNames) {
        return fromMap(getAttributes(annotation, propertyResolver, classValuesAsString, nestedAnnotationsAsMap,
                ignoreDefaultValue, ignoreAttributeNames));
    }

    public static Map<String, Object> getAttributes(Annotation annotation,
                                                    PropertyResolver propertyResolver,
                                                    boolean classValuesAsString,
                                                    boolean nestedAnnotationsAsMap,
                                                    boolean ignoreDefaultValue,
                                                    String... ignoreAttributeNames) {

        Map<String, Object> annotationAttributes = org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes(annotation, classValuesAsString, nestedAnnotationsAsMap);

        String[] actualIgnoreAttributeNames = ignoreAttributeNames;

        if (ignoreDefaultValue && !isEmpty(annotationAttributes)) {

            List<String> attributeNamesToIgnore = new LinkedList<String>(asList(ignoreAttributeNames));

            for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {
                String attributeName = annotationAttribute.getKey();
                Object attributeValue = annotationAttribute.getValue();
                if (nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) {
                    attributeNamesToIgnore.add(attributeName);
                }
            }
            // extends the ignored list
            actualIgnoreAttributeNames = attributeNamesToIgnore.toArray(new String[attributeNamesToIgnore.size()]);
        }

        return getAttributes(annotationAttributes, propertyResolver, actualIgnoreAttributeNames);
    }

    public static Map<String, Object> getAttributes(Map<String, Object> annotationAttributes,
                                                    PropertyResolver propertyResolver, String... ignoreAttributeNames) {
        Set<String> ignoreAttributeNamesSet = new HashSet<String>();
        if (ignoreAttributeNames != null && ignoreAttributeNames.length > 0) {
            for (String ignoreAttributeName : ignoreAttributeNames) {
                ignoreAttributeNamesSet.add(ignoreAttributeName);
            }
        }

        Map<String, Object> actualAttributes = new LinkedHashMap<String, Object>();

        for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {

            String attributeName = annotationAttribute.getKey();
            Object attributeValue = annotationAttribute.getValue();

            // ignore attribute name
            if (ignoreAttributeNamesSet.contains(attributeName)) {
                continue;
            }

            if (attributeValue instanceof String) {
                attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver);
            } else if (attributeValue instanceof String[]) {
                String[] values = (String[]) attributeValue;
                for (int i = 0; i < values.length; i++) {
                    values[i] = resolvePlaceholders(values[i], propertyResolver);
                }
                attributeValue = values;
            }
            actualAttributes.put(attributeName, attributeValue);
        }
        return actualAttributes;
    }

    private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) {
        String resolvedValue = attributeValue;
        if (propertyResolver != null) {
            resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue);
            resolvedValue = trimWhitespace(resolvedValue);
        }
        return resolvedValue;
    }
}

ServiceBeanNameBuilder

public class ServiceBeanNameBuilder {

    private static final String SEPARATOR = ":";

    // Required
    private final String interfaceClassName;

    private final Environment environment;

    // Optional
    private String version;

    private String group;

    private ServiceBeanNameBuilder(Class<?> interfaceClass, Environment environment) {
        this(interfaceClass.getName(), environment);
    }

    private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) {
        this.interfaceClassName = interfaceClassName;
        this.environment = environment;
    }

    public ServiceBeanNameBuilder(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
        this(AnnotationUtils.resolveInterfaceName(attributes, defaultInterfaceClass), environment);
        this.group(AnnotationUtils.getAttribute(attributes, "group"));
        this.version(AnnotationUtils.getAttribute(attributes, "version"));
    }

    public static ServiceBeanNameBuilder create(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
        return new ServiceBeanNameBuilder(attributes, defaultInterfaceClass, environment);
    }

    public static ServiceBeanNameBuilder create(Class<?> interfaceClass, Environment environment) {
        return new ServiceBeanNameBuilder(interfaceClass, environment);
    }

    private static void append(StringBuilder builder, String value) {
        if (StringUtils.hasText(value)) {
            builder.append(SEPARATOR).append(value);
        }
    }

    public ServiceBeanNameBuilder group(String group) {
        this.group = group;
        return this;
    }

    public ServiceBeanNameBuilder version(String version) {
        this.version = version;
        return this;
    }

    public String build() {
        StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
        // Required
        append(beanNameBuilder, interfaceClassName);
        // Optional
        append(beanNameBuilder, version);
        append(beanNameBuilder, group);
        // Build and remove last ":"
        String rawBeanName = beanNameBuilder.toString();
        // Resolve placeholders
        return environment.resolvePlaceholders(rawBeanName);
    }
}

五、注入InstantiationAwareBeanPostProcessor到IoC中

5.1 实现ImportBeanDefinitionRegistrar接口

public class RefImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
                                        BeanNameGenerator importBeanNameGenerator) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(ReferenceAnnotationBeanPostProcessor.class);
        ConstructorArgumentValues values = new ConstructorArgumentValues();
        // 添加需要扫描的注解
        values.addIndexedArgumentValue(0, new Class[]{MyReference.class});
        // isSpringIoCBeanPreferred:是否以Spring IoC容器中Bean优先
        values.addIndexedArgumentValue(1, true);
        beanDefinition.setConstructorArgumentValues(values);
        String beanName = importBeanNameGenerator.generateBeanName(beanDefinition, registry);
        registry.registerBeanDefinition(beanName, beanDefinition);
    }
}

5.2 通过@Import注入

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RefImportBeanDefinitionRegistrar.class})
public @interface EnableReference {
}

六、使用

6.1 打jar包

在这里插入图片描述

将上面代码打成一个jar

6.2 引用jar

<dependency>
    <groupId>com.tortoise</groupId>
    <artifactId>my-reference</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

6.3 调用

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e20037a5b60c4b66a6dcc47f606c86f0.png

6.4 注入是否为单例测试

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值