O que o framework Spring faz? Devo usá-lo? Por que ou por que não?

237

Então, estou iniciando um projeto totalmente novo em Java e estou pensando em usar o Spring. Por que estou considerando a primavera? Porque muitas pessoas me dizem que eu deveria usar o Spring! Sério, sempre que tentei fazer com que as pessoas explicassem exatamente o que é Spring ou o que faz, elas nunca podem me dar uma resposta direta. Eu verifiquei as introduções no site SpringSource, e elas são realmente complicadas ou realmente focadas em tutoriais, e nenhuma delas me dá uma boa idéia de por que devo usá-la ou de como facilitará minha vida. Às vezes, as pessoas usam o termo "injeção de dependência", o que me confunde ainda mais, porque acho que tenho uma compreensão diferente do que esse termo significa.

Enfim, aqui está um pouco sobre meu histórico e meu aplicativo:

Desenvolvo em Java há algum tempo, desenvolvendo back-end na web. Sim, faço muitos testes de unidade. Para facilitar isso, normalmente faço (pelo menos) duas versões de um método: uma que usa variáveis ​​de instância e outra que usa somente variáveis ​​que são passadas para o método. O que usa variáveis ​​de instância chama o outro, fornecendo as variáveis ​​de instância. Quando chega a hora do teste de unidade, eu uso o Mockito para simular os objetos e depois faço chamadas para o método que não usa variáveis ​​de instância. Isso é o que eu sempre entendi como "injeção de dependência".

Meu aplicativo é bem simples, da perspectiva do CS. Pequeno projeto, 1-2 desenvolvedores para começar. Principalmente operações do tipo CRUD com um monte de pesquisas ativadas. Basicamente, um monte de serviços web RESTful, mais um front-end da web e, eventualmente, alguns clientes móveis. Estou pensando em fazer o front-end em HTML / CSS / JS / JQuery direto, então não há planos reais para usar o JSP. Usando o Hibernate como um ORM e Jersey para implementar os serviços da web.

Eu já comecei a codificar e estou realmente ansioso para obter uma demonstração por aí que eu possa comprar e ver se alguém quer investir. Então, obviamente, o tempo é essencial. Eu entendo que o Spring tem bastante curva de aprendizado, além de parecer que precisa de um monte de configurações XML, o que eu normalmente tento evitar como uma praga. Mas se isso pode facilitar minha vida e (especialmente) se isso pode tornar o desenvolvimento e os testes mais rápidos, estou disposto a morder a bala e aprender o Spring.

Então por favor. Eduque-me. Devo usar o Spring? Por que ou por que não?

sangfroid
fonte
10
Eu acho que você realmente precisa experimentá-lo por um tempo para ver se gosta e se é adequado para o seu projeto. Pessoalmente, eu odeio isso.
Richard
1
Enquanto você pode usar XML ou anotações; tenha em mente que o Spring faz uma convenção sobre a mentalidade de configuração. Não é necessariamente uma lista de itens que você precisa endereçar.
Aaron McIver
14
Embora seja verdade que essa questão seja bastante ampla, acho que ela deve permanecer aberta. Eu li como "Quais benefícios o Spring oferece para um projeto de tamanho médio?", E essa é uma boa pergunta.
sleske
1
Eu recomendo a leitura do meu livro técnico favorito: Spring in Action, Third Edition by Craig Walls. É uma ótima leitura e mudará a maneira como você programa.
alfredaday
4
Considerando Java Enterprise, é mais fácil de responder o que Primavera não faz ...
m3th0dman

Respostas:

108

O que o framework Spring faz? Devo usá-lo? Por que ou por que não?

O Spring é uma estrutura que ajuda você a "conectar" diferentes componentes. É mais útil nos casos em que você possui muitos componentes e pode optar por combiná-los de maneiras diferentes, ou deseja facilitar a troca de um componente por outro, dependendo das diferentes configurações ou ambientes.

Isso é o que eu sempre entendi como "injeção de dependência".

Eu sugeriria uma definição diferente:

"Projete seus objetos para que eles confiem em uma força externa para fornecê-los o que precisam, com a expectativa de que essas dependências sejam sempre injetadas antes que alguém lhes peça para começar a fazer seus trabalhos habituais".

