CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-dubbo--dubbo

Apache Dubbo is a powerful RPC framework for building enterprise-grade microservices with service discovery, load balancing, and fault tolerance.

Pending
Overview
Eval results
Files

extensions.mddocs/

Extension System

Apache Dubbo's SPI (Service Provider Interface) extension system provides a powerful and flexible mechanism for customizing all major framework components. It enables plugin-style architecture where core functionality can be extended or replaced without modifying the core framework.

Capabilities

Extension Loading

The ExtensionLoader class provides the core mechanism for loading and managing extensions.

/**
 * Extension loader for SPI-based extension management
 * @param <T> Extension interface type
 */
public class ExtensionLoader<T> {
    /**
     * Get extension loader for specific type
     * @param type Extension interface class
     * @return Extension loader instance
     */
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type);
    
    /**
     * Get extension instance by name
     * @param name Extension name
     * @return Extension instance
     */
    public T getExtension(String name);
    
    /**
     * Get adaptive extension that can select implementation at runtime
     * @return Adaptive extension instance
     */
    public T getAdaptiveExtension();
    
    /**
     * Get default extension instance
     * @return Default extension instance
     */
    public T getDefaultExtension();
    
    /**
     * Get activate extensions based on URL parameters
     * @param url Service URL with parameters
     * @param values Parameter values for activation
     * @param group Extension group
     * @return List of activated extensions
     */
    public List<T> getActivateExtensions(URL url, String[] values, String group);
    
    /**
     * Get all supported extension names
     * @return Set of extension names
     */
    public Set<String> getSupportedExtensions();
    
    /**
     * Check if extension exists
     * @param name Extension name
     * @return True if extension exists
     */
    public boolean hasExtension(String name);
    
    /**
     * Add extension programmatically
     * @param name Extension name
     * @param clazz Extension class
     */
    public void addExtension(String name, Class<?> clazz);
    
    /**
     * Remove extension
     * @param name Extension name
     */
    public void removeExtension(String name);
    
    /**
     * Get loaded extension names
     * @return Set of loaded extension names
     */
    public Set<String> getLoadedExtensions();
    
    /**
     * Get loaded extension instance
     * @param name Extension name
     * @return Extension instance if loaded
     */
    public Object getLoadedExtension(String name);
}

Usage Examples:

import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.Protocol;

// Get protocol extension loader
ExtensionLoader<Protocol> protocolLoader = ExtensionLoader.getExtensionLoader(Protocol.class);

// Get specific protocol implementation
Protocol dubboProtocol = protocolLoader.getExtension("dubbo");
Protocol restProtocol = protocolLoader.getExtension("rest");

// Get adaptive protocol that selects implementation at runtime
Protocol adaptiveProtocol = protocolLoader.getAdaptiveExtension();

// List all available protocols
Set<String> supportedProtocols = protocolLoader.getSupportedExtensions();
System.out.println("Supported protocols: " + supportedProtocols);

Extension Point Declaration

Extensions are declared using the @SPI annotation on interfaces.

/**
 * SPI extension point marker annotation
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SPI {
    /**
     * Default extension name
     * @return Default extension name
     */
    String value() default "";
    
    /**
     * Extension scope for lifecycle management
     * @return Extension scope
     */
    ExtensionScope scope() default ExtensionScope.FRAMEWORK;
}

/**
 * Extension scope enumeration
 */
public enum ExtensionScope {
    FRAMEWORK, // Framework-level singleton
    APPLICATION, // Application-level singleton
    MODULE, // Module-level singleton
    SELF // Instance-level, not singleton
}

Usage Examples:

// Declare a custom extension point
@SPI("default")
public interface CustomLoadBalance {
    <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation);
}

// Implementation
public class MyLoadBalance implements CustomLoadBalance {
    @Override
    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        // Custom load balancing logic
        return invokers.get(0);
    }
}

Adaptive Extensions

Adaptive extensions allow runtime selection of implementations based on URL parameters.

/**
 * Adaptive extension annotation for runtime selection
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Adaptive {
    /**
     * Parameter keys for adaptive selection
     * @return Parameter key names
     */
    String[] value() default {};
}

Usage Examples:

@SPI("dubbo")
public interface Protocol {
    int getDefaultPort();
    
    // Adaptive method selects implementation based on URL protocol
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
    
    // Adaptive method with custom parameter key
    @Adaptive({"protocol"})
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
}

// Usage - the adaptive extension will select "dubbo" or "rest" protocol
// based on the URL protocol parameter
URL url = URL.valueOf("rest://localhost:8080/service");
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
Invoker<Service> invoker = protocol.refer(Service.class, url); // Uses REST protocol

Extension Activation

The @Activate annotation enables conditional activation of extensions.

/**
 * Extension activation annotation for conditional loading
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Activate {
    /**
     * Activation groups
     * @return Group names
     */
    String[] group() default {};
    
    /**
     * Activation parameter keys
     * @return Parameter keys that trigger activation
     */
    String[] value() default {};
    
    /**
     * Extensions that must be loaded before this one
     * @return Extension names
     */
    String[] before() default {};
    
    /**
     * Extensions that must be loaded after this one
     * @return Extension names
     */
    String[] after() default {};
    
    /**
     * Activation order (lower value = higher priority)
     * @return Order value
     */
    int order() default 0;
}

