Quais são os benefícios dos contêineres de injeção de dependência?

104

Eu entendo os benefícios da injeção de dependência em si. Vamos pegar o Spring, por exemplo. Também entendo os benefícios de outros recursos do Spring, como AOP, auxiliares de diferentes tipos, etc. Estou apenas me perguntando quais são os benefícios da configuração XML, como:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

em comparação com o código Java simples, como:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

que é mais fácil de depurar, verificar o tempo de compilação e pode ser entendido por qualquer pessoa que conheça apenas java. Então, qual é o objetivo principal de uma estrutura de injeção de dependência? (ou um pedaço de código que mostra seus benefícios.)


ATUALIZAÇÃO:
Em caso de

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

Como o framework IoC pode adivinhar qual implementação de myService eu desejo que seja injetada, se houver mais de uma? Se houver apenas uma implementação de determinada interface e eu permitir que o contêiner IoC decida automaticamente por usá-la, ela será quebrada após o aparecimento de uma segunda implementação. E se houver intencionalmente apenas uma implementação possível de uma interface, você não precisa injetá-la.

Seria realmente interessante ver um pequeno pedaço de configuração para IoC que mostra seus benefícios. Eu uso o Spring há algum tempo e não posso fornecer esse exemplo. E posso mostrar linhas únicas que demonstram os benefícios do hibernate, dwr e outros frameworks que eu uso.


ATUALIZAÇÃO 2:
Eu percebo que a configuração IoC pode ser alterada sem recompilar. É realmente uma boa ideia? Posso entender quando alguém deseja alterar as credenciais do banco de dados sem recompilar - ele pode não ser desenvolvedor. Em sua prática, com que frequência outra pessoa que não seja o desenvolvedor altera a configuração do IoC? Acho que para os desenvolvedores não há esforço para recompilar essa classe em particular em vez de alterar a configuração. E para quem não é desenvolvedor, você provavelmente gostaria de tornar sua vida mais fácil e fornecer algum arquivo de configuração mais simples.


ATUALIZAÇÃO 3:

Configuração externa de mapeamento entre interfaces e suas implementações concretas

O que há de tão bom em torná-lo extenso? Você não torna todo o seu código externo, embora definitivamente possa - apenas coloque-o no arquivo ClassName.java.txt, leia e compile manualmente em tempo real - uau, você evitou a recompilação. Por que a compilação deve ser evitada ?!

Você economiza tempo de codificação porque fornece mapeamentos declarativamente, não em um código procedural

Eu entendo que às vezes a abordagem declarativa economiza tempo. Por exemplo, declaro apenas uma vez que um mapeamento entre uma propriedade de bean e uma coluna DB e o hibernate usa esse mapeamento ao carregar, salvar, construir SQL baseado em HSQL, etc. É aqui que funciona a abordagem declarativa. No caso do Spring (no meu exemplo), a declaração tinha mais linhas e tinha a mesma expressividade do código correspondente. Se houver um exemplo em que tal declaração seja mais curta do que o código - eu gostaria de ver.

O princípio de inversão de controle permite fácil teste de unidade porque você pode substituir implementações reais por falsas (como substituir o banco de dados SQL por um na memória)

Eu entendo os benefícios da inversão de controle (prefiro chamar o padrão de design discutido aqui como Injeção de Dependência, porque IoC é mais geral - existem muitos tipos de controle, e estamos invertendo apenas um deles - controle de inicialização). Eu estava perguntando por que alguém precisa de algo diferente de uma linguagem de programação para isso. Definitivamente, posso substituir implementações reais por falsas usando código. E esse código expressará a mesma coisa que configuração - ele apenas inicializará campos com valores falsos.

mary = new FakeFemale();

