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

news2024/11/25 9:47:08

  • 一、引入依赖
  • 二、定义一个注解
  • 三、创建一个FactoryBean
  • 四、创建一个BeanPostProcessor
    • 4.1 其他关联类
      • AnnotationUtils
      • ServiceBeanNameBuilder
  • 五、注入InstantiationAwareBeanPostProcessor到IoC中
    • 5.1 实现ImportBeanDefinitionRegistrar接口
    • 5.2 通过@Import注入
  • 六、使用
    • 6.1 打jar包
    • 6.2 引用jar
    • 6.3 调用
    • 6.4 注入是否为单例测试

一、引入依赖

<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 注入是否为单例测试

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1952957.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【proteus经典项目实战】51单片机用计数器中断实现100以内的按键计数并播放音乐

一、简介 一个基于8051微控制器的计数器系统&#xff0c;该系统能够通过按键输入递增计数&#xff0c;并且能够在达到100时归零。该系统将使用计数器中断和外部中断来实现其功能。 51单片机因其简单易用和成本效益高&#xff0c;成为电子爱好者和学生的首选平台。通过编程单片…

猫头虎分享 || 最全Python的Scapy库基础知识点汇总

&#x1f431;‍&#x1f464; 猫头虎分享 || Python的Scapy库基础知识点汇总 摘要 Scapy 是一个强大的Python库&#xff0c;用于网络数据包的生成、解析和操作。通过Scapy&#xff0c;开发者可以轻松地创建自定义数据包&#xff0c;捕获网络流量&#xff0c;并执行网络扫描。…

算法日记day 22

一、二叉搜索树中的插入操作 题目&#xff1a; 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 &#xff0c;新值和原始二叉搜索树中的任意节点值都不同。…

Python学习笔记46:游戏篇之外星人入侵(七)

前言 到目前为止&#xff0c;我们已经完成了游戏窗口的创建&#xff0c;飞船的加载&#xff0c;飞船的移动&#xff0c;发射子弹等功能。很高兴的说一声&#xff0c;基础的游戏功能已经完成一半了&#xff0c;再过几天我们就可以尝试驾驶 飞船击毁外星人了。当然&#xff0c;计…

【优秀python web系统毕设】基于python的全国招聘数据分析可视化系统,包括随机森林算法

1.1 研究背景 自1997年互联网开始在国内的招聘行业发展至今已有二十几年的历史&#xff0c;互联网招聘进入了蓬勃发展的“黄金时代”。根据智研咨询发布的《2023年中国互联网招聘行业发展现状》报告显示&#xff0c;截至2023年5月&#xff0c;中国互联网招聘平台中&#xff0c…

数据结构(Java):反射枚举Lambda表达式

目录 1、反射 1.1 反射的定义 1.2 反射机制的原理 1.3 反射相关类 1.4 Class类 1.4.1 相关方法 1.4.1.1 常用获得类相关的方法 ​编辑 1.4.1.2 常用获得类中属性相关的方法 1.4.1.3 获得类中构造器相关的方法 1.4.1.4 获得类中方法相关的方法 1.4.2 获取Class对象 1.…

DeFi革命:揭秘去中心化金融的核心技术与实操指南

目录 DeFi&#xff08;去中心化金融&#xff09;综述 基本特点 第一&#xff0c;DeFi 是无许可的金融 第二&#xff0c;DeFi 是无门槛的金融 第三&#xff0c;DeFi 是无人驾驶的金融 典型商业模式 闪电贷 MakerDAO 面临的挑战 DeFi技术要点 椭圆曲线签名 EIP-712:…

IS-LM模型的公式与应用解析

IS-LM模型的公式与应用解析 IS-LM模型的核心作用 IS-LM模型是宏观经济学中的一个重要工具&#xff0c;用于分析财政政策和货币政策对经济的影响。IS曲线代表商品市场均衡&#xff0c;LM曲线代表货币市场均衡。两条曲线的交点表示商品市场和货币市场同时达到均衡时的利率和收入…

MySQL笔记3——高级数据查询语句DQL

多表联查 多表联查可以通过连接运算实现&#xff0c;即将多张表通过主外键关系关联在一起进行查询。下图提供了多表联查 时用到的数据库表之间的关系。 等值查询和非等值查询 非等值查询&#xff1a;SELECT * FROM 表1&#xff0c;表2 等值查询&#xff1a;SELECT * FROM 表…

DDR3布线时候的经验总结

