or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

clustering.mdconfiguration.mdextensions.mdindex.mdmetadata.mdregistry.mdrpc-core.mdserialization.mdspring-boot.md

extensions.mddocs/

0

# Extension System

1

2

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.

3

4

## Capabilities

5

6

### Extension Loading

7

8

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

9

10

```java { .api }

11

/**

12

* Extension loader for SPI-based extension management

13

* @param <T> Extension interface type

14

*/

15

public class ExtensionLoader<T> {

16

/**

17

* Get extension loader for specific type

18

* @param type Extension interface class

19

* @return Extension loader instance

20

*/

21

public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type);

22

23

/**

24

* Get extension instance by name

25

* @param name Extension name

26

* @return Extension instance

27

*/

28

public T getExtension(String name);

29

30

/**

31

* Get adaptive extension that can select implementation at runtime

32

* @return Adaptive extension instance

33

*/

34

public T getAdaptiveExtension();

35

36

/**

37

* Get default extension instance

38

* @return Default extension instance

39

*/

40

public T getDefaultExtension();

41

42

/**

43

* Get activate extensions based on URL parameters

44

* @param url Service URL with parameters

45

* @param values Parameter values for activation

46

* @param group Extension group

47

* @return List of activated extensions

48

*/

49

public List<T> getActivateExtensions(URL url, String[] values, String group);

50

51

/**

52

* Get all supported extension names

53

* @return Set of extension names

54

*/

55

public Set<String> getSupportedExtensions();

56

57

/**

58

* Check if extension exists

59

* @param name Extension name

60

* @return True if extension exists

61

*/

62

public boolean hasExtension(String name);

63

64

/**

65

* Add extension programmatically

66

* @param name Extension name

67

* @param clazz Extension class

68

*/

69

public void addExtension(String name, Class<?> clazz);

70

71

/**

72

* Remove extension

73

* @param name Extension name

74

*/

75

public void removeExtension(String name);

76

77

/**

78

* Get loaded extension names

79

* @return Set of loaded extension names

80

*/

81

public Set<String> getLoadedExtensions();

82

83

/**

84

* Get loaded extension instance

85

* @param name Extension name

86

* @return Extension instance if loaded

87

*/

88

public Object getLoadedExtension(String name);

89

}

90

```

91

92

**Usage Examples:**

93

94

```java

95

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

96

import org.apache.dubbo.rpc.Protocol;

97

98

// Get protocol extension loader

99

ExtensionLoader<Protocol> protocolLoader = ExtensionLoader.getExtensionLoader(Protocol.class);

100

101

// Get specific protocol implementation

102

Protocol dubboProtocol = protocolLoader.getExtension("dubbo");

103

Protocol restProtocol = protocolLoader.getExtension("rest");

104

105

// Get adaptive protocol that selects implementation at runtime

106

Protocol adaptiveProtocol = protocolLoader.getAdaptiveExtension();

107

108

// List all available protocols

109

Set<String> supportedProtocols = protocolLoader.getSupportedExtensions();

110

System.out.println("Supported protocols: " + supportedProtocols);

111

```

112

113

### Extension Point Declaration

114

115

Extensions are declared using the `@SPI` annotation on interfaces.

116

117

```java { .api }

118

/**

119

* SPI extension point marker annotation

120

*/

121

@Target(ElementType.TYPE)

122

@Retention(RetentionPolicy.RUNTIME)

123

public @interface SPI {

124

/**

125

* Default extension name

126

* @return Default extension name

127

*/

128

String value() default "";

129

130

/**

131

* Extension scope for lifecycle management

132

* @return Extension scope

133

*/

134

ExtensionScope scope() default ExtensionScope.FRAMEWORK;

135

}

136

137

/**

138

* Extension scope enumeration

139

*/

140

public enum ExtensionScope {

141

FRAMEWORK, // Framework-level singleton

142

APPLICATION, // Application-level singleton

143

MODULE, // Module-level singleton

144

SELF // Instance-level, not singleton

145

}

146

```

147

148

**Usage Examples:**

149

150