Eu entendo os benefícios do DI. Não entendo quais benefícios são adicionados pela configuração XML externa em comparação com a configuração de código que faz o mesmo. Não acho que a compilação deva ser evitada - eu compilo todos os dias e ainda estou vivo. Acho que a configuração do DI é um mau exemplo de abordagem declarativa. A declaração pode ser útil se for declarada uma vez E é usada muitas vezes de maneiras diferentes - como hibernate cfg, onde o mapeamento entre a propriedade do bean e a coluna DB é usado para salvar, carregar, construir consultas de pesquisa, etc. A configuração do Spring DI pode ser facilmente traduzida para configurando código, como no começo dessa pergunta, não pode? E é usado apenas para inicialização do bean, não é? O que significa que uma abordagem declarativa não acrescenta nada aqui, certo?

Quando declaro o mapeamento do hibernate, apenas dou algumas informações ao hibernate e ele funciona com base nelas - não digo a ele o que fazer. No caso de spring, minha declaração diz a spring exatamente o que fazer - então por que declarar, por que não simplesmente fazer?


ÚLTIMA ATUALIZAÇÃO:
Pessoal, muitas respostas estão me falando sobre injeção de dependência, o que SEI QUE É BOM. A questão é sobre o propósito da configuração de DI em vez de inicializar o código - tendo a pensar que a inicialização do código é mais curta e clara. A única resposta que recebi até agora à minha pergunta, é que evita a recompilação, quando a configuração muda. Acho que devo postar outra pergunta, porque é um grande segredo para mim, por que compilar deve ser evitado neste caso.

Pavel Feldman
fonte
21
Finalmente alguém teve a coragem de fazer esta pergunta. Por que você iria querer evitar a recompilação quando sua implementação muda ao custo de sacrificar (ou pelo menos degradar) a ferramenta / suporte IDE?
Christian Klauser
3
Parece que o título não está certo. O autor disse que os contêineres IOC estão bem, mas parece ter problemas com o uso de configuração XML em vez de configurar via código (e justo também). Eu sugeriria talvez "Quais são os benefícios de configurar contêineres IOC via XML ou outras abordagens sem código?"
Orion Edwards
Os exemplos @Orion que forneci (com masculino e feminino) não exigem nenhum contêiner IOC. Estou bem com o COI; usar o container, esteja ele configurado em XML ou não, ainda é uma questão em aberto para mim.
Pavel Feldman
@ Órion 2: Embora eu use alguma forma de IOC na maioria dos projetos, alguns deles se beneficiam do contêiner IOC tanto quanto se beneficiam do Contêiner de Atribuição de Variável ou Contêiner de Instrução If - apenas a linguagem costuma ser suficiente para mim. Não tenho problemas para recompilar projetos em que estou trabalhando e ter código de inicialização de dev / test / production convenientemente separado. Então, para mim, o título está bom.
Pavel Feldman
Eu vejo problemas com a amostra. Um dos princípios são os serviços de injeção, não os dados
Jacek Cz

Respostas:

40

Para mim, uma das principais razões para usar um IoC (e fazer uso de configuração externa) é em torno de duas áreas:

  • Testando
  • Manutenção de produção

Testando

Se você dividir seu teste em 3 cenários (o que é bastante normal no desenvolvimento em grande escala):

  1. Teste de unidade
  2. Teste de integração
  3. Teste de caixa preta

O que você vai querer fazer é para os dois últimos cenários de teste (Integração e Caixa Preta), não recompilar nenhuma parte do aplicativo.

