Mehrere Routinen und Implementierungen zur Aufrechterhaltung der Skalierbarkeit in Java

In der täglichen Entwicklung fasst der Autor einige häufig verwendete kostengünstige und skalierbare Routinen zusammen und teilt sie. Jeder ist willkommen, sie zu diskutieren.

Vorwort

Die fünf Prinzipien von SOLID (einzeln, offen und geschlossen, innerer Ersatz, Schnittstellenisolation, Abhängigkeitsumkehr) und 23 Entwurfsmuster (gemeinsame Singletons, Builder, Dekorationen, Anpassungen, Agenten, Kombinationen, Vorlagen usw.) müssen Ihnen bekannt sein mit diesen. Diese Prinzipien und Entwurfsmuster können uns dabei helfen, beim Entwurf Entscheidungen zu treffen, um eine hohe Kohäsion und eine geringe Kopplung zu erreichen.

Wenn es um Design geht, fällt auf jeden Fall das Wort Architektur. Gängige Architekturbegriffe: Schichtarchitektur, hexagonale Architektur, SOA-Architektur, CQRS-Architektur, EDA-Architektur usw. Mein persönliches Verständnis von Architektur ist die Bestätigung von Grenzen und die Kombination von Elementen innerhalb der Grenzen. Tatsächlich muss ein Programmierer, solange er ein Programmierer ist, ein Architekt sein, aber ob er nun ein guter Architekt ist oder nicht so- guter Architekt; jeder ist ein Architekt Architekt, ich denke, mit diesem Satz gibt es kein Problem. Der Unterschied besteht darin, dass seine Erkenntnis die Grenzen bestimmt, die er bestätigen kann und wie er interne Elemente effizienter kombinieren kann; technische Architekten müssen sich auf Technologie konzentrieren, und Geschäftsarchitekten muss sich darauf konzentrieren Die Grenzen, die Geschäfts- und Produktarchitekten erkennen können, beschränken sich höchstwahrscheinlich auf die Produktdomäne. Die Architekten des ICBU-Architekturteams denken mehr über horizontale Geschäftsunterstützung nach. Das Obige ist mein persönliches Verständnis des Wortes Architektur. Heute werden wir nicht auf die spezifische Architektur eingehen, sondern auf einige Routinen. In der täglichen Entwicklung habe ich einige kostengünstige und skalierbare Routinen zusammengefasst, die ich normalerweise zum Teilen verwende. Komm raus und Jeder ist willkommen, darüber zu diskutieren.

Pipeline-basierte Routinen

Kernpunkt

  • Pipeline----Pipeline-Durchgang für Serienventile
  • Ventil (PipelineValue) – wird für jeden Knoten verwendet, um tatsächliche Geschäftsanforderungen zu verarbeiten
  • Pipeline-Kontext (PipelineContext) – wird für die Rotation von Daten im Pipeline-Kontext verwendet

Anwendbare Szene

  • Wenn Ihr Datenfluss viele gleichwertige logische Verarbeitungen durchlaufen muss, können Sie die Verwendung dieser Routine in Betracht ziehen, um die spätere Erweiterung zu erleichtern.

Code implementieren

  • Pipeline/StandardPipeline
package com.example.ownertest.dm.pipelline;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:46
 */
public interface Pipeline {

    /**
     * 执行
     *
     * @return
     */
    boolean invoke(PipelineContext pipelineContext);

    /**
     * 添加值
     *
     * @param pipelineValue
     * @return
     */
    boolean addValue(PipelineValue pipelineValue);

    /**
     * 移除值
     *
     * @param pipelineValue
     * @return
     */
    boolean removeValue(PipelineValue pipelineValue);
}




package com.example.ownertest.dm.pipelline;

import java.util.List;

import com.google.common.collect.Lists;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:46
 */
@Data
@Slf4j
public class StandardPipeline implements Pipeline {

    private List<PipelineValue> pipelineValueList = Lists.newArrayList();

