BT

Disseminando conhecimento e inovação em desenvolvimento de software corporativo.

Contribuir

Tópicos

Escolha a região

Início Artigos O que há de novo no Spring 2.5: Parte 1

O que há de novo no Spring 2.5: Parte 1

Introdução

Desde a sua concepção, o Spring Framework tem focado consistentemente no objetivo de simplificar o desenvolvimento de aplicativos corporativos enquanto oferece soluções poderosas e não invasivas para problemas complexos. Com a versão 2.0 do Spring apenas a um ano atrás, esse tema avança para um novo nível. O suporte a XML Schema e namespaces custumizados reduzem a quantidade de configuração baseada em XML. Desenvolvedores que usam Java 5 ou maior podem se beneficiar de bibliotecas do Spring que exploram novas funcionalidades da linguagem como generics e annotations. A integração mais próxima com a expression language do AspectJ permite adicionar comportamento de forma não invasiva em determinados grupos de objetos gerenciados pelo Spring.

A recém lançada versão 2.5 do Spring segue com essa tendência oferecendo mais simplicidade e força com novas funcionalidades especialmente para aqueles que usam Java 5 ou maior. Essa funcionalidades incluem injeção de dependência através de annotations, auto-detecção de componentes do Spring no classpath utilizando annotations ao invés de XML, suporte a annotations para métodos de ciclo de vida, um novo modelo de web controller para mapear requisições para métodos anotados, suporte a JUnit 4 no framework de testes, novidades nos namespaces XML, e mais.

Esse artigo é o primeiro de uma série de três partes que explora essa novas funcionalidades. O artigo atual vai focar em configurações simplificadas e novas funcionalidades baseadas em annotations no núcleo do contexto de aplicação do Spring. O segundo artigo vai cobrir novas funcionalidades disponíveis na camada web, e o artigo final vai destacar funcionalidades adicionais disponíveis para integração e testes. A maioria dos exemplos descritos neste artigo são baseado no aplicativo de exemplo Spring PetClinic. Esse exemplo foi recentemente refatorado para servir de demonstração das últimas funcionalidades do Spring e está incluido na distribuição do Spring 2.5 que está disponível na página de Download do Spring Framework.. Veja o arquivo 'readme.txt' dentro do diretório 'samples/petclinic' para instruções de construir e implantar a aplicação PetClinic. Experimentando os recursos mostradas na aplicação PetClinic é provavelmente a melhor maneira de ficar mestre nas novas técnicas discutidas aqui.

Suporte do Spring à anotações da JSR-250

As 'Commons Annotations da Plataforma Java' foram introduzidas na versão 5 do Java EE e estão também incluídas out-of-the-box no Java SE a partir da versão 6. Em maio de 2006, a BEA Systems anunciou sua colaboração com a Interface21 em um projeto chamado Pitchfork que oferecia uma implementação do modelo de programação do Java EE 5 baseado em Spring incluindo suporte para as annotations da JSR-250 e as annotations do EJB 3 (JSR-220) para injeção, interceptação, e transações. A partir da versão 2.5, o Spring Framework core agora oferece suporte para as seguintes annotations da JSR-250:

  • @Resource
  • @PostConstruct
  • @PreDestroy

Com Spring essas annotations são suportadas em qualquer ambiente - com ou sem um servidor de aplicações - e até mesmo para testes de integração. Ativar esse suporte é somente questão de registrar um único Spring post-processor:

 class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"             /> 

A Annotation @Resource

A Anotação @Resource habilita a injeção de dependência de um "recurso nomeado". Sem um aplicativo Java EE, isso tipicamente se traduz a um objeto vinculado ao contexto JNDI. O Spring suporta o uso da Annotation @Resource para encontrar objetos através de lookups JNDI, mas por padrão, o objeto gerenciado pelo Spring cujo nome (bean name) for igual ao informado na annotations @Resource será injetado. No exemplo seguinte, o Spring vai passar uma referencia do objeto gerenciado de nome "dataSource" ao método setter anotado.

@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

Também é possível anotar um campo diretamente com @Resource. Se não se expor o método seter, o código fica mais conciso e também oferece o beneficío adicional de fortalecer a imutabilidade. Como demonstrado a seguir, a annotaion @Resource nem sequer precisa de um valor String explicito. Quando nada é informado, o nome do atributo será utilizado por padrão.