Compare isso com o seguinte: "Cada objeto é responsável por sair e encontrar tudo e todos que precisa ao iniciar."

parece que precisa de um monte de configuração XML

Bem, a maioria das coisas XML (ou baseadas em anotações) diz coisas da Spring, como:

  • Quando alguém pede "HammerStore", quero que você crie uma instância example.HammerStoree a retorne. Coloque em cache a instância para a próxima vez, pois só precisa haver uma loja.
  • Quando alguém pede "SomeHammer", quero que você se peça um "HammerStore" e retorne o resultado do makeHammer()método da loja . Você não armazenar em cache este resultado.
  • Quando alguém pede "SomeWrench", quero que você crie uma instância de example.WrenchImpl, Use a configuração gaugeAmounte coloque-a na setWrenchSize()propriedade da instância . Não armazene em cache o resultado.
  • Quando alguém pede "LocalPlumber", quero que você crie uma instância de example.PlumberImpl. Coloque a string "Pedro" em seu setName()método, coloque "SomeHammer" em seu setHammer()método e coloque "SomeWrench" em seu setWrench()método. Retorne o resultado e armazene em cache o resultado para mais tarde, pois precisamos apenas de um encanador.

Dessa forma, o Spring permite conectar componentes, rotulá-los, controlar seus ciclos de vida / cache e alterar o comportamento com base na configuração.

Para facilitar [testes], normalmente faço (pelo menos) duas versões de um método: uma que usa variáveis ​​de instância e outra que usa apenas variáveis ​​que são passadas para o método.

Isso parece muita sobrecarga, não traz muitos benefícios para mim. Em vez disso, faça com que as variáveis ​​da instância tenham protectedou visibilidade do pacote e localize os testes de unidade dentro do mesmo com.mycompany.whateverpacote. Dessa forma, você pode inspecionar e alterar as variáveis ​​da instância sempre que desejar durante o teste.

Darien
fonte
65

Primeiro, o que é injeção de dependência?

Simples. Você tem uma classe, ele possui um campo privado (definido como nulo) e declara um setter público que fornece o valor para esse campo. Em outras palavras, a dependência da classe (o campo) está sendo injetada por uma classe externa (via setter). É isso aí. Nada mágico.

Segundo, o Spring pode ser usado sem XML (ou muito pouco)

Se você se interessar pelo Spring 3.0.5.GA ou superior, poderá usar o suporte à injeção de dependência do JDK6 +. Isso significa que você pode conectar dependências usando as anotações @Componente @Resource.

Por que usar o Spring?

Obviamente, a injeção de dependência promove testes de unidade muito fáceis, pois todas as suas classes têm configuradores para as dependências importantes e elas podem ser facilmente zombadas usando sua estrutura de zombaria favorita para fornecer o comportamento necessário.

Além disso, o Spring também fornece muitos modelos que atuam como classes base para facilitar o trabalho com as tecnologias padrão JEE. Por exemplo, o JdbcTemplate funciona bem com o JDBC, o JpaTemplate faz boas coisas com o JPA, o JmsTemplate torna o JMS bastante simples. O RestTemplate é simplesmente incrível por sua simplicidade. Por exemplo:

RestTemplate restTemplate = new RestTemplate();
MyJaxbObject o = restTemplate.getForObject("https://secure.example.org/results/{param1}?param2={param2}",MyJaxbObject.class,"1","2");

e pronto. Os parâmetros são injetados e você só precisa fornecer anotações JAXB para MyJaxbObject. Isso não levará tempo se você os gerou automaticamente a partir de um XSD usando o plug-in Maven JAXB. Observe que não havia elenco acontecendo lá, nem havia a necessidade de declarar um delegado. Está tudo feito para você.

Eu poderia falar sobre as maravilhas do Spring para sempre, mas talvez a melhor coisa a fazer é tentar um pico de código simples, onde você tenta conectar um serviço da Web RESTful para extrair dados de um DAO injetado que suporta transações.

Gary Rowe
fonte
4
Sim, o RestTemplate é incrível. Eu tenho 100 linhas de código que posso jogar fora e substituir por 2-3 linhas.
Kevin
11
Para nitpick: Dependency Injection também inclui a abordagem baseada no construtor. Você não precisa necessariamente ter levantadores.
Darien
28