Se algum de seus cenários de teste exigir que você altere a configuração (ou seja: use outro componente para simular uma integração bancária ou fazer uma carga de desempenho), isso pode ser facilmente tratado (isso vem com os benefícios de configurar o lado DI de um IoC embora.

Além disso, se o seu aplicativo for usado em vários sites (com servidor e configuração de componente diferente) ou tiver uma configuração de alteração no ambiente ao vivo, você pode usar os estágios posteriores de teste para verificar se o aplicativo lidará com essas alterações.

Produção

Como desenvolvedor, você não (e não deve) ter controle do ambiente de produção (em particular quando seu aplicativo está sendo distribuído para vários clientes ou sites separados), este para mim é o benefício real de usar um IoC e uma configuração externa , já que cabe ao suporte de infraestrutura / produção ajustar e ajustar o ambiente de produção sem ter que voltar aos desenvolvedores e por meio de teste (custo mais alto quando tudo o que eles querem fazer é mover um componente).

Resumo

Os principais benefícios da configuração externa de um IoC vêm de dar a outros (não desenvolvedores) o poder de configurar seu aplicativo. Em minha experiência, isso só é útil em um conjunto limitado de circunstâncias:

  • O aplicativo é distribuído para vários sites / clientes onde os ambientes serão diferentes.
  • Controle / entrada de desenvolvimento limitado sobre o ambiente de produção e configuração.
  • Cenários de teste.

Na prática, descobri que, mesmo ao desenvolver algo que você tem controle sobre o ambiente, ele será executado, com o tempo é melhor dar a outra pessoa os recursos para alterar a configuração:

  • Ao desenvolver você não sabe quando isso vai mudar (o aplicativo é tão útil que sua empresa vende para outra pessoa).
  • Não quero ficar preso em mudar o código toda vez que uma pequena mudança é solicitada que poderia ter sido resolvida pela instalação e uso de um bom modelo de configuração.

Nota: Aplicativo refere-se à solução completa (não apenas o executável), portanto, todos os arquivos necessários para que o aplicativo seja executado .

Edgar Catalán
fonte
14

A injeção de dependência é um estilo de codificação que tem suas raízes na observação de que a delegação de objeto é geralmente um padrão de design mais útil do que a herança de objeto (ou seja, o objeto tem-um relacionamento é mais útil do que o objeto é-um relacionamento). Um outro ingrediente é necessário, entretanto, para que o DI funcione, o de criar interfaces de objetos. Combinando esses dois poderosos padrões de projeto, os engenheiros de software perceberam rapidamente que podiam criar código flexível e fracamente acoplado e, assim, nasceu o conceito de injeção de dependência. No entanto, não foi até que a reflexão de objeto se tornou disponível em certas linguagens de alto nível que o DI realmente decolou. O componente de reflexão é fundamental para a maior parte de hoje '

Uma linguagem deve fornecer um bom suporte para técnicas normais de programação orientada a objetos, bem como suporte para interfaces de objetos e reflexão de objetos (por exemplo, Java e C #). Embora você possa construir programas usando padrões DI em sistemas C ++, sua falta de suporte a reflexão dentro da linguagem apropriada impede que ele ofereça suporte a servidores de aplicativos e outras plataformas DI e, portanto, limita a expressividade dos padrões DI.

Pontos fortes de um sistema construído usando padrões DI:

  1. O código DI é muito mais fácil de reutilizar, pois a funcionalidade 'dependente' é extrapolada em interfaces bem definidas, permitindo que objetos separados, cuja configuração seja tratada por uma plataforma de aplicativo adequada, sejam plugados em outros objetos à vontade.
  2. O código DI é muito mais fácil de testar. A funcionalidade expressa pelo objeto pode ser testada em uma caixa preta construindo objetos 'fictícios' que implementam as interfaces esperadas pela lógica do seu aplicativo.
  3. O código DI é mais flexível. É um código inatamente fracamente acoplado - ao extremo. Isso permite ao programador selecionar e escolher como os objetos são conectados com base exclusivamente em suas interfaces necessárias em uma extremidade e em suas interfaces expressas na outra.
  4. A configuração externa (Xml) de objetos DI significa que outras pessoas podem personalizar seu código em direções imprevistas.
  5. A configuração externa também é uma separação do padrão de interesse, pois todos os problemas de inicialização do objeto e gerenciamento de interdependência do objeto podem ser tratados pelo servidor de aplicativos.
  6. Observe que a configuração externa não é necessária para usar o padrão DI, para interconexões simples, um pequeno objeto de construção geralmente é adequado. Há uma troca de flexibilidade entre os dois. Um objeto construtor não é uma opção tão flexível quanto um arquivo de configuração visível externamente. O desenvolvedor do sistema DI deve pesar as vantagens da flexibilidade sobre a conveniência, tomando cuidado para que o controle de pequena escala e granulação fina sobre a construção do objeto, conforme expresso em um arquivo de configuração, possa aumentar a confusão e os custos de manutenção no futuro.

Definitivamente, o código DI parece mais complicado, as desvantagens de ter todos aqueles arquivos XML que configuram objetos a serem injetados em outros objetos parecem difíceis. Este é, no entanto, o ponto dos sistemas DI. Sua capacidade de misturar e combinar objetos de código como uma série de definições de configuração permite que você crie sistemas complexos usando código de terceiros com o mínimo de codificação de sua parte.

O exemplo fornecido na pergunta apenas toca na superfície do poder expressivo que uma biblioteca de objetos de DI devidamente fatorada pode fornecer. Com alguma prática e muita autodisciplina, a maioria dos praticantes de DI descobrem que podem construir sistemas que tenham 100% de cobertura de teste do código do aplicativo. Este único ponto é extraordinário. Isso não é 100% de cobertura de teste de um pequeno aplicativo de algumas centenas de linhas de código, mas 100% de cobertura de teste de aplicativos compreendendo centenas de milhares de linhas de código. Não consigo descrever qualquer outro padrão de design que forneça este nível de testabilidade.

Você está correto ao dizer que uma aplicação de meros 10s de linhas de código é mais fácil de entender do que vários objetos mais uma série de arquivos de configuração XML. No entanto, como acontece com os padrões de projeto mais poderosos, os ganhos são encontrados à medida que você continua a adicionar novos recursos ao sistema.

Resumindo, os aplicativos baseados em DI em grande escala são mais fáceis de depurar e de entender. Embora a configuração do Xml não seja 'verificada no tempo de compilação', todos os serviços de aplicativo dos quais este autor está ciente fornecerão mensagens de erro ao desenvolvedor se tentarem injetar um objeto com uma interface incompatível em outro objeto. E a maioria fornece um recurso de 'verificação' que cobre todas as configurações de objetos conhecidas. Isso é feito de forma fácil e rápida verificando se o objeto A a ser injetado implementa a interface exigida pelo objeto B para todas as injeções de objeto configuradas.

Kevin S.
fonte
4
entender os benefícios do DI. Não entendo quais benefícios são adicionados pela configuração XML externa em comparação com a configuração de código que faz o mesmo. Os benefícios que você mencionou são fornecidos pelo padrão de projeto DI. A questão era sobre os benefícios da configuração DI em comparação com o código de inicialização simples.
Pavel Feldman
> A configuração externa também é uma separação ... A separação da configuração é o coração do DI, o que é bom. E pode ser desabilitado usando o código de inicialização. O que o cfg adiciona em comparação com a inicialização do código? Para mim, parece que cada linha de cfg tem uma linha de código de inicialização correspondente.
Pavel Feldman
7

Esta é uma questão um pouco carregada, mas tendo a concordar que grandes quantidades de configuração xml não trazem muitos benefícios. Gosto que meus aplicativos sejam o mais leves possível em dependências, incluindo as estruturas pesadas.

Eles simplificam o código muitas vezes, mas também têm uma sobrecarga de complexidade que torna o rastreamento de problemas bastante difícil (eu vi esses problemas em primeira mão, e o Java direto seria muito mais confortável para mim).

Eu acho que depende um pouco do estilo e do que você se sente confortável ... você gosta de voar sua própria solução e tem a vantagem de conhecê-la de dentro para fora, ou aposta em soluções existentes que podem ser difíceis quando a configuração não é apenas certo? É tudo uma troca.

No entanto, a configuração XML é um pouco chata minha ... Tento evitá-la a todo custo.

Mike Stone
fonte
5

Sempre que você pode alterar seu código para dados, está dando um passo na direção certa.

Codificar qualquer coisa como dados significa que seu próprio código é mais geral e reutilizável. Também significa que seus dados podem ser especificados em uma linguagem que se adapte exatamente a eles.

Além disso, um arquivo XML pode ser lido em uma GUI ou alguma outra ferramenta e facilmente manipulado de forma pragmática. Como você faria isso com o exemplo de código?

Estou constantemente fatorando coisas que a maioria das pessoas implementaria como código em dados, isso torna o código que resta MUITO mais limpo. Acho inconcebível que as pessoas criem um menu em código em vez de dados - deve ser óbvio que fazer isso em código é simplesmente errado por causa do clichê.

Bill K
fonte
faz sentido, não pensei nisso nesta perspectiva
Pavel Feldman
7
por outro lado, as pessoas geralmente vão por outro caminho e tentam colocar lógica nos dados, o que significa que você acaba codificando seu aplicativo em uma linguagem de programação abaixo do padrão
Casebash,
@Casebash Esse é um ponto de vista interessante - eu ficaria extremamente interessado em um exemplo. Acho que qualquer coisa que eu puder mover para os dados ajuda. Eu também acho que se eu fizer exatamente o que você está dizendo, a linguagem é realmente melhorada porque é uma DSL - mas mesmo assim é necessária uma justificativa séria para criar uma linguagem inteiramente nova.
Bill K de
1
"Sempre que você pode alterar seu código para dados, está dando um passo na direção certa." Bem-vindo ao anti-padrão do Soft Coding.
Raedwald,
@Raedwald O que você está falando é a externalização, o que pode ser muito difícil se você não souber o que está fazendo (e a razão pela qual alguém incompetente tentou, falhou e chamou de anti-padrão). Exemplos mais positivos seriam injeção, iteradores , quase tudo com anotações, tudo que inicializa com matrizes. A maioria das grandes estruturas de programação são uma tentativa de separar as diferenças em seu código e combinar o que resta, conduzindo-o com algo que pode ser agrupado e gerenciado melhor.
Bill K,
3

A razão para usar um contêiner de DI é que você não precisa ter um bilhão de propriedades pré-configuradas em seu código que são simplesmente getters e setters. Você realmente deseja codificar todos aqueles com o novo X ()? Claro, você pode ter um padrão, mas o contêiner DI permite a criação de singletons, o que é extremamente fácil e permite que você se concentre nos detalhes do código, não na tarefa diversa de inicializá-lo.

Por exemplo, Spring permite que você implemente a interface InitializingBean e adicione um método afterPropertiesSet (você também pode especificar um "método init" para evitar o acoplamento de seu código ao Spring). Esses métodos permitirão que você garanta que qualquer interface especificada como um campo em sua instância de classe seja configurada corretamente na inicialização, e então você não precisa mais verificar seus getters e setters (assumindo que você permite que seus singletons permaneçam seguros para thread )

Além disso, é muito mais fácil fazer inicializações complexas com um contêiner de DI em vez de fazer você mesmo. Por exemplo, eu ajudo a usar o XFire (não o CeltiXFire, usamos apenas Java 1.4). O aplicativo usava Spring, mas infelizmente usava o mecanismo de configuração services.xml do XFire. Quando uma coleção de elementos precisava declarar que tinha ZERO ou mais instâncias em vez de UMA ou mais instâncias, tive que substituir alguns dos códigos XFire fornecidos para este serviço específico.

Existem certos padrões XFire definidos em seu esquema Spring beans. Portanto, se estivéssemos usando Spring para configurar os serviços, os beans poderiam ter sido usados. Em vez disso, o que aconteceu foi que tive que fornecer uma instância de uma classe específica no arquivo services.xml em vez de usar os beans. Para fazer isso, precisei fornecer o construtor e definir as referências declaradas na configuração do XFire. A mudança real que eu precisava fazer exigia que eu sobrecarregasse uma única classe.

Mas, graças ao arquivo services.xml, tive que criar quatro novas classes, definindo seus padrões de acordo com seus padrões nos arquivos de configuração do Spring em seus construtores. Se tivéssemos sido capazes de usar a configuração Spring, eu poderia apenas ter declarado:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

Em vez disso, parecia mais com isto:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

Portanto, o resultado líquido é que quatro classes Java adicionais, em sua maioria sem sentido, tiveram que ser adicionadas à base de código para atingir o efeito que uma classe adicional e algumas informações de contêiner de dependência simples alcançaram. Esta não é a "exceção que prova a regra", esta É a regra ... lidar com peculiaridades no código é muito mais claro quando as propriedades já são fornecidas em um contêiner de DI e você simplesmente as altera para se adequar a uma situação especial, o que acontece com mais frequência do que não.

MetroidFan2002
fonte
3

Eu tenho sua resposta

Obviamente, há compensações em cada abordagem, mas os arquivos de configuração XML externalizados são úteis para o desenvolvimento empresarial no qual os sistemas de construção são usados ​​para compilar o código e não o seu IDE. Usando o sistema de construção, você pode querer injetar certos valores em seu código - por exemplo, a versão da construção (que pode ser doloroso ter que atualizar manualmente cada vez que você compila). A dor é maior quando seu sistema de compilação puxa o código de algum sistema de controle de versão. Modificar valores simples em tempo de compilação exigiria que você altere um arquivo, confirme, compile e, em seguida, reverta a cada vez para cada alteração. Estas não são mudanças que você deseja comprometer em seu controle de versão.

Outros casos de uso úteis sobre o sistema de compilação e configurações externas:

  • injetar estilos / folhas de estilo para uma única base de código para diferentes compilações
  • injetar diferentes conjuntos de conteúdo dinâmico (ou referências a eles) para sua única base de código
  • injetar contexto de localização para diferentes compilações / clientes
  • alterar um URI de serviço da web para um servidor de backup (quando o principal cair)

Atualização: Todos os exemplos acima foram sobre coisas que não necessariamente requerem dependências de classes. Mas você pode facilmente construir casos em que um objeto complexo e automação são necessários - por exemplo:

  • Imagine que você tivesse um sistema no qual monitorasse o tráfego do seu site. Dependendo do número de usuários simultâneos, ele liga / desliga um mecanismo de registro. Talvez enquanto o mecanismo está desligado, um objeto stub é colocado em seu lugar.
  • Imagine que você tivesse um sistema de webconferência no qual, dependendo do número de usuários, você deseja trocar a capacidade de fazer P2P dependendo do número de participantes
badunk
fonte
+1 para destacar o aspecto empresarial logo no topo. Testar código legado mal escrito às vezes pode ser um pesadelo de dias.
Richard Le Mesurier
2

Você não precisa recompilar seu código cada vez que alterar algo na configuração. Isso simplificará a implantação e manutenção do programa. Por exemplo, você pode trocar um componente por outro com apenas 1 alteração no arquivo de configuração.

aku
fonte
desdobramento, desenvolvimento? provavelmente ... manutenção de implantação? provavelmente ... manutenção de código? Eu tendo a pensar não ... depurar por meio de frameworks tende a ser uma grande dor de cabeça, e pojos são muito mais fáceis de lidar nesse aspecto.
Mike Stone,
1
Mike, eu não disse nada sobre código. Todos nós sabemos que a configuração XML é uma merda :)
aku
Hmm .. com que frequência você muda componentes sem recompilar e para quê? Eu entendo que se alguém muda as credenciais do banco de dados e não deseja recompilar o programa - ele pode não ser aquele que o desenvolve. Mas eu mal posso imaginar alguém além do desenvolvedor mudando a configuração da mola
Pavel Feldman,
Pavel geralmente essa situação ocorre quando você precisa implantar o programa para centenas de clientes. Em tal situação, é muito mais fácil alterar a configuração em vez de implantar uma nova versão do produto. Você está certo ao dizer sobre devs. Normalmente, o desenvolvedor cria um novo cfg e o administrador o implanta.
aku
2

Você pode inserir uma nova implementação para namorada. Assim, uma nova fêmea pode ser injetada sem recompilar seu código.

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(O acima pressupõe que Feminino e HotFemale implementam a mesma interface de namorada)

Paul Whelan
fonte
Por que modificações lógicas sem recompilar são consideradas uma boa ideia?
Pavel Feldman
Eu definitivamente posso fazer HotFemale jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (jane); Portanto, a única diferença é que o cfg pode ser alterado sem recompilar? Parece ser uma resposta comum quando o Spring é discutido. Por quê?! Por que é bom evitar a compilação?
Pavel Feldman
Bem, posso testar o código melhor, posso simular o objeto feminino.
Paul Whelan,
@Pavel Feldman: porque se você já tem o app implantado no cliente fica mais fácil.
Andrei Rînea
1

No mundo .NET, a maioria das estruturas IoC fornece configuração XML e de código.

StructureMap e Ninject, por exemplo, usam interfaces fluentes para configurar contêineres. Você não está mais limitado a usar arquivos de configuração XML. Spring, que também existe no .NET, depende muito de arquivos XML, pois é sua interface de configuração principal histórica, mas ainda é possível configurar contêineres de forma programática.

Romain Verdier
fonte
É ótimo que eu finalmente possa usar o código para o que pretendia ser usado :) Mas por que eu preciso de outra coisa além da linguagem de programação para fazer essas coisas?
Pavel Feldman
Acho que é porque o XML permite mudanças em tempo de execução, ou pelo menos, mudanças na configuração sem ter que recompilar o projeto.
Romain Verdier,
1