@Resource
private DataSource dataSource; // injeta o bean de nome 'dataSource'

Quando aplicado a um método setter, o nome padrão seria derivado da propriedade correspondente. Em outras palavras, um método chamado 'setDataSource' seria também para resolver a propriedade chamada 'dataSource'.

private DataSource dataSource;
@Resource
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

Ao utilizar @Resource sem um nome explícito informado, se nenhum objeto gerenciado pelo Spring for encontrado pelo nome padrão, o mecanismo de injeção irá retroceder para combinar pelo tipo-classe do objeto. Se houver exatamente um objeto gerenciado pelo Spring que for do mesmo tipo da dependência, então este será injetado. Essa funcionalidade pode ser disabilitada definindo a propriedade 'fallbackToDefaultTypeMatch' do CommonAnnotationBeanPostProcessor para "false" (é "true" por padrão).

 class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
name="fallbackToDefaultTypeMatch" value="false" />

Como mencionado acima, o Spring oferece suporte a lookups JNDI quando resolve dependências que estão anotadas com @Resource. Para forçar lookups JNDI diretos para todas as dependências anotadas com @Resource, defina propriedade 'alwaysUseJndiLookup' do CommonAnnotationBeanPostProcessor para 'true' (é 'false' por padrão).

 class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
name="alwaysUseJndiLookup" value="true" />

Aternativamente, para habilitar o lookup baseado em nomes JNDI globais especificados como 'resource-ref-mappings', informe o atributo 'mappedName' com a annotation @Resource. Mesmo quando o objeto alvo for na verdade um recurso JNDI, essa é a pratica recomendada para referenciar um objeto gerenciado pelo Spring provendo um nível indireto e portanto um pequeno grau de acoplamento. Com o namespace additions disponível desde o Spring 2.0, a definição de um bean que delega para o Spring o gerenciamento de lookups JNDI é trivial e conciso:

 id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"             /> 

A vantagem dessa abordagem é que o nível de indireção provê maior flexibilidade de deployment. Por exemplo, um ambiente de teste de sistema standalone não deveria precisar de um JNDI registry. Nesse caso, a seguinte alternativa de definição de bean poderia ser utilizada na configuração do sistema de teste:

 id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}" />

No exemplo acima as propriedades da conexão JDBC são solucionadas através de um arquivo de propriedades em que as chaves são iguais aos ${placeholder} tokens informados. Para isso acontecer basta registrar uma implementação do Spring BeanFactoryPostProcessor chamada PropertyPlaceholderConfigurer. Essa é uma técnica frequentemente utilizada para externalizar essas propriedades - geralmente aquelas que são específicas dos ambiente - que podem precisar ser alteradas com mais frequência do que o resto da configuração.

 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
name="location" value="classpath:jdbc.properties" />

Com a adição do namespace 'context' no Spring 2.5, uma alternativa mais concisa para a configuração da propriedade placeholder está disponível:

 location="classpath:jdbc.properties"             /> 

Anotações de ciclo de Vida: @PostConstruct e @PreDestroy

As anotações @PostConstruct e @PreDestroy podem ser usadas para disparar chamadas Spring de inicialização e destruição. Esse recurso extende mas não substituí as duas opções para oferecer essas chamadas nas versões do Spring anteriores a 2.5. A primeira opção é a implementação de uma ou ambas as interfaces InitializingBean e DisposableBean do Spring. Cada uma dessas interfaces requer a implementação de um única chamada de método (afterPropertiesSet() e destroy() respectivamente). A abordagem baseada em interfaces toma a vantagem da habilidade do Spring de automaticamente reconhecer qualquer objeto gerenciado pelo Spring implementando essas interfaces e portanto, não exige configuração adicional. Por outro lado, um objetivo chave do Spring é não ser tão invasivo o possível. Por isso, ao invés de implementar interfaces específicas do Spring, muitos usuários do Spring utilizam a segunda opção para prover seus próprios métodos de inicialização e destruição. Embora menos invasiva, a desvantagem dessa abordagem é que ela exige um declaração explícita dos atributos 'init-method' e/ou 'destroy-method' no elemento 'bean'. A configuração explícita as vezes é necessária, assim como, quando as chamadas precisam ser invocadas no código que está fora do controle do desenvolvedor. O aplicativo PetClinic demonstra esse cenário. Quando ele é executado com a configuração JDBC, um terceiro DataSource é utilizado, e o 'destroy-method' é declarado explicitamente. Note também que o standalone connection-pooling DataSource é uma ourtra opção de deployment para o 'datasource' e não necessita de nenhuma alteração de código.

 

 id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}" />

