使用BeanDefinition来构建Spring Bean并注入Spring上下文中

发布时间:2023年12月26日

在做中间件产品的时候,为了给业务方一个好用的客户端,我们一般会提供一个自定义的xxx-spring-boot-starter,那么我们就可能涉及到将自己的客户端中的某个类初始化并注入到Spring上下文中去。为了更标准化去初始化这个类,让Spring来管理我们这个对象的生命周期,那么我们经常会使用BeanDefinition来定义并通过自定义的xxxFactoryBean来真正初始化我们的对象。

先看下使用示例:

private void resolveRegistryClientBeanDefinition(BeanDefinitionRegistry registry, DispatchProperty dispatchProperty) {
        String beanName = Client.class.getName();
        ClientBeanDefinitionBuilder beanDefinitionBuilder = new ClientBeanDefinitionBuilder();
        beanDefinitionBuilder.property(dispatchProperty);
        BeanDefinition beanDefinition = beanDefinitionBuilder.build();
        if (!context.containsBean(beanName)) {
            registry.registerBeanDefinition(beanName, beanDefinition);
            LOGGER.info("NBP-CLIENT-STARTER", "registered beanDefinition of {} in spring context.", beanName);
        } else {
            LOGGER.warn("NBP-CLIENT-STARTER", "beanDefinition of {} has already registered in spring context.", beanName);
        }
    }

以上,我们使用ClientBeanDefinitionBuilder来定义如何构建ClientFactoryBean,然后通过ClientFactoryBean来创建Client对象,并通过registry.registerBeanDefinition(beanName, beanDefinition); 来将其注入到Spring上下文中去。

我们再来看下ClientBeanDefinitionBuilder和ClientFactoryBean里面是如何实现的。

ClientBeanDefinitionBuilder

package com.xxx.arch.mw.nbp.client.spring;

import com.xxx.arch.mw.nbp.client.configuration.DispatchProperty;
import com.xxx.arch.mw.nbp.client.constant.ClientConstants;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;

/**
 * @created 2022-11-30 3:08 PM
 * @description:
 */
public class ClientBeanDefinitionBuilder {

    private DispatchProperty property;

    ClientBeanDefinitionBuilder() {
    }

    ClientBeanDefinitionBuilder property(DispatchProperty property) {
        this.property = property;
        return this;
    }

    BeanDefinition build() {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ClientFactoryBean.class);
        builder.addPropertyValue("property", this.property);
        builder.addPropertyReference("publisher", ClientConstants.NBP_PUBLISHER_IMPL_BEAN_NAME);
        builder.addPropertyReference("subscriber", ClientConstants.NBP_SUBSCRIBER_IMPL_BEAN_NAME);
        builder.addDependsOn(ClientConstants.NBP_PUBLISHER_IMPL_BEAN_NAME);
        builder.addDependsOn(ClientConstants.NBP_SUBSCRIBER_IMPL_BEAN_NAME);
        builder.setInitMethodName(ClientConstants.INIT_METHOD);

        return builder.getBeanDefinition();
    }

}

ClientFactoryBean

package com.xxx.arch.mw.nbp.client.spring;

import com.xxx.arch.mw.nbp.client.Client;
import com.xxx.arch.mw.nbp.client.DefaultClient;
import com.xxx.arch.mw.nbp.client.configuration.DispatchProperty;
import com.xxx.arch.mw.nbp.client.publish.Publisher;
import com.xxx.arch.mw.nbp.client.subscribe.Subscriber;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;

/**
 * @created 2022-11-30 3:32 PM
 * @description:
 */
public class ClientFactoryBean implements FactoryBean<Object>, EnvironmentAware, InitializingBean {
    private ConfigurableEnvironment environment;

    private DispatchProperty property;

    private Client client;

    private Publisher publisher;
    private Subscriber subscriber;

    public ClientFactoryBean() {
    }

    @Override
    public Object getObject() throws Exception {
        return client;
    }