摆放BGA下面的滤波电容的时候注意不要让两个电容的电源和地对着头放&#xff0c;手工焊接时候容易短路 阻抗层必须是实心铜皮覆盖&#xff1a; &#xff08;3&#xff09;阻抗线一定要有阻抗参考层&#xff0c;一般以相邻的接地或电源层做参考层&#xff08;如顶层阻抗线&…

人工智能技术的分析与探讨

《人工智能技术的分析与探讨》 摘要&#xff1a; 本文深入探讨了人工智能技术在多个领域的应用&#xff0c;包括智能感知、智能语音、智能问答、智能机器人、智能制造、智能医疗等。详细阐述了这些技术在当前的应用现状和主要场景&#xff0c;展示了一些典型的应用案例&#…

放大电路总结

补充: 只有直流移动时才有Rbe动态等效电阻 从RsUs看进去,实际上不管接了什么东西都能够看成是一个Ri(输入电阻) Ri Ui/Ii Rb//Rbe Ui/Us Ri/(RiRs) Aus (Uo/Ui)*(Ui/Us) Au *Ri/(RiRs) 当前面是一个电压源的信号 我们就需要输入电阻更大 Ro--->输出电阻--->将…

学习C语言第十四天(指针练习)

1.第一题C 2.第二题C 3.第三题 00345 short类型解引用一次访问两个字节 4.第四题 6&#xff0c;12 5.第五题C 6.第六题 下面代码结果是0x11223300 7.第七题 int main() {int a 0;int n 0;scanf("%d %d",&a,&n);int i 0;int k 0;int sum 0;for (i 0;…

创维汽车滁州永通体验中心开业仪式暨超充车型区域上市会圆满成功

2024年7月20日&#xff0c;创维汽车滁州永通体验中心盛大开业&#xff0c;当日&#xff0c;创维汽车市场部经理周世鹏、安徽大区总监王大明等领导参加本次开业盛典&#xff0c;共同见证创维汽车滁州永通体验中心成功落地。 2021年&#xff0c;新能源乘用车高速发展&#xff0c;…

安装CUDA Cudnn Pytorch(GPU版本)步骤

一.先看自己的电脑NVIDIA 支持CUDA版本是多少&#xff1f; 1.打开NVIDIA控制面板 2.点击帮助---系统信息--组件 我的支持CUDA11.6 二.再看支持Pytorch的CUDA版本 三.打开CUDA官网 下载CUDA 11.6 下载好后&#xff0c;安装 选择 自定义 然后安装位置 &#xff08;先去F盘…

MySQL可重复读的隔离机制下是否彻底解决了幻读?

答案&#xff1a;没有彻底解决。 一、什么是幻读&#xff1f; 当同一个查询在不同时间产生不同的结果集时&#xff0c;事务中就会出现幻读问题。 幻读关注的是记录数量的不同。 不可重复读关注的是记录内容的不同。 二、快照读和当前读 InnoDB引擎的默认隔离级别是可重复读&…

vue3 命令运行窗口暴露网络地址,以及修改端口号

一般情况下这里的地址是隐藏的 这里加上 --host 可以暴露网络地址&#xff0c;再加上--port --8080 就可以将端口号修改为8080&#xff08;修改后边的数字就可以修改为你想要的端口号&#xff09;

pytorch-训练自定义数据集实战

目录 1. 步骤2. 加载数据2.1 继承Dataset2.1.1 生成name2label2.1.2 生成image path, label的文件2.1.3 __len__2.1.3 __getitem__2.1.4 数据切分为train、val、test 3. 建立模型4. 训练和测试4. 完整代码 1. 步骤 加载数据创建模型训练和测试迁移学习 2. 加载数据 这里以宝…

打造创新项目:从理念到市场的成功之路

打造创新项目&#xff1a;从理念到市场的成功之路 前言为何创新&#xff1f;如何创新&#xff1f;创新的意义 一、深入市场&#xff0c;洞察行业脉搏二、精准定位&#xff0c;锁定目标市场三、全面评估&#xff0c;确保项目可行性四、创新引领&#xff0c;打造独特卖点五、开放…

二叉树_堆(下卷)

前言 接前面两篇的内容&#xff0c;接着往下讲二叉树_堆相关的内容。 正文 那么&#xff0c;回到冒泡排序与堆排序的比较。 我们知道冒泡排序的时间复杂度为 O ( N 2 ) O(N^2) O(N2)&#xff0c;这个效率是不太好的。 那么&#xff0c;我们的堆排序的时间复杂度如何呢&…