    @Override
    public boolean invoke(PipelineContext pipelineContext) {
        boolean isResult = true;
        for (PipelineValue pipelineValue :
            pipelineValueList) {
            try {
                isResult = pipelineValue.execute(pipelineContext);
                if (!isResult) {
                    log.error("{},exec is wrong", pipelineValue.getClass().getSimpleName());
                }

            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }

        return isResult;
    }

    @Override
    public boolean addValue(PipelineValue pipelineValue) {
        if (pipelineValueList.contains(pipelineValue)) {
            return true;
        }

        return pipelineValueList.add(pipelineValue);
    }

    @Override
    public boolean removeValue(PipelineValue pipelineValue) {
        return pipelineValueList.remove(pipelineValue);
    }
}
  • PipelineContext/StandardPipelineContext
package com.example.ownertest.dm.pipelline;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:47
 */
public interface PipelineContext {

    String FOR_TEST = "forTest";

    /**
     * 设置
     *
     * @param contextKey
     * @param contextValue
     */
    void set(String contextKey, Object contextValue);

    /**
     * 获取值
     *
     * @param contextKey
     * @return
     */
    Object get(String contextKey);
}




package com.example.ownertest.dm.pipelline;

import java.util.Map;

import com.google.common.collect.Maps;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:47
 */
public class StandardPipelineContext implements PipelineContext {

    private Map<String, Object> contentMap = Maps.newConcurrentMap();

    @Override
    public void set(String contextKey, Object contextValue) {
        contentMap.put(contextKey, contextValue);
    }

    @Override
    public Object get(String contextKey) {
        return contentMap.get(contextKey);
    }
}
  • PipelineValue/AbstractPipelineValue/GraySwitchValue/ForTestValue
package com.example.ownertest.dm.pipelline;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:47
 */
public interface PipelineValue {

    /**
     * 节点执行
     *
     * @param pipelineContext
     * @return
     */
    boolean execute(PipelineContext pipelineContext);

}



package com.example.ownertest.dm.pipelline;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:48
 */
public abstract class AbstractPipelineValue implements PipelineValue {

    @Override
    public boolean execute(PipelineContext pipelineContext) {

        System.out.println(this.getClass().getSimpleName() + " start ");

        boolean result = doExec(pipelineContext);

        System.out.println(this.getClass().getSimpleName() + " end ");

        return result;
    }

    protected abstract boolean doExec(PipelineContext pipelineContext);
}


package com.example.ownertest.dm.pipelline;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:48
 */
public class GraySwitchValue extends AbstractPipelineValue {
    @Override
    public boolean doExec(PipelineContext pipelineContext) {

        pipelineContext.set(PipelineContext.FOR_TEST, true);

        return true;
    }
}



package com.example.ownertest.dm.pipelline;

/**
 * @Author: linear.zw
 * @Date: 2023/10/25 19:48
 */
public class ForTestValue extends AbstractPipelineValue {
    @Override
    public boolean doExec(PipelineContext pipelineContext) {

        return true;
    }
}
  • PipelineClient
package com.example.ownertest.dm.pipelline;

/**
 * 入口类
 *
 * @Author: linear.zw
 * @Date: 2023/10/25 19:48
 */
public class PipelineClient {

    public static void main(String[] args) {

        // 管道初始化
        Pipeline pipeline = new StandardPipeline();

        // value扩展
        PipelineValue pipelineValue = new GraySwitchValue();
        PipelineValue pipelineValue2 = new ForTestValue();

        // 上下文
        PipelineContext pipelineContext = new StandardPipelineContext();

        pipeline.addValue(pipelineValue);
        pipeline.addValue(pipelineValue2);

        // 调用管道
        pipeline.invoke(pipelineContext);

    }
}

Anwendungen in gängigen Frameworks

  • Im Netty-Framework werden die Hauptkomponenten der Netzwerkschicht, wie ChannelPipeline, ChannelHandler und ChannelHandlerContext, verwendet, um das Entpacken, Dekodieren usw. von TCP abzuwickeln.

Routine basierend auf der Filterkette

Kernpunkt

Siehe auch: https://www.oracle.com/java/technologies/intercepting-filter.html

  • Filter – der Knoten, der tatsächlich Geschäfte verarbeitet
  • FilterChain----eine Kette von Filtern in Reihe

Anwendbare Szene

  • Zum Beispiel gängige Webanforderungsszenarien

Code implementieren