Com o Spring 2.5, se um objeto precisar invocar um método na sua inicialização, esse método pode ser anotado com a annotation @PostContruct. Por exemplo, imagine uma tarefa em background que precise iniciar o pooling de um diretório de arquivos em sua inicialização.

public class FilePoller {

@PostConstruct
public void startPolling() {
...
}
...
}

De forma semelhante, um método anotado com @PreDestroy em um objeto gerenciado pelo Spring seria invocado quando o contexto de aplicação deste objeto é encerrado.

public class FilePoller {

@PreDestroy
public void stopPolling() {
...
}
...
}

Com suporte às annoations da JSR-250, o Spring 2.5 agora combina as vantagens delas e de seus dois método de ciclo de vida anteriores. Adicionando @PostConstruct e @PreDestroy como annotations a nível de método é o suficiente para disparar chamadas em um contexto gerenciado pelo Spring. Em outras palavras, nenhuma configuração XML adicional é necessária. Ao mesmo tempo, as annotations são parte da própria linguagem Java (e inclusive fazem parte da versão 6 do Java SE) e então não necessitam de nenhum import específico do Spring. As annotations tem o beneficio adicional da semântica indicativa que deve ser ententida em outros ambientes, e ao longo do tempo os desenvolvedores Java pode esperar para ver ver essas annotations usadas mais frequentemente em bibliotecas terceiras. Finalmente, uma consequencia interessante do ciclo de vida baseado em annotations é que mais de apenas um método pode possuir cada annotation, e todos os métodos anotados serão invocados.

Para habilitar todo o comportamento descrito acima sobre as annotations @Resource, @Postcontruct e @PreDestroy, configure o CommonAnnotationBeanPostProcessordo Spring como demonstrado anteriormente. Uma opção ainda mais concisa é possível com o novo namespace 'context' do Spring 2.5:

 

Incluindo esse único elemento não apenas será registrado um CommonAnnotationBeanPostProcessor, mas também será habilitado o comportamento de autowiring (criação de componente pelo container) como será descrito na seção seguinte. O CommonAnnotationBeanPostProcessor também oferece suporte para as annotations @WebServiceRef e @EJB. Essas serão cobertas no terceiro artigo dessa série juntamente com outras novas funcionalidades do Spring 2.5 para integração enterprise.

Autowiring muito granular com Annotations

A documentação que cobre o suporte to Spring a autowiring tem sido frequentemente acompanhada com ressalvas devido a alta granularidade do mecanismo de autowiring. Antes do Spring 2.5, o autowiring podia ser configuardo por diferentes abordagens: construtoes, setters por tipo, setters pode nome, ou de forma automática (o Spring opta por construtor ou setter por tipo). Essas diversas opções possibilitam um amplo degrau de flexibilidade, porém nenhum deles oferece um controle refinado. Em outras palavas, antes do Spring 2.5, não era possivel o autowire de um subconjunto específico de um método setter de um objeto ou o autowire de algunas das suas propriedades por tipo e de outras por nome. Como resultado, muitos usuários do Spring tem reconhecido os beneficios do autowiring aplicado a construção de protótipos e testes, mas em se tratando de manutenção e suporte de sistema em produção, a maioria concorda que a verbosidade adicional da configuração explícita vale pela clareza que oferece.

No entanto, o Spring 2.5 muda drasticamente o cenário. Como descrito acima, as escolhas de autowiring agora foram ampliadas pelo suporte a annotation @Resource da JSR-250 para habilitar o autowiring de recursos nomeados, aplicados por método ou por atributo. No entanto, a annotation @Resource sozinha tem algumas limitações. Spring 2.5 portanto introduz a annotation Autowired para aumentar ainda mais o nível de controle. Habilitar o comportamento descrito nessa sessão, registrar uma única definição de bean:

 class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"             /> 