    public void start() throws Exception {
        if (client == null) {
            client = new DefaultClient(this.property);
            if (publisher != null) {
                ((DefaultClient) client).setPublisher(publisher);
            }
            if (subscriber != null) {
                ((DefaultClient) client).setSubscriber(subscriber);
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    }

    @Override
    public Class<?> getObjectType() {
        return Client.class;
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }

    public DispatchProperty getProperty() {
        return property;
    }

    public void setProperty(DispatchProperty property) {
        this.property = property;
    }

    public Publisher getPublisher() {
        return publisher;
    }

    public void setPublisher(Publisher publisher) {
        this.publisher = publisher;
    }

    public Subscriber getSubscriber() {
        return subscriber;
    }

    public void setSubscriber(Subscriber subscriber) {
        this.subscriber = subscriber;
    }
}

我们看到Client内部还分别依赖了Publisher和Subscriber,此实现也类似,详见如下:

如何构建Publisher

 private void resolveRegistryPublisherImplBeanDefinition(ConfigurableListableBeanFactory beanFactory,
                                                            BeanDefinitionRegistry registry,
                                                            DispatchProperty dispatchProperty) {
        String beanName = ClientConstants.NBP_PUBLISHER_IMPL_BEAN_NAME;
        // 额外增加主子任务需要发布者订阅的模板
        PUBLISHER_TEMPLATE_SET.addAll(MAPREDUCE_PUBLISHER_TEMPLATE_SET);
        BeanDefinition beanDefinition = new PublisherBeanDefinitionBuilder()
                .property(dispatchProperty)
                .beanFactory(beanFactory)
                .templates(PUBLISHER_TEMPLATE_SET)
                .filters(CUSTOM_PUBLISH_FILTER_SET)
                .build();
        if (!context.containsBean(beanName)) {
            registry.registerBeanDefinition(beanName, beanDefinition);
            LOGGER.info("NBP-CLIENT-STARTER",
                    "registered beanDefinition of {} in spring context.", beanName);
        } else {
            LOGGER.warn("NBP-CLIENT-STARTER",
                    "beanDefinition of {} has already registered in spring context.", beanName);
        }
    }

PublisherBeanDefinitionBuilder

package com.xxx.arch.mw.nbp.client.spring;

import com.xxx.arch.mw.nbp.client.configuration.DispatchProperty;
import com.xxx.arch.mw.nbp.client.constant.ClientConstants;
import com.xxx.arch.mw.nbp.common.domain.Template;
import com.xxx.commons.data.domain.tuple.Pair;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @created 2022-11-30 3:08 PM
 * @description:
 */
public class PublisherBeanDefinitionBuilder {

    private DispatchProperty property;

    /**
     *  依赖的bean名称列表
     */
    private List<String> dependsOns = new ArrayList<>();

    /**
     * 发布的任务模板列表
     */
    private Set<Template> templates = new HashSet<>();
    /**
     *  发布者的自定义过滤器列表
     *  Pair格式: (filterBeanName, filterClass)
     */
    private Set<Pair<String, Class<?>>> filters = new HashSet<>();
    private ConfigurableListableBeanFactory beanFactory;

    PublisherBeanDefinitionBuilder() {
    }

    PublisherBeanDefinitionBuilder property(DispatchProperty property) {
        this.property = property;
        return this;
    }

    PublisherBeanDefinitionBuilder templates(Set<Template> templates) {
        if (templates != null) {
            this.templates = templates;
        }
        return this;
    }

    PublisherBeanDefinitionBuilder template(Template template) {
        if (template == null) {
            return this;
        }
        if (this.templates == null) {
            this.templates = new HashSet<>();
        }
        this.templates.add(template);
        return this;
    }

    PublisherBeanDefinitionBuilder filters(Set<Pair<String, Class<?>>> filters) {
        if (filters != null) {
            this.filters = filters;
        }
        return this;
    }

    PublisherBeanDefinitionBuilder beanFactory(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        return this;
    }

    PublisherBeanDefinitionBuilder filter(Pair<String, Class<?>> filter) {
        if (filter == null) {
            return this;
        }
        if (this.filters == null) {
            this.filters = new HashSet<>();
        }
        this.filters.add(filter);
        return this;
    }

    PublisherBeanDefinitionBuilder dependsOns(List<String> dependsOns) {
        if (dependsOns != null) {
            this.dependsOns = dependsOns;
        }
        return this;
    }

    PublisherBeanDefinitionBuilder dependsOn(String dependsOn) {
        if (dependsOn == null) {
            return this;
        }
        if (this.dependsOns != null) {
            this.dependsOns = new ArrayList<>();
        }
        this.dependsOns.add(dependsOn);
        return this;
    }

    BeanDefinition build() {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PublisherFactoryBean.class);
        builder.addPropertyValue("property", this.property);
        builder.addPropertyValue("templates", this.templates);
        builder.addPropertyValue("filters", this.filters);
        builder.addPropertyValue("beanFactory", this.beanFactory);
        builder.setInitMethodName(ClientConstants.INIT_METHOD);
        for (String dependsOn : dependsOns) {
            builder.addDependsOn(dependsOn);
        }

        return builder.getBeanDefinition();
    }

}

PublisherFactoryBean

package com.xxx.arch.mw.nbp.client.spring;

import com.xxx.arch.mw.nbp.client.PublisherImpl;
import com.xxx.arch.mw.nbp.client.configuration.DispatchProperty;
import com.xxx.arch.mw.nbp.client.publish.Publisher;
import com.xxx.arch.mw.nbp.common.domain.Template;
import com.xxx.arch.mw.nbp.common.extension.Filter;
import com.xxx.commons.data.domain.tuple.Pair;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * @created 2022-11-30 3:32 PM
 * @description:
 */
public class PublisherFactoryBean implements FactoryBean<Object>, EnvironmentAware, InitializingBean {
    private ConfigurableEnvironment environment;