  • Filter/ForTest1Filter/ForTest2Filter
package com.example.ownertest.dm.filter;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:22
 */
public interface Filter {

    void doFilter(HttpRequest httpRequest,FilterChain filterChain);
}



package com.example.ownertest.dm.filter;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:22
 */
public class ForTest1Filter implements Filter {
    @Override
    public void doFilter(HttpRequest httpRequest, FilterChain filterChain) {
        // do

        System.out.println(this.getClass().getSimpleName() + " before " + System.currentTimeMillis());

        filterChain.doFilter(httpRequest);

        // after

        System.out.println(this.getClass().getSimpleName() + " end " + System.currentTimeMillis());

    }
}





package com.example.ownertest.dm.filter;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:22
 */
public class ForTest2Filter implements Filter {
    @Override
    public void doFilter(HttpRequest httpRequest, FilterChain filterChain) {
        // do

        System.out.println(this.getClass().getSimpleName() + " before " + System.currentTimeMillis());

        filterChain.doFilter(httpRequest);

        // after

        System.out.println(this.getClass().getSimpleName() + " end " + System.currentTimeMillis());
    }
}
  • FilterChain/StandardFilterChain
package com.example.ownertest.dm.filter;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:23
 */
public interface FilterChain {

    void doFilter(HttpRequest httpRequest);

    void addFilter(Filter filter);
}




package com.example.ownertest.dm.filter;

import java.util.List;

import com.google.common.collect.Lists;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:24
 */
public class StandardFilterChain implements FilterChain {

    private List<Filter> filterList = Lists.newArrayList();

    private int currentIndex = 0;

    @Override
    public void doFilter(HttpRequest httpRequest) {
        if (currentIndex == filterList.size()) { return; }

        Filter filter = filterList.get(currentIndex);

        currentIndex = currentIndex + 1;

        filter.doFilter(httpRequest, this);
    }

    @Override
    public void addFilter(Filter filter) {
        if (filterList.contains(filter)) {
            return;
        }

        filterList.add(filter);
    }

}
  • HttpRequest/StandardHttpRequest
package com.example.ownertest.dm.filter;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:24
 */
public interface HttpRequest {
}




package com.example.ownertest.dm.filter;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:24
 */
public class StandardHttpRequest implements HttpRequest {
}
  • FilterClient----Eintrittstest
package com.example.ownertest.dm.filter;

/**
 * @Author: linear.zw
 * @Date: 2023/10/26 19:25
 */
public class FilterClient {

    public static void main(String[] args) {
        FilterChain filterChain = new StandardFilterChain();

        filterChain.addFilter(new ForTest1Filter());
        filterChain.addFilter(new ForTest2Filter());

        filterChain.doFilter(new StandardHttpRequest());
    }
}

Anwendungen in gängigen Frameworks

  • hsfs Filtermechanismus, serverseitiger erweiterter ServerFilter und clientseitiger erweiterter ClientFilter;

  • Freunde, die Java Web entwickelt haben, kennen sich mit Servlets aus. Der Eingang des Servlets ist FilterChain und Filter.

Kombinations-/vorlagenbasierte Routinen

Kernpunkt

  • Prozessorregister – wird zum Speichern einer Sammlung von Prozessoren verwendet
  • Prozessorfabrik – wird zum Erstellen von Prozessoren verwendet
  • Prozessor – der eigentliche Prozessor und die Implementierung der Erweiterung
  • Prozessorkontext ---- Prozessorkontext, der zum Übergeben von Parametern verwendet wird

Anwendbare Szene

  • Geeignet für Szenarien, die gemeinsame Merkmale aufweisen und in Zukunft weiter zunehmen werden

Code implementieren

  • PiiHandlerRegistry----Prozessorregister
package com.example.ownertest.dm.comp;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:45
 */
@Slf4j
public class PiiHandlerRegistry {

    private static Map<String, PiiDomainFieldHandler> piiDomainFieldHandlerMap = Maps.newHashMap();