Antes de tudo, sua compreensão da injeção de dependência não é fundamentalmente errada, mas bastante diferente do que a maioria das pessoas quer dizer quando usa o termo. O que você descreve é ​​uma maneira bastante estranha e não convencional de obter testabilidade. Eu recomendo que você se afaste dele, pois outros desenvolvedores ficarão bastante intrigados com esse tipo de código.

A injeção de dependência, como geralmente é entendida (e implementada pelo Spring) significa que as dependências que uma classe possui (por exemplo, uma fonte de dados JDBC) não são buscadas pela própria classe, mas "injetadas" por um contêiner quando a instância é criada. Portanto, você não tem duas versões de todos os métodos que usam a fonte de dados; em vez disso, você tem uma configuração de injeção de dependência em que a fonte de dados "real" é injetada e outra em que uma simulação é injetada. Ou, se a injeção ocorrer por meio do construtor ou getter, o código de teste poderá fazer a injeção explicitamente.

Segundo, o Spring não é apenas injeção de dependência, embora essa seja sua principal funcionalidade. Ele também fornece transações declarativas, agendamento de tarefas, autenticação e várias outras funcionalidades (incluindo uma estrutura da Web MVC completa) que você pode precisar. Existem outras estruturas que fornecem a mesma funcionalidade, mas, além da Spring, apenas o Java EE as integra.

Michael Borgwardt
fonte
OP entende DI perfeitamente bem
Basilevs
19

Por que você deseja usar o Spring, você pode lê-lo em http://www.wrox.com/WileyCDA/Section/Why-Use-the-Spring-Framework-.id-130098.html

Em suma :

  • Os aplicativos J2EE tendem a conter quantidades excessivas de código "encanamento". Muitas revisões de código revelam repetidamente uma alta proporção de código que não faz nada: código de pesquisa JNDI, Transferir objetos, blocos try / catch para adquirir e liberar recursos JDBC. . . . Escrever e manter esse código de canalização prova uma grande perda de recursos que devem ser focados no domínio comercial do aplicativo.

  • Muitos aplicativos J2EE usam um modelo de objeto distribuído onde isso é inapropriado. Essa é uma das principais causas de código excessivo e duplicação de código. Também é conceitualmente errado em muitos casos; aplicativos distribuídos internamente são mais complexos que aplicativos co-localizados e geralmente com muito menos desempenho. Obviamente, se seus requisitos de negócios determinam uma arquitetura distribuída, você precisa implementar uma arquitetura distribuída e aceitar o compromisso que ocorre (e o Spring oferece recursos para ajudar em tais cenários). Mas você não deve fazê-lo sem uma razão convincente.

  • O modelo de componente EJB é indevidamente complexo. O EJB foi concebido como uma maneira de reduzir a complexidade ao implementar a lógica de negócios em aplicativos J2EE; não conseguiu esse objetivo na prática.

  • O EJB está em uso excessivo. O EJB foi desenvolvido essencialmente para aplicativos transacionais distribuídos internamente. Embora quase todos os aplicativos não triviais sejam transacionais, a distribuição não deve ser incorporada ao modelo de componente básico.

  • Muitos "padrões de design J2EE" não são, de fato, padrões de design, mas soluções alternativas para limitações de tecnologia. O uso excessivo da distribuição e o uso de APIs complexas, como EJB, geraram muitos padrões de design questionáveis; é importante examiná-las criticamente e procurar abordagens mais simples e produtivas.

  • Os aplicativos J2EE são difíceis de testar na unidade. As APIs J2EE e, principalmente, o modelo de componente EJB, foram definidas antes da decolagem do movimento ágil. Portanto, seu design não leva em consideração a facilidade de teste de unidade. Por meio de APIs e contratos implícitos, é surpreendentemente difícil testar aplicativos com base no EJB e em muitas outras APIs J2EE fora de um servidor de aplicativos. No entanto, o teste de unidade fora de um servidor de aplicativos é essencial para obter alta cobertura de teste e reproduzir muitos cenários de falha, como perda de conectividade com um banco de dados. Também é vital garantir que os testes possam ser executados rapidamente durante o processo de desenvolvimento ou manutenção, minimizando o tempo improdutivo aguardando a reimplantação.

  • Certas tecnologias J2EE simplesmente falharam. O principal ofensor aqui são os beans de entidade, que provaram ser pouco desastrosos para a produtividade e em suas restrições à orientação a objetos.