Facilidade de combinar configurações parciais em uma configuração final completa.

Por exemplo, em aplicativos da web, o modelo, a visualização e os controladores são normalmente especificados em arquivos de configuração separados. Use a abordagem declarativa, você pode carregar, por exemplo:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

Ou carregue com uma IU diferente e alguns controladores extras:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

Fazer o mesmo no código requer uma infraestrutura para combinar configurações parciais. Não é impossível fazer no código, mas certamente é mais fácil de fazer usando uma estrutura IoC.

flicken
fonte
1

Freqüentemente, o ponto importante é quem está mudando a configuração depois que o programa foi escrito. Com a configuração no código, você assume implicitamente que a pessoa que o altera possui as mesmas habilidades e acesso ao código-fonte, etc., que o autor original tinha.

Em sistemas de produção, é muito prático extrair algum subconjunto de configurações (por exemplo, idade em seu exemplo) para o arquivo XML e permitir, por exemplo, o administrador do sistema ou pessoal de suporte para alterar o valor sem dar a eles o poder total sobre o código-fonte ou outras configurações - ou apenas para isolá-los das complexidades.

Miro A.
fonte
Esse é um ponto válido, mas a configuração da mola geralmente tende a ser bastante complexa. Embora seja fácil mudar de idade, sysadmin ainda tem que lidar com grandes arquivos xml que ele não precisa entender inteiramente. Não é melhor extrair a parte que deveria ser configurada em algo ainda mais simples, do que a configuração do Spring XML? Como arquivo de propriedades, com uma única linha "idade = 23" e não permite que o administrador altere outros detalhes, como nomes de classes, etc, que requerem conhecimento da estrutura interna do programa.
Pavel Feldman
Recentemente, estive trabalhando em um projeto que tinha uma mistura de código Java e XSLT. A equipe era uma mistura de pessoas fortes em Java (e talvez menos confortáveis ​​trabalhando com XML e XSLT); e pessoas que trabalhavam muito bem com XML e XSLT (e menos confortáveis ​​com Java). Como a configuração seria gerenciada pelo segundo grupo, fazia sentido usar Spring e ter configurações XML. Em outras palavras, o Spring resolveu um problema de divisão de trabalho na equipe. Não resolveu um problema "técnico"; no sentido de que a configuração poderia facilmente ter sido feita com o código Java.
Dawood ibn Kareem
Quando o 'pessoal de suporte' saberia algo sobre ter que alterar algumas classes sendo criadas dentro de um contêiner de injeção de dependência? Mesmo supondo que é trabalho de um desenvolvedor fazer isso?
Jimbo
Essa é exatamente a razão pela qual extrair os valores de configuração (por exemplo, URL do sistema com o qual você se integra) faz sentido: o pessoal de suporte edita o arquivo de propriedades ou (no pior caso) o arquivo XML, a classe Java compilada permanece a mesma.
Miro A.
1