    public static void putHandler(String piiDomainFieldName, PiiDomainFieldHandler piiDomainFieldHandler) {
        if (StringUtils.isEmpty(piiDomainFieldName)) {
            log.warn(" piiDomainFieldName is null,continue");
            return;
        }

        if (piiDomainFieldHandler == null) {
            log.warn(piiDomainFieldName + " piiDomainFieldHandler is null,continue");
            return;
        }

        if (!piiDomainFieldHandlerMap.containsKey(piiDomainFieldName)) {
            piiDomainFieldHandlerMap.put(piiDomainFieldName, piiDomainFieldHandler);
        }
    }

    public static <T extends Object> int handlerRead(T domain, Field domainField, PiiContent piiContent) {
        int num = 0;
        for (Map.Entry<String, PiiDomainFieldHandler> piiDomainFieldHandlerEntry :
            piiDomainFieldHandlerMap.entrySet()) {
            if (piiDomainFieldHandlerEntry.getValue().isSupport(domain, domainField)) {
                piiDomainFieldHandlerEntry.getValue().handlerRead(domain, domainField, piiContent);
            }
        }
        return num;
    }

    public static <T extends Object> int handlerWrite(T domain, Field domainField, PiiContent piiContent) {
        int num = 0;
        for (Map.Entry<String, PiiDomainFieldHandler> piiDomainFieldHandlerEntry :
            piiDomainFieldHandlerMap.entrySet()) {
            if (piiDomainFieldHandlerEntry.getValue().isSupport(domain, domainField)) {
                piiDomainFieldHandlerEntry.getValue().handlerWrite(domain, domainField, piiContent);
            }
        }
        return num;
    }

    public static Map<String, PiiDomainFieldHandler> getPiiDomainFieldHandlerMap() {
        return piiDomainFieldHandlerMap;
    }

    public static void init() {
        List<PiiDomainFieldHandler> piiDomainFieldHandlerList = PiiDomainFieldHandlerFactory
            .createPiiDomainFieldHandler();
        if (CollectionUtils.isNotEmpty(piiDomainFieldHandlerList)) {

            for (PiiDomainFieldHandler piiDomainFieldHandler :
                piiDomainFieldHandlerList) {
                putHandler(piiDomainFieldHandler.getPiiDomainMeta(), piiDomainFieldHandler);
            }
        }
    }
}
  • PiiDomainFieldHandlerFactory----Prozessorfabrik
package com.example.ownertest.dm.comp;

import java.util.List;

import com.google.common.collect.Lists;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:46
 */
public class PiiDomainFieldHandlerFactory {

    /**
     * 创建领域处理器
     *
     * @return
     */
    public static List<PiiDomainFieldHandler> createPiiDomainFieldHandler() {
        List<PiiDomainFieldHandler> piiDomainFieldHandlerList = Lists.newArrayList();

        //
        piiDomainFieldHandlerList.add(new ForTestSupportFieldHandler());
        piiDomainFieldHandlerList.add(new ForTestNotSupportFieldHandler());

        return piiDomainFieldHandlerList;
    }
}
  • PiiDomainFieldHandler/PiiDomainFieldHandlerBase/ForTestNotSupportFieldHandler/ForTestSupportFieldHandler----处理器
package com.example.ownertest.dm.comp;

import java.lang.reflect.Field;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:46
 */
public interface PiiDomainFieldHandler {

    /**
     * 处理实际操作
     * 读----从PiiContent获取数据回填domain
     *
     * @param domain
     * @param domainField
     * @param piiContent
     * @param <T>
     * @return
     */
    <T extends Object> boolean handlerRead(T domain, Field domainField, PiiContent piiContent);

    /**
     * 处理实际操作
     * 写----将domain中需要写入pii的字段数据写入PiiContent
     *
     * @param domain
     * @param domainField
     * @param piiContent
     * @param <T>
     * @return
     */
    <T extends Object> boolean handlerWrite(T domain, Field domainField, PiiContent piiContent);

    /**
     * 当前处理器是否支持该领域对象
     *
     * @param domain
     * @param domainField
     * @param <T>
     * @return
     */
    <T extends Object> boolean isSupport(T domain, Field domainField);

    /**
     * 获取处理器对应的元信息
     *
     * @return
     */
    String getPiiDomainMeta();
}




package com.example.ownertest.dm.comp;

import java.lang.reflect.Field;

import lombok.extern.slf4j.Slf4j;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:47
 */
@Slf4j
public abstract class PiiDomainFieldHandlerBase implements PiiDomainFieldHandler {