```java

151

// Declare a custom extension point

152

@SPI("default")

153

public interface CustomLoadBalance {

154

<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation);

155

}

156

157

// Implementation

158

public class MyLoadBalance implements CustomLoadBalance {

159

@Override

160

public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {

161

// Custom load balancing logic

162

return invokers.get(0);

163

}

164

}

165

```

166

167

### Adaptive Extensions

168

169

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

170

171

```java { .api }

172

/**

173

* Adaptive extension annotation for runtime selection

174

*/

175

@Target({ElementType.METHOD, ElementType.TYPE})

176

@Retention(RetentionPolicy.RUNTIME)

177

public @interface Adaptive {

178

/**

179

* Parameter keys for adaptive selection

180

* @return Parameter key names

181

*/

182

String[] value() default {};

183

}

184

```

185

186

**Usage Examples:**

187

188

```java

189

@SPI("dubbo")

190

public interface Protocol {

191

int getDefaultPort();

192

193

// Adaptive method selects implementation based on URL protocol

194

@Adaptive

195

<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

196

197

// Adaptive method with custom parameter key

198

@Adaptive({"protocol"})

199

<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;

200

}

201

202

// Usage - the adaptive extension will select "dubbo" or "rest" protocol

203

// based on the URL protocol parameter

204

URL url = URL.valueOf("rest://localhost:8080/service");

205

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

206

Invoker<Service> invoker = protocol.refer(Service.class, url); // Uses REST protocol

207

```

208

209

### Extension Activation

210

211

The `@Activate` annotation enables conditional activation of extensions.

212

213

```java { .api }

214

/**

215

* Extension activation annotation for conditional loading

216

*/

217

@Target(ElementType.TYPE)

218

@Retention(RetentionPolicy.RUNTIME)

219

public @interface Activate {

220

/**

221

* Activation groups

222

* @return Group names

223

*/

224

String[] group() default {};

225

226

/**

227

* Activation parameter keys

228

* @return Parameter keys that trigger activation

229

*/

230

String[] value() default {};

231

232

/**

233

* Extensions that must be loaded before this one

234

* @return Extension names

235

*/

236

String[] before() default {};

237

238

/**

239

* Extensions that must be loaded after this one

240

* @return Extension names

241

*/

242

String[] after() default {};

243

244

/**

245

* Activation order (lower value = higher priority)

246

* @return Order value

247

*/

248

int order() default 0;

249

}

250

```

251

252

**Usage Examples:**

253

254

```java

255

// Filter that activates for consumer side only

256

@Activate(group = "consumer", order = -10000)

257

public class ConsumerContextFilter implements Filter {

258

@Override

259

public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

260

// Consumer-side filtering logic

261

return invoker.invoke(invocation);

262

}

263

}

264

265

// Filter that activates when cache parameter is present

266

@Activate(group = {"consumer", "provider"}, value = "cache")

267

public class CacheFilter implements Filter {

268

@Override

269

public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

270

// Caching logic

271

return invoker.invoke(invocation);

272

}

273

}

274

275

// Get activated filters

276

ExtensionLoader<Filter> filterLoader = ExtensionLoader.getExtensionLoader(Filter.class);

277

URL url = URL.valueOf("dubbo://localhost:20880/service?cache=lru");

278

List<Filter> filters = filterLoader.getActivateExtensions(url, new String[]{"cache"}, "consumer");

279

```

280

281

### Extension Configuration

282

283

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

284

285

**Configuration File Format:**

286

```

287

# META-INF/dubbo/org.apache.dubbo.rpc.Protocol

288

dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol

289

rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol

290

grpc=org.apache.dubbo.rpc.protocol.grpc.GrpcProtocol

291

```

292

293

**Directory Structure:**

294

```

295

META-INF/

296

├── dubbo/ # Dubbo-specific extensions

297

├── dubbo/internal/ # Internal extensions

298

└── services/ # Standard Java SPI

299

```

300

301

### Wrapper Extensions

302

303

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

304

305