Usage Examples:

// Filter that activates for consumer side only
@Activate(group = "consumer", order = -10000)
public class ConsumerContextFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // Consumer-side filtering logic
        return invoker.invoke(invocation);
    }
}

// Filter that activates when cache parameter is present
@Activate(group = {"consumer", "provider"}, value = "cache")
public class CacheFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // Caching logic
        return invoker.invoke(invocation);
    }
}

// Get activated filters
ExtensionLoader<Filter> filterLoader = ExtensionLoader.getExtensionLoader(Filter.class);
URL url = URL.valueOf("dubbo://localhost:20880/service?cache=lru");
List<Filter> filters = filterLoader.getActivateExtensions(url, new String[]{"cache"}, "consumer");

Extension Configuration

Extensions are configured through configuration files in the META-INF/dubbo/ directory.

Configuration File Format:

# META-INF/dubbo/org.apache.dubbo.rpc.Protocol
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol
grpc=org.apache.dubbo.rpc.protocol.grpc.GrpcProtocol

Directory Structure:

META-INF/
├── dubbo/                          # Dubbo-specific extensions
├── dubbo/internal/                 # Internal extensions
└── services/                       # Standard Java SPI

Wrapper Extensions

Wrapper extensions provide AOP-like functionality for decorating other extensions.

/**
 * Wrapper extension example
 */
public class ProtocolFilterWrapper implements Protocol {
    private final Protocol protocol;
    
    public ProtocolFilterWrapper(Protocol protocol) {
        this.protocol = protocol;
    }
    
    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        // Add pre-processing
        return protocol.export(buildInvokerChain(invoker));
    }
    
    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        // Add post-processing
        return buildInvokerChain(protocol.refer(type, url));
    }
    
    private <T> Invoker<T> buildInvokerChain(Invoker<T> invoker) {
        // Build filter chain
        return invoker;
    }
}

Common Extension Points

Apache Dubbo provides numerous built-in extension points:

// Core extension interfaces
@SPI("dubbo")
public interface Protocol { /* ... */ }

@SPI("random")  
public interface LoadBalance { /* ... */ }

@SPI("failover")
public interface Cluster { /* ... */ }

@SPI("zookeeper")
public interface RegistryFactory { /* ... */ }

@SPI("hessian2")
public interface Serialization { /* ... */ }

@SPI("netty")
public interface Transporter { /* ... */ }

@SPI("javassist")
public interface ProxyFactory { /* ... */ }

@SPI
public interface Filter { /* ... */ }

@SPI("jdk")
public interface Compiler { /* ... */ }

Creating Custom Extensions:

// 1. Define extension interface
@SPI("default")
public interface CustomService {
    String process(String input);
}

// 2. Implement extension
public class MyCustomService implements CustomService {
    @Override
    public String process(String input) {
        return "Processed: " + input;
    }
}

// 3. Create configuration file: META-INF/dubbo/com.example.CustomService
// my=com.example.MyCustomService

// 4. Use extension
ExtensionLoader<CustomService> loader = ExtensionLoader.getExtensionLoader(CustomService.class);
CustomService service = loader.getExtension("my");
String result = service.process("test");

Extension Injection

Dubbo supports automatic injection of dependencies into extensions.

/**
 * Extension with dependency injection
 */
public class MyProtocol implements Protocol {
    // Dubbo will automatically inject the LoadBalance extension
    private LoadBalance loadBalance;
    
    // Setter injection
    public void setLoadBalance(LoadBalance loadBalance) {
        this.loadBalance = loadBalance;
    }
    
    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        // Use injected loadBalance
        return new MyInvoker<>(type, url, loadBalance);
    }
}

Extension Lifecycle

Extensions participate in Dubbo's lifecycle management.

/**
 * Lifecycle-aware extension
 */
public class MyExtension implements Protocol, Lifecycle {
    private volatile boolean initialized = false;
    
    @Override
    public void initialize() throws IllegalStateException {
        // Extension initialization logic
        initialized = true;
    }
    
    @Override
    public void start() throws IllegalStateException {
        // Extension startup logic
    }
    
    @Override
    public void destroy() throws IllegalStateException {
        // Extension cleanup logic
        initialized = false;
    }
    
    @Override
    public boolean isInitialized() {
        return initialized;
    }
}

Extension Best Practices:

  1. Use meaningful names for extensions in configuration files
  2. Implement proper error handling in extension methods
  3. Follow single responsibility principle for each extension
  4. Use @Activate wisely to avoid unnecessary extension loading
  5. Provide clear documentation for custom extensions
  6. Test extensions in isolation and integration scenarios
  7. Consider performance impact of wrapper extensions
  8. Use dependency injection instead of direct extension loading

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-dubbo--dubbo

docs

clustering.md

configuration.md

extensions.md

index.md

metadata.md

registry.md

rpc-core.md

serialization.md

spring-boot.md

tile.json