    @Override
    public <T extends Object> boolean handlerRead(T domain, Field domainField, PiiContent piiContent) {
        // to do business read

        return true;
    }

    @Override
    public <T extends Object> boolean handlerWrite(T domain, Field domainField, PiiContent piiContent) {

        // to do business write

        return true;
    }
}




package com.example.ownertest.dm.comp;

import java.lang.reflect.Field;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:47
 */
public class ForTestSupportFieldHandler extends PiiDomainFieldHandlerBase {
    @Override
    public <T> boolean isSupport(T domain, Field domainField) {

        if (this.getClass().getSimpleName().equalsIgnoreCase(domain.getClass().getSimpleName())) {

            // to do business

            System.out.println(this.getClass().getSimpleName() + " is support, to do some business");

            return true;
        }

        return false;
    }

    @Override
    public String getPiiDomainMeta() {
        return this.getClass().getSimpleName();
    }
}



package com.example.ownertest.dm.comp;

import java.lang.reflect.Field;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:48
 */
public class ForTestNotSupportFieldHandler extends PiiDomainFieldHandlerBase {
    @Override
    public <T> boolean isSupport(T domain, Field domainField) {

        if (this.getClass().getSimpleName().equalsIgnoreCase(domain.getClass().getSimpleName())) {

            // to do business

            System.out.println(this.getClass().getSimpleName() + " is support, to do some business");

            return true;
        }

        return false;
    }

    @Override
    public String getPiiDomainMeta() {
        return this.getClass().getSimpleName();
    }
}
  • PiiContent----Context
package com.example.ownertest.dm.comp;

import java.util.Map;

import com.google.common.collect.Maps;
import lombok.Data;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:48
 */
@Data
public class PiiContent {

    public static String FORTEST="fortest";

    private Map<String, Object> piiDataMap = Maps.newHashMap();

    private Map<String, Object> piiContextMap = Maps.newHashMap();

    public void putPiiData(String domainFieldName, Object domainFieldValue) {
        piiDataMap.put(domainFieldName, domainFieldValue);
    }

    public Object getPiiData(String domainFieldName) {
        return piiDataMap.get(domainFieldName);
    }

    public void putPiiContext(String contextName, Object contextNameValue) {
        piiContextMap.put(contextName, contextNameValue);
    }

    public Object getPiiContext(String contextName) {
        return piiContextMap.get(contextName);
    }
}
  • PiiClient----Eintrittstestklasse
package com.example.ownertest.dm.comp;

import java.util.Map;

/**
 * @Author: linear.zw
 * @Date: 2023/10/31 20:48
 */
public class PiiClient {

    public static void main(String[] args) {
        PiiHandlerRegistry.init();

        // 遍历处理器
        for (Map.Entry<String, PiiDomainFieldHandler> entryHandler :
            PiiHandlerRegistry.getPiiDomainFieldHandlerMap().entrySet()) {
            System.out.println(entryHandler.getKey() + "\t" + entryHandler.getValue().getPiiDomainMeta());
        }

        //
        PiiContent piiContent = new PiiContent();
        piiContent.putPiiContext(PiiContent.FORTEST, PiiContent.FORTEST);

        // 请求处理
        System.out.println("ForTestSupportFieldHandler start");
        PiiHandlerRegistry.handlerRead(new ForTestSupportFieldHandler(), null, piiContent);
        System.out.println("ForTestSupportFieldHandler end");

        // 请求处理
        System.out.println("ForTestNotSupportFieldHandler start");
        PiiHandlerRegistry.handlerRead(new ForTestNotSupportFieldHandler(), null, piiContent);
        System.out.println("ForTestNotSupportFieldHandler end");

    }
}

Anwendungen in gängigen Frameworks

  • Es gibt zu viele. Beispielsweise verwaltet der BeanPostProcessor-Kernmechanismus von Spring eine Reihe von BeanPostProcessors über org.springframework.beans.factory.support.AbstractBeanFactory#beanPostProcessors. Wenn der Spring-Kontext org.springframework.context.support.AbstractApplicationContext#refresh ist, Bean-Initialisierung durchführen (InitDestroyAnnotationBeanPostProcessor), Anmerkungen analysieren (ScheduledAnnotationBeanPostProcessor, AutowiredAnnotationBeanPostProcessor), AOP analysieren (AnnotationAwareAspectJAutoProxyCreator) usw.

Annotationsbasierte Routinen

Kernpunkt