    private DispatchProperty property;
    private Set<Template> templates = new HashSet<>();
    private Set<Pair<String, Class<?>>> filters = new HashSet<>();
    private ConfigurableListableBeanFactory beanFactory;
    private Publisher publisher;

    public PublisherFactoryBean() {
    }

    @Override
    public Object getObject() throws Exception {
        return publisher;
    }

    public void start() throws Exception {
        if (publisher == null) {
            publisher = new PublisherImpl(this.property);
            for (Template template : templates) {
                publisher.register(template.getTemplateCode());
            }
            for (Pair<String, Class<?>> filterPair : filters) {
                Object filter = filterPair.getRight().getAnnotation(Component.class) != null ?
                        beanFactory.getBean(filterPair.getLeft(), filterPair.getRight()) :
                        filterPair.getRight().getDeclaredConstructor().newInstance();
                publisher.addFilter((Filter) filter);
            }
        }
        publisher.start();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    }

    @Override
    public Class<?> getObjectType() {
        return PublisherImpl.class;
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }

    public DispatchProperty getProperty() {
        return property;
    }

    public void setProperty(DispatchProperty property) {
        this.property = property;
    }

    public Set<Template> getTemplates() {
        return templates;
    }

    public void setTemplates(Set<Template> templates) {
        this.templates = templates;
    }

    public Set<Pair<String, Class<?>>> getFilters() {
        return filters;
    }

    public void setFilters(Set<Pair<String, Class<?>>> filters) {
        this.filters = filters;
    }

    public ConfigurableListableBeanFactory getBeanFactory() {
        return beanFactory;
    }

    public void setBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
}

如何构建Subscriber

private void resolveRegistrySubscriberImplBeanDefinition(ConfigurableListableBeanFactory beanFactory,
                                                             BeanDefinitionRegistry registry,
                                                             DispatchProperty dispatchProperty) {
        String beanName = ClientConstants.NBP_SUBSCRIBER_IMPL_BEAN_NAME;

        BeanDefinition beanDefinition = new SubscriberBeanDefinitionBuilder()
                .beanFactory(beanFactory)
                .property(dispatchProperty)
                .filters(CUSTOM_EXECUTE_FILTER_SET)
                .listeners(DISPATCH_LISTENER_MAP)
                .build();
        if (!context.containsBean(beanName)) {
            registry.registerBeanDefinition(beanName, beanDefinition);
            LOGGER.info("NBP-CLIENT-STARTER", "registered beanDefinition of {} in spring context.", beanName);
        } else {
            LOGGER.warn("NBP-CLIENT-STARTER", "beanDefinition of {} has already registered in spring context.", beanName);
        }
    }

SubscriberBeanDefinitionBuilder

package com.xxx.arch.mw.nbp.client.spring;

import com.xxx.arch.mw.nbp.client.configuration.DispatchProperty;
import com.xxx.arch.mw.nbp.client.constant.ClientConstants;
import com.xxx.arch.mw.nbp.client.remoting.Discover;
import com.xxx.commons.data.domain.tuple.Pair;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @created 2022-11-30 3:08 PM
 * @description:
 */
public class SubscriberBeanDefinitionBuilder {

    private DispatchProperty property;

    /**
     * 执行者的自定义过滤器列表
     * Pair格式: (filterBeanName, filterClass)
     */
    private Set<Pair<String, Class<?>>> filters = new HashSet<>();

    /**
     * 监听器列表
     * Map格式: (templateCode, (listenerBeanName, listenerClass))
     */
    private Map<String, Pair<String, Class<?>>> listeners = new HashMap<>();
    private ConfigurableListableBeanFactory beanFactory;

    SubscriberBeanDefinitionBuilder() {
    }

    SubscriberBeanDefinitionBuilder property(DispatchProperty property) {
        this.property = property;
        return this;
    }

    SubscriberBeanDefinitionBuilder filters(Set<Pair<String, Class<?>>> filters) {
        if (filters != null) {
            this.filters = filters;
        }
        return this;
    }

    SubscriberBeanDefinitionBuilder filter(Pair<String, Class<?>> filter) {
        if (filter == null) {
            return this;
        }
        if (this.filters == null) {
            this.filters = new HashSet<>();
        }
        this.filters.add(filter);
        return this;
    }

    SubscriberBeanDefinitionBuilder listeners(Map<String, Pair<String, Class<?>>> listeners) {
        if (listeners != null) {
            this.listeners = listeners;
        }
        return this;
    }