Do ponto de vista da primavera, posso dar duas respostas.

Primeiro, a configuração XML não é a única maneira de definir a configuração. A maioria das coisas pode ser configurada usando anotações e as coisas que devem ser feitas com XML são a configuração do código que você não está escrevendo de qualquer maneira, como um pool de conexão que você está usando de uma biblioteca. Spring 3 inclui um método para definir a configuração de DI usando Java semelhante à configuração de DI enrolada à mão em seu exemplo. Portanto, usar Spring não significa que você precisa usar um arquivo de configuração baseado em XML.

Em segundo lugar, o Spring é muito mais do que apenas um framework de DI. Possui muitos outros recursos, incluindo gerenciamento de transações e AOP. A configuração Spring XML combina todos esses conceitos. Frequentemente, no mesmo arquivo de configuração, estou especificando dependências de bean, configurações de transação e adicionando beans com escopo de sessão que realmente manipulam usando AOP em segundo plano. Acho que a configuração XML oferece um lugar melhor para gerenciar todos esses recursos. Também sinto que a configuração baseada em anotação e a configuração XML aumentam melhor do que a configuração baseada em Java.

Mas eu vejo seu ponto e não há nada de errado em definir a configuração de injeção de dependência em Java. Normalmente faço isso em testes de unidade e quando estou trabalhando em um projeto pequeno o suficiente para não ter adicionado um framework DI. Normalmente não especifico a configuração em Java porque, para mim, esse é o tipo de código de encanamento que estou tentando evitar de escrever quando escolhi usar o Spring. No entanto, essa é uma preferência, não significa que a configuração XML seja superior à configuração baseada em Java.