  • Anmerkungs-Metadefinition ---- wird zum Definieren allgemeiner Metainformationen verwendet;
  • Annotationsparser – analysiert, ob bestimmte Annotationen für die Klasse vorhanden sind, und führt dann entsprechende Erweiterungsoperationen aus;
  • BeanPostProcessor von Spring ---- Hier leihen wir uns den BeanPostProcessor-Mechanismus von Spring. Wenn der Spring-Container initialisiert wird, wird ein Rückruf ausgeführt, um das erwartete Erweiterungsverhalten abzuschließen.

Anwendbare Szene

  • Vereinfachen Sie die interne Verwendung

Code implementieren

  • ForTestAnnotation----Annotations-Metadefinition
package com.example.ownertest.dm.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Component;

/**
 * 用于测试的标识注解
 *
 * @Author: linear.zw
 * @Date: 2023/11/1 10:21
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface ForTestAnnotation {
}
  • ForTestAnnotationProcessor----Annotationsparser
package com.example.ownertest.dm.annotation;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

/**
 * 注解解析器
 * @Author: linear.zw
 * @Date: 2023/11/1 10:25
 */
@Component
public class ForTestAnnotationProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        // 获取目标类是否有ForTestAnnotation注解
        ForTestAnnotation annotation = AnnotationUtils.findAnnotation(AopUtils.getTargetClass(bean),
            ForTestAnnotation.class);

        if (annotation == null) {
            return bean;
        }

        // 处理想要的扩展
        System.out.println(beanName + " has ForTestAnnotation");

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
  • ForTestBean----Test-Bean
package com.example.ownertest.dm.annotation;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 10:26
 */
@ForTestAnnotation
public class ForTestBean {

    public ForTestBean() {
        System.out.println(ForTestBean.class.getSimpleName() + " init");
    }
}
  • ForTestClient---Testeingang
package com.example.ownertest.dm.annotation;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 10:26
 */
public class ForTestClient {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
            "com.example.ownertest.dm.annotation");

        System.out.println(ForTestClient.class.getSimpleName());
    }
}

Anwendungen in gängigen Frameworks

  • Beispielsweise spring-boot-alibaba-diamond-autoconfigure innerhalb der Gruppe

Routinen basierend auf der Ereignisverteilung

Kernpunkt

  • Ereignisquelle – Ereignisauslöser
  • Ereignis – die Quelle der Identifizierung
  • Ereignis-Listener – der Follower des Ereignisses, also der Handler
  • Ereignis-Dispatcher – wird zum Weiterleiten von Ereignissen von Ereignisquellen an Ereignis-Listener verwendet

Code implementieren

  • EventSource/EventSourceForTest/EventSourceForTest2
package com.example.ownertest.dm.event;

/**
 * 发出事件
 * @Author: linear.zw
 * @Date: 2023/11/1 14:12
 */
public interface EventSource {

    /**
     * 发出事件
     *
     * @return
     */
    Event fireEvent();
}





package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:14
 */
public class EventSourceForTest implements EventSource {
    @Override
    public Event fireEvent() {

        Event event = new EventForTest();
        System.out.println(getClass().getSimpleName() + " \t fireEvent " + event.getName());

        return event;
    }
}





package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:15
 */
public class EventSourceForTest2 implements EventSource {
    @Override
    public Event fireEvent() {

        Event event = new EventForTest2();
        System.out.println(getClass().getSimpleName() + " \t fireEvent " + event.getName());

        return event;
    }
}
  • Event/EventForTest/EventForTest2
package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:15
 */
public interface Event {

    /**
     * 事件名称
     *
     * @return
     */
    String getName();
}




package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:17
 */
public class EventForTest implements Event {
    @Override
    public String getName() {
        return getClass().getSimpleName();
    }
}




package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:17
 */
public class EventForTest2 implements Event {
    @Override
    public String getName() {
        return getClass().getSimpleName();
    }
}
  • EventListener/EventListenerForTest