Alternativamente, o namespace 'context' oferece uma alternativa mais concisa do que a apresentada anteriormente. Isso habilitará ambos os post-processors discutidos neste arigo (o AutowiredAnnotationBeanPostProcessor e o CommonAnnotationBeanPostProcessor) assim como os annotation-based post-processors que foram introduzidos no Spring 2.0: RequiredAnnotationBeanPostProcessor e PersistenceAnnotationBeanPostProcessor.

 

Como a annotation @Autowired é possível injetar dependências que fazem 'match' pelo tipo. Esse comportamento é aplicado a atributos, constutores e métodos. De fato, métodos autowired não tem que ter métodos 'setter' e podem até mesmo aceitar multiplos parâmetros. O código seguinte é prefeitamente aceitável:

@Autowired
public void setup(DataSource dataSource, AnotherObject o) { ... }

Por padrão, as dependências marcadas com a annotation @Autowired são tratadas como obrigatórias. Entretanto, também é possível declará-las como opcionais definindo o atributo 'required'para 'false'. No exemplo seguinte, O DefaultStrategy será utilizado se nenhum objeto gerenciado pelo Spring do tipo SomeStrategy for encontrato no contexto.

@Autowired(required=false)
private SomeStrategy strategy = new DefaultStrategy();

O Autowiring por tipo pode obviamente resultar em ambiguidades quando o contexto do Spring contiver mair de um objeto do tipo esperado. Por padrão, o mecanismo de autorwing falhará se não houver exatamente um bean para uma dependência obrigatória. Assim como para qualquer propriedade opcional, ele falhará se mais um candidato estiver disponível (se opcional e nenhum candidado estiver disponível, então, ele simplesmente ingorará a propriedade). Há uma série de opções de configuração para evitar esses conflitos.

Quando há apenas uma instância principal de um determinado tipo no contexto, a definição do bean para esse tipo deve conter o atributo 'primary' (principal). Essa abordagem funciona bem quando outras instancias puderem estar disponíveis no contexto, as instancias não principais ainda são sempre configuradas explicitamente.

 id="dataSource" primary="true" ...              /> 

Quando um maior controle é preciso, qualquer campo autowired, argumento de construtor, ou parâmetro de método podem ainda ser anotados com a annotation @Qualifier. O qualificador poderia conter um valor String e o Spring tentaria comparar pelo nome.

 

@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource;

 

A principal razão para a existência da annotation @Qualifier com uma annotaion separada é que ela pode ser aplicada a um argumento de construtor ou a um parâmetro de método enquando a annotation @Autowired pode ser aplicada somente a seu construtor ou seu método.

@Autowired
public void setup(@Qualifier("primaryDataSource") DataSource dataSource, AnotherObject o) { ... }

O fato de que a annotation @Qualifier é separada oferece ainda mais benefícios considerando a customização. Annotations definidas pelo usuário podem também ser utilizadas com qualificadoras no processo de autowiring. A forma mais simples de fazer isso é anotar a annotation customizada @Qualifier como uma meta-annotation.

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface VetSpecialty { ... }

Annotations customizadas podem opcionalmente incluir um valor para comparar por nome, mas seria mais comum utilizá-las como um annotation marcadora ou definir um valor que ofereça algum outro significado ao processo de qualificação. Por exemplo, o trecho abaixo mostra um campo que deveria ser autowired com um candidato qualificado entre aqueles que fazem 'match' por tipo.

@Autowired
@VetSpecialty("dentistry")
private Clinic dentistryClinic;

Ao utilizar configuração XML para atingir a resolução dessa dependência, sub-elementos 'qualifier' podem ser adicionados a definição do bean. Na próxima sessão de component-scanning, uma alternativa não XML será apresentada.

 id="dentistryClinic" class="samples.DentistryClinic">
type="example.VetSpecialty" value="dentistry" />

Para evitar qualquer dependência em relção a qualquer annotation @Qualifier, defina o bean CustomAutowireConfigurerno contexto do Spring e registre qualquer tipo de Annotation diretamente:

 class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
name="customQualifierTypes">

example.VetSpecialty


Agora que o qualifier customizado foi explicitamente delcarado, a meta-anotation @Qualifier não é mais necessária.

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface VetSpecialty { ... }

A propósito, também é possível substituir a annotation @Autowired em si quando configurando o AutowiredAnnotationBeanPostProcessor.

 class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