```java { .api }

306

/**

307

* Wrapper extension example

308

*/

309

public class ProtocolFilterWrapper implements Protocol {

310

private final Protocol protocol;

311

312

public ProtocolFilterWrapper(Protocol protocol) {

313

this.protocol = protocol;

314

}

315

316

@Override

317

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {

318

// Add pre-processing

319

return protocol.export(buildInvokerChain(invoker));

320

}

321

322

@Override

323

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {

324

// Add post-processing

325

return buildInvokerChain(protocol.refer(type, url));

326

}

327

328

private <T> Invoker<T> buildInvokerChain(Invoker<T> invoker) {

329

// Build filter chain

330

return invoker;

331

}

332

}

333

```

334

335

### Common Extension Points

336

337

Apache Dubbo provides numerous built-in extension points:

338

339

```java { .api }

340

// Core extension interfaces

341

@SPI("dubbo")

342

public interface Protocol { /* ... */ }

343

344

@SPI("random")

345

public interface LoadBalance { /* ... */ }

346

347

@SPI("failover")

348

public interface Cluster { /* ... */ }

349

350

@SPI("zookeeper")

351

public interface RegistryFactory { /* ... */ }

352

353

@SPI("hessian2")

354

public interface Serialization { /* ... */ }

355

356

@SPI("netty")

357

public interface Transporter { /* ... */ }

358

359

@SPI("javassist")

360

public interface ProxyFactory { /* ... */ }

361

362

@SPI

363

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

364

365

@SPI("jdk")

366

public interface Compiler { /* ... */ }

367

```

368

369

**Creating Custom Extensions:**

370

371

```java

372

// 1. Define extension interface

373

@SPI("default")

374

public interface CustomService {

375

String process(String input);

376

}

377

378

// 2. Implement extension

379

public class MyCustomService implements CustomService {

380

@Override

381

public String process(String input) {

382

return "Processed: " + input;

383

}

384

}

385

386

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

387

// my=com.example.MyCustomService

388

389

// 4. Use extension

390

ExtensionLoader<CustomService> loader = ExtensionLoader.getExtensionLoader(CustomService.class);

391

CustomService service = loader.getExtension("my");

392

String result = service.process("test");

393

```

394

395

### Extension Injection

396

397

Dubbo supports automatic injection of dependencies into extensions.

398

399

```java { .api }

400

/**

401

* Extension with dependency injection

402

*/

403

public class MyProtocol implements Protocol {

404

// Dubbo will automatically inject the LoadBalance extension

405

private LoadBalance loadBalance;

406

407

// Setter injection

408

public void setLoadBalance(LoadBalance loadBalance) {

409

this.loadBalance = loadBalance;

410

}

411

412

@Override

413

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {

414

// Use injected loadBalance

415

return new MyInvoker<>(type, url, loadBalance);

416

}

417

}

418

```

419

420

### Extension Lifecycle

421

422

Extensions participate in Dubbo's lifecycle management.

423

424

```java { .api }

425

/**

426

* Lifecycle-aware extension

427

*/

428

public class MyExtension implements Protocol, Lifecycle {

429

private volatile boolean initialized = false;

430

431

@Override

432

public void initialize() throws IllegalStateException {

433

// Extension initialization logic

434

initialized = true;

435

}

436

437

@Override

438

public void start() throws IllegalStateException {

439

// Extension startup logic

440

}

441

442

@Override

443

public void destroy() throws IllegalStateException {

444

// Extension cleanup logic

445

initialized = false;

446

}

447

448

@Override

449

public boolean isInitialized() {

450

return initialized;

451

}

452

}

453

```

454

455

**Extension Best Practices:**

456

457

1. **Use meaningful names** for extensions in configuration files

458

2. **Implement proper error handling** in extension methods

459

3. **Follow single responsibility principle** for each extension

460

4. **Use @Activate wisely** to avoid unnecessary extension loading

461

5. **Provide clear documentation** for custom extensions

462

6. **Test extensions** in isolation and integration scenarios

463

7. **Consider performance impact** of wrapper extensions

464

8. **Use dependency injection** instead of direct extension loading