package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:17
 */
public interface EventListener {

    /**
     * 是否支持此事件
     *
     * @param event
     * @return
     */
    boolean supportEvent(Event event);

    /**
     * 处理事件
     *
     * @return
     */
    boolean handlerEvent(Event event);
}





package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:18
 */
public class EventListenerForTest implements EventListener {
    @Override
    public boolean supportEvent(Event event) {

        return event.getName().contains("Test");
    }

    @Override
    public boolean handlerEvent(Event event) {

        System.out.println(this.getClass().getSimpleName() + "\t handler " + event.getName());

        return true;
    }
}
  • EventDispatcher/EventListenerManager
package com.example.ownertest.dm.event;

import org.apache.commons.collections4.CollectionUtils;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:18
 */
public class EventDispatcher {

    /**
     * 单例模式
     */
    private static EventDispatcher eventDispatcher = new EventDispatcher();

    private EventDispatcher() {

    }

    /**
     * 分发事件
     *
     * @param event
     * @return
     */
    public static boolean dispatchEvent(Event event) {
        if (CollectionUtils.isNotEmpty(EventListenerManager.getEventListenerList())) {
            for (EventListener eventListener :
                EventListenerManager.getEventListenerList()) {
                if (eventListener.supportEvent(event)) {
                    eventListener.handlerEvent(event);
                }
            }
        }
        return true;
    }
}



package com.example.ownertest.dm.event;

import java.util.List;

import com.google.common.collect.Lists;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:18
 */
public class EventListenerManager {

    private static List<EventListener> eventListenerList = Lists.newArrayList();

    /**
     * 添加事件监听器
     *
     * @param eventListener
     * @return
     */
    public static boolean addEventListener(EventListener eventListener) {
        if (!eventListenerList.contains(eventListener)) {
            return eventListenerList.add(eventListener);
        }

        return true;
    }

    /**
     * 移除事件监听器
     *
     * @param eventListener
     * @return
     */
    public static boolean removeEventListener(EventListener eventListener) {
        if (eventListenerList.contains(eventListener)) {
            return eventListenerList.remove(eventListener);
        }

        return true;
    }

    public static List<EventListener> getEventListenerList() {
        return eventListenerList;
    }
}
  • EventClient
package com.example.ownertest.dm.event;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 14:19
 */
public class EventClient {

    public static void main(String[] args) {

        // 创建事件源
        EventSource eventSourceForTest = new EventSourceForTest();
        EventSource eventSourceForTest2 = new EventSourceForTest2();

        // 创建事件监听器
        EventListener eventListener = new EventListenerForTest();
        EventListenerManager.addEventListener(eventListener);

        // 发布事件
        EventDispatcher.dispatchEvent(eventSourceForTest.fireEvent());
        EventDispatcher.dispatchEvent(eventSourceForTest2.fireEvent());

    }
}

Routine basierend auf dem SPI-Mechanismus

Kernpunkt

 
 
  • Serviceanrufer
  • Dienstimplementierer ---- Verwenden Sie den Schnittstellennamen als Dateinamen, fügen Sie ihn in META-INF/services ein und der Wert ist die Implementierung der Schnittstelle

  • Standard-Serviceschnittstelle

Anwendbare Szene

Code implementieren

  • SpiServiceLoaderHelper
package com.example.ownertest.dm.spi;

import java.util.Iterator;
import java.util.Objects;
import java.util.ServiceLoader;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 15:32
 */
public class SpiServiceLoaderHelper {

    public static ProductPackageRemoteServiceInterface getProductPackageRemoteServiceInterface() {
        // 先从缓存中加载
        Object serviceCache = DependServiceRegistryHelper.getDependObject(ProductPackageRemoteServiceInterface.class);
        if (serviceCache != null) {
            return (ProductPackageRemoteServiceInterface) serviceCache;
        }
        // spi 方式加载
        ProductPackageRemoteServiceInterface serviceInterface = loadSpiImpl(ProductPackageRemoteServiceInterface.class);
        // 防止注入的bean为空 提前进行判断 以免业务执行出现问题
        boolean isExist = true;
        if (Objects.isNull(serviceInterface)) {
            isExist = false;
        } else if (Objects.isNull(serviceInterface.getProductPackageRemoteService())) {
            isExist = false;
        }
        if (!isExist) {
            throw new RuntimeException("getProductPackageRemoteService load impl failed,please check spi service");
        }
        // 添加进统一的依赖管理
        DependServiceRegistryHelper.registry(ProductPackageRemoteServiceInterface.class, serviceInterface);
        return serviceInterface;
    }