name="autowiredAnnotationType" value="example.Injected" />

Na maioria dos casos, a habilidade de definir annotations macardoras customizadas combinada as opções de comparar por nome ou outro valor semântico deve ser suficiente para atigir um controle granular do processo de autowiring. Entretanto, O Spring também oferece suporte à qualquer numero de atributos arbitrários nas annotations qualifier. Veja um exemplo hipotético de um qualifier muito granular.

@SpecializedClinic(species="dog", breed="poodle")
private Clinic poodleClinic;

A implementação do qualificador customizado definiria esses atributos.

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface SpecializedClinic {

String species();

String breed();

}

Os atributos do qualificador customizado podem então ser comparados à 'atributos' de sub-elementos da annotation 'qualifier' através de uma definicação de bean no XML. Esses elementos são usados para oferecer pares chave/valor:

 id="poodleClinic" class="example.PoodleClinic">
type="example.SpecializedClinic">
key="species" value="dog" />
key="breed" value="poodle" />

Todos os autowiring demonstrados foram para única instância, mas collections também são suportadas. Qualquer hora que for necessário obter objetos gerenciados pelo Spring de um certo tipo com um contexto, simplesmente adicione a annotation @Autowired para uma Collection fortemente tipada.

@Autowired
private List allClinics;

Um recurso final que vale apena apresentar nesta seção é o uso de autowiring ao invés de interfaces "Aware" do Spring. Antes do Spring 2.5, se um objeto precisasse de uma referência para o ResourceLoader do contexto do Spring, ele podia implementar a interface ResourceLoaderAware assim permitindo que o Spring injetasse a depedência através do método setResourceLoader(ResourceLoader resourceLoader). A mesma técnica se aplica para obter uma referência do MessageSoruce gerenciado pelo Spring e até mesmo do ApplicationContext em si. Para usuários do Spring 2.5, esse comportamento é agora totalmente suportado por autowiring (perceba que a inclusão dessas dependências específicas do Spring devem ser sempre cuidadosamente consideradas e tipicamente são apenas usadas em código de infra-estrutura que é claramente separado da lógica de negócios).

@Autowired
private MessageSource messageSource;

@Autowired
private ResourceLoader resourceLoader;

@Autowired
private ApplicationContext applicationContext;

Auto-Detecção de Componentes Spring

Com inicio na versão 2.0, o Spring introduziu o conceito de annotations de "esteriótipo" com a annotation @Repository que serve para marcar código de acesso a dados. O Spring 2.5 adicionou duas novas annotations - @Service e @Controller - para completar a designação de papéis de uma arquitetura comum de três camadas (objetos de acesso a dados, serviços e controllers web). O Spring 2.5 também introduziu a annotation genérica @Component que é um outro esteriótipo logicamente extensível. Para indiciar mais claramente os papéis da aplicação, estes esteriótipos facilitam o uso dos post processors do Spring AOP oferecendo comportamento adicional aos objetos annotados baseado em seus papéis. Por exemplo, o Spring 2.0 introduziu a PersistenceExceptionTranslationPostProcessorque automaticamente habilita a tradução da exeção de acesso a dados para qualquer objeto que contenha a annotation @Repository.

Essas mesmas annotations podem também ser usados em conjunto com outra funcionalidade do Spring 2.5: a detecção automática de componentes no classpath. No entanto, XML tem sido tradicionalmente a forma mais popular para metadados do Spring, mas não é a única opção. De fato, a representação interna dos metadados do Spring container é puro Java, e quando o XML é usado para definir os objetos gerenciados pelo Spring, essas definições são convertidas para objetos Java para o processo de instanciação. Uma nova habilidade significante do Spring 2.5 é o suporte a leitura de metadados a partir de annottaions em nível de código. Os mecanismos de autowiring descritos então fazem uso dos metadados para injetar dependencias, mas ainda requerem registro ao menos no nível um definição mínima de bean para oferecer a classe de implementação para cada objeto gerenciado pelo Spring. A funcionalidade de escanear componente pode acabar com a necessidade até de mesmo de definições mínimas de beans em XML.