Rudy
fonte
13

Costumávamos escrever aplicativos e serviços da Web simples, eficientes e rápidos usando apenas Java, Servlets e JSP, html e xml, API JDBC. Foi bom o suficiente; JUnit foi uma boa ferramenta para testar. Descansamos tranqüilamente que nosso código funcionasse.

O Hibernate surgiu para simplificar o SQL e permitir o mapeamento verdadeiro das tabelas do banco de dados com objetos Java, permitindo que os relacionamentos hierárquicos sejam refletidos no Mapeamento de Relações com Objetos ou ORM, como chamamos. Eu amei. Especialmente porque não tivemos que mapear o ResultSet de volta para um objeto ou tipo de dados Java.

O Struts veio para adicionar o padrão Model View Controller aos nossos aplicativos da Web, foi bom.

Os EJBs eram uma sobrecarga enorme, e as anotações e as anotações faziam o código parecer um arranhão de galinha e agora a Spring surgiu sobre nós, gente inocente. Parece exagero para mim.

Por exemplo, agora empacotamos nossa url simples do jdbc, user, passamos primeiro para o jdbc.properties, depois para as propriedades de hibernação e depois para o Spring beans pela terceira vez!

Antes de tudo isso, considere obter uma conexão onde você precisa, é realmente tão simples como mostrado abaixo em java puro, que é o que realmente estamos fazendo depois de analisar todas essas coisas de ar quente com o Spring:

Connection connection = DriverManager.getConnection(url, user, pass);

Isso é, por si só, autoexplicativo: é uma grande rodada e uma repetição para fazer uma coisa simples de maneira rápida e fácil, sem outros grandes benefícios. É como embrulhar toneladas e toneladas de papel de presente em torno de um pequeno presente agradável, que é tudo o que você realmente guarda de qualquer maneira.

Outro exemplo é uma atualização em lote. Com o Spring, ele envolve várias classes e interfaces antes de você poder usar o JdbcTemplate para fazer uma atualização em lote. Com o jdbc simples, é simplesmente:

Statement statement = connection.createStatement();
statement.addBatch(sqlquery);
statement.executeBatch();

Não é possível ficar mais simples ou mais rápido que isso.

Eu não apoio esse quadro. Desculpa. Quem na terra quer injeções toda vez que precisa de alguma coisa?

Uma
fonte
6
esse código é simples, mas onde está definido o tratamento da sua transcessão e como você o testa? Ambas as coisas são simplificadas na primavera. Além disso, seu código java está diretamente vinculado a uma conexão db, a menos que você armazene URLs e senhas de conexão externamente, isso também será simplificado na primavera.
NimChimpsky 21/10/12
+1 para esta resposta, para abordar o comentário acima, o homem usa seus próprios padrões de design leves (GOF), singleton para o pool de conexões, uma classe proxy que fornece sql (string) e valores (array) ao objeto de banco de dados (qual método , depende do método http), o dbobject manipula o pool de conexões, transações etc. executando a consulta seguida pela liberação. Um objeto é usado em todos os módulos, ninguém precisa de código excessivo da placa da caldeira. ponto de bônus com a configuração de testes de unidade na classe proxy e no dbobject.
precisa saber é o seguinte
Confira Spring-Data-JPA! Anote um pojo em uma entidade, implemente uma interface e defina assinaturas de métodos usando nomes razoáveis, como findHammerByWeight (), e o Spring implementa os métodos para você, fornecendo um repositório injetável que você pode usar em todas as outras classes de serviços ou controladores de negócios .
precisa saber é o seguinte
13

O que o framework Spring faz?

A primavera não é apenas hoje, o que era conhecido como uma estrutura simples, é um ecossistema completo.

Tópicos cobertos pelo ecossistema da primavera:

  • Spring Framework (por exemplo, injeção de dependência, AOP ...)

  • Spring Cloud

  • Dados da Primavera

  • Spring Security

  • Lote de Primavera

  • Spring Social

Veja aqui a cobertura completa do ecossistema. É possível escolher projetos de maneira que você possa usar o Google Guice for DI e, por exemplo, o Spring Security para lidar com assuntos relacionados à segurança. Você não precisa comprar todo o ecossistema.