    SubscriberBeanDefinitionBuilder listener(String templateCode, Pair<String, Class<?>> listener) {
        if (templateCode == null) {
            return this;
        }
        if (listener == null) {
            return this;
        }
        if (this.listeners == null) {
            this.listeners = new HashMap<>();
        }
        this.listeners.put(templateCode, listener);
        return this;
    }

    SubscriberBeanDefinitionBuilder beanFactory(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        return this;
    }

    BeanDefinition build() {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SubscriberFactoryBean.class);
        builder.addPropertyValue("property", this.property);
        builder.addPropertyValue("filters", this.filters);
        builder.addPropertyValue("beanFactory", this.beanFactory);
        builder.addPropertyValue("listeners", this.listeners);
        builder.addPropertyReference("publisher", ClientConstants.NBP_PUBLISHER_IMPL_BEAN_NAME);
        builder.addDependsOn(ClientConstants.NBP_PUBLISHER_IMPL_BEAN_NAME);

        for (Pair<String, Class<?>> filterPair : this.filters) {
            if (filterPair.getRight().getAnnotation(Component.class) == null) {
                continue;
            }
            builder.addDependsOn(filterPair.getLeft());
        }
        for (Map.Entry<String, Pair<String, Class<?>>> entry : this.listeners.entrySet()) {
            if (Discover.IGNORED_TEMPLATE_CODE.equals(entry.getKey())) {
                continue;
            }
            builder.addDependsOn(entry.getValue().getLeft());
        }
        builder.setInitMethodName(ClientConstants.INIT_METHOD);

        return builder.getBeanDefinition();
    }

}

SubscriberFactoryBean

package com.xxx.arch.mw.nbp.client.spring;

import com.xxx.arch.mw.nbp.client.PublisherImpl;
import com.xxx.arch.mw.nbp.client.SubscriberImpl;
import com.xxx.arch.mw.nbp.client.configuration.DispatchProperty;
import com.xxx.arch.mw.nbp.client.publish.Publisher;
import com.xxx.arch.mw.nbp.client.remoting.Discover;
import com.xxx.arch.mw.nbp.client.subscribe.Subscriber;
import com.xxx.arch.mw.nbp.common.domain.Listener;
import com.xxx.arch.mw.nbp.common.extension.Filter;
import com.xxx.commons.data.domain.tuple.Pair;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @created 2022-11-30 3:32 PM
 * @description:
 */
public class SubscriberFactoryBean implements FactoryBean<Object>, EnvironmentAware, InitializingBean {
    private ConfigurableEnvironment environment;

    private DispatchProperty property;
    private Set<Pair<String, Class<?>>> filters = new HashSet<>();
    private Map<String, Pair<String, Class>> listeners = new HashMap<>();
    private ConfigurableListableBeanFactory beanFactory;
    private Subscriber subscriber;
    private Publisher publisher;


    public SubscriberFactoryBean() {
    }

    @Override
    public Object getObject() throws Exception {
        return subscriber;
    }

    public void start() throws Exception {
        if (subscriber == null) {
            subscriber = new SubscriberImpl(this.property, publisher);
            for (Pair<String, Class<?>> filterPair : filters) {
                Object filter = filterPair.getRight().getAnnotation(Component.class) != null ?
                        beanFactory.getBean(filterPair.getLeft(), filterPair.getRight()) :
                        filterPair.getRight().getDeclaredConstructor().newInstance();
                subscriber.addFilter((Filter) filter);
            }
            for (Map.Entry<String, Pair<String, Class>> entry : this.listeners.entrySet()) {
                if (Discover.IGNORED_TEMPLATE_CODE.equals(entry.getKey())) {
                    continue;
                }
                subscriber.subscribe(entry.getKey(), (Listener) beanFactory
                        .getBean(entry.getValue().getLeft(), entry.getValue().getRight()));
            }
        }
        subscriber.start();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    }

    @Override
    public Class<?> getObjectType() {
        return PublisherImpl.class;
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }

    public DispatchProperty getProperty() {
        return property;
    }

    public void setProperty(DispatchProperty property) {
        this.property = property;
    }

    public Publisher getPublisher() {
        return publisher;
    }

    public void setPublisher(Publisher publisher) {
        this.publisher = publisher;
    }

    public Set<Pair<String, Class<?>>> getFilters() {
        return filters;
    }

    public void setFilters(Set<Pair<String, Class<?>>> filters) {
        this.filters = filters;
    }

    public Map<String, Pair<String, Class>> getListeners() {
        return listeners;
    }

    public void setListeners(Map<String, Pair<String, Class>> listeners) {
        this.listeners = listeners;
    }

    public ConfigurableListableBeanFactory getBeanFactory() {
        return beanFactory;
    }

    public void setBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }
}

文章来源:https://blog.csdn.net/shallowgrave/article/details/135220978
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。