    /**
     * 以spi的方式加载实现类
     *
     * @param cls
     * @param <P>
     * @return
     */
    private static <P> P loadSpiImpl(Class<P> cls) {
        ServiceLoader<P> spiLoader = ServiceLoader.load(cls);
        Iterator<P> iaIterator = spiLoader.iterator();
        if (iaIterator.hasNext()) {
            return iaIterator.next();
        }
        return null;
    }
}
  • DependServiceRegistryHelper
package com.example.ownertest.dm.spi;

import java.util.Map;

import com.google.common.collect.Maps;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 15:35
 */
public class DependServiceRegistryHelper {

    /**
     * 存储策略依赖的服务,统一管理
     */
    private static Map<String, Object> dependManagerMap = Maps.newHashMap();

    public static boolean registryMap(Map<Class, Object> dependManagerMap) {
        for (Map.Entry<Class, Object> dependEntry :
            dependManagerMap.entrySet()) {
            registry(dependEntry.getKey(), dependEntry.getValue());
        }
        return true;
    }

    public static boolean registry(Class cls, Object dependObject) {
        dependManagerMap.put(cls.getCanonicalName(), dependObject);
        return true;
    }

    public static Object getDependObject(Class cls) {

        return dependManagerMap.get(cls.getCanonicalName());
    }
}
  • SpiServiceLoaderClientTest
package com.example.ownertest.dm.spi;

/**
 * @Author: linear.zw
 * @Date: 2023/11/1 15:37
 */
public class SpiServiceLoaderClientTest {

    public static void main(String[] args) {
        ProductPackageRemoteServiceInterface productPackageRemoteServiceInterface
            = SpiServiceLoaderHelper.getProductPackageRemoteServiceInterface();

    }
}

Anwendungen in gängigen Frameworks

  • Derzeit basieren die meisten Strategiepakete im Middle Office auf der SPI-Methode und laden die Geschäftsimplementierung dynamisch, um den Expansionszweck zu erreichen.
  • Beispielsweise generiert der Open-Source-Autoservice von Google automatisch das SPI-Implementierungsverzeichnis durch Anmerkungen;

zu guter Letzt

Die meisten Programmierer sind praktische Leute. Was sind also Ihre Routinen? Ihr Platz ist im Kommentarbereich. Zeigen Sie mir den Code.

Autor|Ghat

Ursprünglicher Link

Dieser Artikel ist Originalinhalt von Alibaba Cloud und darf nicht ohne Genehmigung reproduziert werden.

Spring Boot 3.2.0 wird offiziell veröffentlicht. Der schwerwiegendste Servicefehler in der Geschichte von Didi. Liegt der Schuldige an der zugrunde liegenden Software oder an „Kostensenkung und zunehmendem Lachen“? Programmierer manipulierten ETC-Guthaben und veruntreuten mehr als 2,6 Millionen Yuan pro Jahr. Google-Mitarbeiter kritisierten den Big Boss, nachdem sie ihren Job aufgegeben hatten. Sie waren stark in das Flutter-Projekt involviert und formulierten HTML-bezogene Standards. Microsoft Copilot Web AI wird offiziell am eingeführt 1. Dezember, Unterstützung für chinesisches PHP 8.3 GA Firefox im Jahr 2023 Rust Web Framework Rocket ist schneller geworden und hat Version 0.5 veröffentlicht: Unterstützt asynchron, SSE, WebSockets usw. Der Desktop-Prozessor Loongson 3A6000 wird offiziell veröffentlicht, das Licht der inländischen Produktion! Broadcom gibt erfolgreiche Übernahme von VMware bekannt
{{o.name}}
{{m.name}}

Acho que você gosta

Origin my.oschina.net/yunqi/blog/10314488
Recomendado
Clasificación