David W Crook
fonte
0

Spring também possui um carregador de propriedades. Usamos este método para definir variáveis ​​que dependem do ambiente (por exemplo, desenvolvimento, teste, aceitação, produção, ...). Pode ser, por exemplo, a fila para ouvir.

Se não houver motivo para a alteração da propriedade, também não há motivo para configurá-la desta forma.

Jeroen Wyseur
fonte
0

Seu caso é muito simples e, portanto, não precisa de um container IoC (Inversion of Control) como o Spring. Por outro lado, quando você "programa para interfaces, não implementações" (o que é uma boa prática em OOP), você pode ter um código como este:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(observe que o tipo de myService é IService - uma interface, não uma implementação concreta). Agora pode ser útil deixar seu contêiner IoC fornecer automaticamente a instância concreta correta de IService durante a inicialização - quando você tem muitas interfaces e muitas implementações, pode ser complicado fazer isso manualmente. Os principais benefícios de um contêiner IoC (estrutura de injeção de dependência) são:

  • Configuração externa de mapeamento entre interfaces e suas implementações concretas
  • O contêiner IoC lida com alguns problemas complicados, como resolver gráficos de dependência complicados, gerenciar a vida útil do componente etc.
  • Você economiza tempo de codificação porque fornece mapeamentos declarativamente, não em um código procedural
  • O princípio de inversão de controle permite fácil teste de unidade porque você pode substituir implementações reais por falsas (como substituir o banco de dados SQL por um na memória)
Borek Bernard
fonte
0

A inicialização em um arquivo de configuração XML simplificará seu trabalho de depuração / adaptação com um cliente que tenha seu aplicativo implantado em seus computadores. (Porque não requer recompilação + substituição de arquivos binários)

Andrei Rînea
fonte
-2

Um dos motivos mais atraentes é o " princípio de Hollywood ": não ligue para nós, nós ligaremos para você. Um componente não é necessário para fazer pesquisas em outros componentes e serviços; em vez disso, eles são fornecidos automaticamente. Em Java, isso significa que não é mais necessário fazer pesquisas JNDI dentro do componente.

Também é muito mais fácil testar a unidade de um componente isoladamente: em vez de dar a ele uma implementação real dos componentes de que ele precisa, você simplesmente usa simulações (possivelmente geradas automaticamente).

jan.vdbergh
fonte
Esta resposta é sobre injeção de dependência. Eu sei o que é, eu sei que é bom e declaro isso claramente na primeira frase da pergunta. A questão era sobre os benefícios da configuração DI, em comparação com o código de inicialização simples.
Pavel Feldman
Realmente não responde à pergunta
Casebash de