O próprio framework Spring cobre hoje principalmente

  • Injeção de dependência

  • Programação Orientada a Aspectos, incluindo gerenciamento de transações declarativas da Spring

  • Aplicativo da Web Spring MVC e estrutura de serviço da Web RESTful

  • Suporte básico para JDBC, JPA, JMS

Fonte spring.io

Em geral, você poderia dizer que o Spring é uma coleção de padrões e práticas implementadas no código, que podem ajudar a melhorar ou acelerar o ciclo de desenvolvimento de aplicativos.

Pois o que é mais conhecido (a estrutura principal) são as suas capacidades no campo da injeção de dependência . A própria Spring possui o que é chamado de Inversão do contêiner de controle ou Short IoC Container ou ainda menor o contêiner (para o qual "spring" às vezes é usado como sinônimo).

O que é injeção de dependência?

Injeção de dependência significa que seu objeto recebe toda dependência de outros objetos por meio de um mecanismo externalizado.

Digamos, você tem um carro, da maneira típica, é implementado é:

public class Car {

    Engine e;

    public Car() { 
        e = new Engine(); 
    }

}

O objeto do carro depende de um motor. Uma vez que o motor é implementado como membro do automóvel, não pode ser trocado por, por exemplo, um motor de teste.

Agora a injeção de dependência entra em jogo:

public class Car {

    Engine e;

    public Car(Engine e) { 
        this.e = e; 
    }

}

Depois disso, você poderá trocar de mecanismo. O que você vê acima é chamado de injeção de construtor . Existem outros tipos como, por exemplo, injeção de setter ou injeção de método . Como o Spring ajuda você com isso? O Spring permite marcar componentes a serem injetados com a anotação @Autowirede faz a fiação do objeto injetado automaticamente - é provável que o componente que você deseja injetar tenha dependências. Os injetáveis ​​- por assim dizer - são marcados como@Component

public class Car {

    Engine e;

    @Autowired
    public Car(Engine e) { 
        this.e = e; 
    }

}

Mas esse é apenas um dos muitos recursos que a Spring tem a oferecer.

Devo usar o Spring? Por que ou por que não?

Como a primavera não é muito intrusiva e oferece muitos auxílios, você deve considerar o uso da primavera. Especialmente para novos projetos, o Spring Boot é muito atraente. start.spring.io oferece um fácil de usar point'n'click -interface para gerar um modelo de projeto para começar. É até possível usar curlpara recuperar um modelo:

curl start.spring.io

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

:: Spring Initializr ::  https://start.spring.io

This service generates quickstart projects that can be easily customized.
Possible customizations include a project's dependencies, Java version, and
build system or build structure. See below for further details.

The services uses a HAL based hypermedia format to expose a set of resources
to interact with. If you access this root resource requesting application/json
as media type the response will contain the following links:
+-----------------+-----------------------------------------+
| Rel             | Description                             |
+-----------------+-----------------------------------------+
| gradle-build    | Generate a Gradle build file            |
| gradle-project  | Generate a Gradle based project archive |
| maven-build     | Generate a Maven pom.xml                |
| maven-project * | Generate a Maven based project archive  |
+-----------------+-----------------------------------------+

...

Por outro lado, estruturas como spark ou dropwizard também oferecem um bom ponto de partida para a criação rápida de aplicativos da web.

Thomas Junk
fonte
1
Resposta muito informativa!
GOXR3PLUS
Resposta concordada, muito boa. OP, eu simpatizo com você. Também tive várias pessoas que me mostraram demos do Spring, onde "simplificam" o código adicionando um arquivo XML e duas camadas de indireção, para que possam chamar o construtor de uma classe :) Você realmente só precisa mergulhar ou ir a um apresentação muito boa e, eventualmente, torna-se claro que as vantagens e desvantagens são
Adam Hughes
4

É uma estrutura escrita em Java com várias coisas incluídas para tornar seu aplicativo Web funcional (por exemplo, suporte à internacionalização). Ele também fornece uma boa maneira de estruturar seu aplicativo em camadas. Use-o, você economizará muito tempo a longo prazo.

Um bom livro para aprender sobre o Spring é: Expert Spring MVC e Web Flow

Bernard
fonte