Como visto acima, o autowiring dirigido por annotations do Spring, pode reduzir significativamente a quantidade de XML sem sacrificar o controle de granularidade fina. O mecanismo de detecção de componentes leva isso mais adiante. Não é absolutamente necessário fazer a configuração em XML, uma vez que a varredura de componente pode operar paralelamente ao metadado de XML para simplificar a configuração global. Isso possibilita que combinação de XML e técnicas dirigidas a anotações podem levar a uma abordagem equilibrada, bem como demonstrada pela versão 2.5 da aplicação PetClinic. Lá, os componentes de infra-estrutura (data source, transaction manager, etc) são também definidos em XML, mas suas configurações também leva a vantagem da anotação @Autowired para simplificar a injeção de dependências. Finalmente, a camada de "controllers" não é explicitamente definida em XML como um todo. Ao invés disso a seguinte configuração é usada para disparar a auto-detecção de todos controllers web:

 base-package="org.springframework.samples.petclinic.web"             /> 

Perceba que o atributo 'base-package' é informado. O valor default das regras de combinação para a varredura do componente irá recursivamente detectar qualquer uma das annotations de esteriótipo do Spring nas classes do pacote (vários pacotes podem ser informados em uma lista separada por virgulas). Então, as várias implementações de controllers no aplicativo de exemplo PetClinic estão todas com a annotation @Controller (Um dos esteriotipos pré-definidos do Spring). Aqui tem um exemplo:

@Controller
public class ClinicController {

private final Clinic clinic;

@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
...

Componentes auto-detectados são registrados com o container Spring simplesmente se eles foram definidos em XML. Tal como descrito acima, esses objetos podem, por sua vez, fazer uso de autowiring dirigido a anotações.

A regra de varredura de componentes pode também ser customizadas com filtros para inclusão e exclusão de componentes baseado no tipo, anotação, expressão AspectJ, ou expressão regular para buscar nomes. O esteriótipo padrão pode também ser desabilitado. Por exemplo, uma configuração de teste pode ignorar o esteriótipo padrão em vez de auto-detectar qualquer classe o qual o nome começa com Stub ou que tenha a anotação @Mock:

 base-package="example" use-default-filters="false">
type="aspectj" expression="example..Stub*" />
type="annotation" expression="example.Mock" />

Restrições de 'match' de tipo podem ser controladas com filtros de exclusão. Por exemplo, para invocar filtros padrões exceto para a anotação @Repository, adicione um exclude-filter.

 base-package="example">
type="annotation" expression="org.springframework.stereotype.Repository" />

É claro que é possível extender a varredura do componente em inúmeras maneiras para registrar deu próprio tipo customizado. As anotações de esteriótipo são as opções mais simples, então a noção de esteriótipo, portanto, pode se extender. Como mencionado anteriormente, @Component é o indicador de esteriótipo genérico que as anotações @Repository, @Service, e @Controller "logicamente" extende. Isso então simplesmente acontece e qualquer anotação customizada que a meta-anotação @Component será automaticamente detectada pela regra padrão de 'matching' de varredura. Um exemplo revelará que é muito mais simples do que parece.

Voltando a tarefa hipotética de segundo plano, que foi descrita na sessão acima cobrindo o ciclo de vida das anotações @PostConstruct e @PreDestroy. Talvez um aplicativo tenha um número de tarefas de segundo plano, e aquelas instâncias de tarefas tipicamente irão requerer uma definição de bean no XML a fim de ser registrada com o contexto Spring e ter seus métodos de ciclo de vida invocados no tempo certo. Com a varredura de componentes, não existe uma necessidade para aquelas definições explicitas de bean no XML. Se todas as tarefas de segundo plano implementam a mesma interface ou seguem uma convensão de nome, em seguida podem ser usados. Contudo, uma abordagem ainda mais simples é criar uma anotação para essa tarefa de objeto e formecer a meta-anotação @Component

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BackgroundTask {
String value() default "";
}

Em seguida forneceer uma anotação de esteriótipo customizada em qualquer definição de classe da tarefa de segundo plano.

@BackgroundTask
public class FilePoller {

@PostConstruct
public void startPolling() {
...
}

@PreDestroy
public void stopPolling() {
...
}
...
}

A anotação @Conponent genérica poderia poderia simplesmente ter sido fornecida, mas ao invés disso a técnica de anotação customizada fornece uma oportunidade para utilização de significado, nomes de domínio. Essas anotações de domínio em seguida fornecem novas oportunidades como usar uma expressão pointcut de AspectJ para identificar todas tarefas de segundo plano para o propósito de adicionar avisos que monitorem a atividade dessas tarefas.

Por padrão. quando um componente é detectado, o Spring irá gerar automaticamente um "bean name" usando o nome da classe não qualificado. No exemplo anterior, o nome do bean gerado será "filePoller". Entretanto, para qualquer classe que é anotada com uma das anotações de esterióripo (@Component, @Repository, @Service, ou @Controller) que é anotada com @Conponent como uma meta-anotação (semelhante a @BackgroundTask no exemplo acima), o atributo 'value' pode ser especificado explicitamente para a anotação de esteriótipo, e a instancia irá em seguida ser registrada dentro do contexto com value como o "bean name". No próximo exemplo o nome será 'petClinic' ao invés do nome padrão gerado "simpleJdbcClinic".

@Service("petClinic")
public class SimpleJdbcClinic {
...
}

 

@BackgroundTask("poller")
public class FilePoller {
...
}

Embora todos objetos gerenciados pelo Spring são tratados como instancias singleton por padrão, é algo necessário especificar um escopo alternativo para um objeto. Por exemplo, na camada web um objeto gerenciado pelo Spring pode ser vinculado ao escopo de 'request' ou 'session'. Como na versão 2.0, o escopo do Spring é tão extensível que escopos customizados podem ser registrados com o contexto de aplicação (application context). Em uma configuração de XML, é simplesmente uma questão de incluir o atributo de 'scopo' e o nome do escopo.

