IoC Container & Service Providers
Este documento aborda o conceito e o uso do contêiner Inversion of Control (IoC) dentro do AdonisJs. É um conceito de armazenar/vincular dependências dentro de um contêiner e então buscá-las de volta do contêiner em vez de solicitá-las manualmente. O benefício dessa abordagem é:
- A configuração de um objeto é ocultada do usuário final, fornecendo uma API simples e clara.
- Suporte sólido para Dependency Injection (DI), já que todos os objetos são buscados de uma única fonte de verdade.
- Fácil de escrever módulos/addons de terceiros, já que você pode buscar dependências do contêiner IoC, em vez de segurar o usuário final para passá-las manualmente.
Exemplo básico
Vamos dar um exemplo simples de vincular dependências ao contêiner IoC e então consumi-las mais tarde. Ao longo desse processo, você será apresentado a muitos termos e métodos novos.
// Dependências de ligação
const Ioc = require('adonis-fold').Ioc
const bugsnag = require('bugsnag')
Ioc.bind('Adonis/Src/Bugsnag', function (app) { <1>
const Config = app.use('Adonis/Src/Config') <2>
const bugSnagConfig = Config.get('services.bugsnag') <3>
bugsnag.register(bugSnagConfig.apiKey, bugSnagConfig.options) <4>
return bugsnag <5>
})
- Começamos vinculando um objeto ao contêiner IoC. Cada vinculação precisa ter um namespace exclusivo que é
Adonis/Src/Bugsnag
neste caso. - Como temos acesso ao contêiner
Ioc
dentro do fechamento, buscamos a vinculação Config. - Em seguida, pegamos a configuração do
bugsnag
que deve ser salva dentro do arquivoconfig/services.js
. - Usando as opções de configuração, registramos a
apiKey
com bugsnag. - Finalmente, retornamos o objeto
bugsnag
, que pode ser usado para relatar os erros.
Para usar a vinculação Bugsnag, podemos aproveitar o método global use
.
const Bugsnag = use('Adonis/Src/Bugsnag')
Bugsnag.notify(new Error('Something went wrong'))
Com a ajuda do contêiner IoC, podemos abstrair o processo de configuração do Bugsnag e oferecer uma excelente API ao usuário final.
Métodos disponíveis
Abaixo está a lista de métodos disponíveis expostos pelo contêiner IoC.
use(namespace/alias)
Busca uma ligação usando seu namespace ou alias.
const Redis = use('Redis')
make(namespace/alias/class)
Retorna uma instância da classe injetando automaticamente as dependências do construtor.
class Book {
static get inject () { <1>
return ['App/Model/Book', 'Adonis/Addons/Mail']
}
constructor (BookModel, Mail) { <2>
this.BookModel = BookModel
this.Mail = Mail
}
}
const bookInstance = make(Book) <3>
- O getter estático
inject
retorna uma matriz de dependências a serem injetadas em sequência. - Todas as dependências especificadas são injetadas no construtor.
- Finalmente, usamos o método
make
para criar uma instância da classeBook
, que injeta automaticamente as dependências definidas.
alias(name, namespace)
Defina o alias para um determinado namespace.
const Ioc = require('adonis-fold').Ioc
Ioc.alias('UserModel', 'App/Model/User')
Provedores de serviço
Até agora, vinculamos manualmente as dependências ao contêiner IoC usando o método bind
, mas não temos certeza de onde escrever esse código e como estruturar as vinculações. Os provedores de serviço fornecem uma interface amigável para registrar as vinculações ao contêiner IoC.
OBSERVAÇÃO
Sempre certifique-se de dar nomes exclusivos às suas vinculações. Por exemplo: Adonis usa Adonis/Src/<ModuleName>
para as vinculações principais e Adonis/Addons/<ModuleName>
para complementos primários. Considere sufixar provedores com o nome da sua empresa.
Um Service Provider é uma classe ES2015
e suporta dois métodos para registrar as ligações e inicializar o estado inicial do provedor. Por exemplo:
const ServiceProvider = require('adonis-fold').ServiceProvider
class BugSnagProvider extends ServiceProvider {
* register () { <1>
this.app.bind('Adonis/Addons/BugSnag', (app) => {
const BugSnag = require('./BugSnag')
const Config = app.use('Adonis/Src/Config')
return new BugSnag(Config)
})
}
* boot () { <2>
// Tudo está registrado para algum trabalho duro
}
}
- O método
register
é usado para registrar ligações no contêiner IoC. Além disso, você podeusar
outras ligações do contêiner IoC usando seu namespace. - O método
boot
é chamado quando todos os provedores foram registrados. O que significa que você pode fazer um trabalho pesado dentro deste método para inicializar seu provedor. Além disso, este método não é necessário para todos os provedores e só o implementa quando seu provedor precisa ser inicializado.
Eventos
Abaixo está a lista de eventos disparados pelo contêiner IoC.
const Ioc = require('adonis-fold').Ioc
Ioc.on('bind:provider', (namespace, isSingleton) => {
// Vinculo registrado
})
Ioc.on('provider:resolved', (namespace, returnValue) => {
// Vinculo resolvido
})
Ioc.on('module:resolved', (namespace, fromPath, returnValue) => {
// módulo autocarregado resolvido
})
Ioc.on('extend:provider', (key, namespace) => {
// um provedor foi estendido
})
Ioc.on('bind:autoload', (namespace, directoryPath) => {
// namespace e diretório de carregamento automático definidos
})
Ioc.on('bind:alias', (alias, namespace) => {
// um alias foi registrado
})
Ioc.on('providers:registered', () => {
// todos os provedores foram registrados
})
Ioc.on('providers:booted', () => {
// todos os provedores foram inicializados
})