 id="shoppingCart" class="example.ShoppingCart" scope="session">
...

Com Spring 2.5, o mesmo pode ser realizado por um componente varrido pela anotação @Scope fornecida.

@Component
@Scope("session")
public class ShoppingCart {
...
}

Um tópico final a resolver aqui é a simplificação da anotação qualificada quando usado a varredura de componente. Na sessão anterior, o seguinte objeto foi usado como um exemplo de autowiring com uma anotação customizada:

@VetSpecialty("dentistry")
private Clinic dentistryClinic;

O mesmo exemplo do uso de um 'qualifier' na definição do bean alvo pretendido para essa dependência. Quando usado varredura de componente, o metadado XML não é necessário. Ao invés disso, o qualificador customizado pode ser incluído como uma anotação de nível de tipo no alvo da definição de classe. Um exemplo alternativo com uma instância @Repository varrida como a dependência, irá então aparecer como o seguinte:

@Repository
@VetSpecialty("dentistry")
public class DentistryClinic implements Clinic {
...
}

Finalmente, para o exemplo que apresentou o annotations de qualificação customizada com atributos, o exemplo sem XML equivante para a dependência seria:

@Repository
@SpecializedClinic(species="dog", breed="poodle")
public class PoodleClinic implements Clinic {
...
}

Conclusão

Spring 2.5 oferece novas funcionalidades significantes em diversas áreas. O foco principal deste artigo foi em simplificar a configuração através do aproveitamento do poder das annotations do Java. O Spring suporta 'Common Annotations' como definido na JSR-250 enquando prove annotations adicionais para um controle mais granular do processo de autowiring. O Spring 2.5 também extende as annotations de 'esteriótipo' que começaram com a @Repository do Spring 2.0, e todos os esteriótipos podem ser usados em cojunto com a nova funcionalidade de varredura de componente. A configuração por XML ainda é totalmente suportada, e o Spring 2.5 introduziu um novo namespace 'context' que oferece uma sintaxe mais concisa para os cenários de configuração mais comuns. De fato, o suporte a combinação de configuração por XML e annotations permite uma abordagem, em geral, bem equilibrada. Configurações complexas de infra-estrutura podem ser definidas em arquivos de XML modulares enquanto progressivamente camadas mais altas da pilha da aplicação pode beneficiar-se mais de tecnicas baseadas em annotations - tudo com o mesmo contexto de aplicação Spring 2.5.

Fique ligado no próximo artigo dessa serie, em que cobriremos as poderosas novas funcionalidades baseadas em annotations de camada web do Spring.

 

 

 

 

 

 

 

 

 

Avalie esse artigo

Relevância
Estilo/Redação

Conteúdo educacional

BT