SeamFramework.orgCommunity Documentation
Interceptadores são um meio poderoso para capturar e separar preocupações ortogonais para a aplicação (e sistema de tipos). Qualquer interceptador é capaz de interceptar invocações de qualquer tipo Java. Isso os torna ideais para resolver questões técnicas, tais como gerenciamento de transação, segurança e registro de chamadas. No entanto, por natureza, interceptadores desconhecem a real semântica dos eventos que interceptam. Assim, interceptadores não são um instrumento adequado para a separação de questões relacionadas a negócios.
O contrário é verdadeiro para decoradores. Um decorador intercepta invocações apenas para uma determinada interface Java e, portanto, é ciente de toda a semântica que acompanha esta interface. Visto que decoradores implementam diretamente operações com regras de negócios, isto torna eles uma ferramenta perfeita para modelar alguns tipos de questões de negócios. Isto também significa que um decorador não tem a generalidade de um interceptador. Decoradores não são capazes de resolver questões técnicas que atravessam muitos tipos diferentes. Interceptadores e decoradores, ambora similares em muitos aspectos, são complementares. Vamos ver alguns casos onde decoradores são bem convenientes.
Suponha que temos uma interface que represente contas:
public interface Account {
public BigDecimal getBalance();
public User getOwner();
public void withdraw(BigDecimal amount);
public void deposit(BigDecimal amount);
}
Vários beans diferentes em nosso sistema implementam a interface Account
. No entanto, temos um requisito legal que, para qualquer tipo de conta, as grandes transações devem ser registadas pelo sistema em um registro (log) específico. Esse é um trabalho perfeito para um decorador.
Um decorador é um bean (possivelmente, até mesmo uma classe abstrata) que implementa o tipo que ele decora e é anotado com @Decorator
.
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
...
}
O decorador implementa os métodos do tipo decorado que ele deseja interceptar.
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Inject @Delegate @Any Account account;
@PersistenceContext EntityManager em;
public void withdraw(BigDecimal amount) {
...
}
public void deposit(BigDecimal amount);
...
}
}
Ao contrário de outros beans, um decorador pode ser uma classe abstrata. Portanto, se não há nada de especial que o decorador precisa fazer para um determinado método da interface decorada, você não precisa implementar esse método.
Interceptadores para um método são chamados antes dos decoradores que se aplicam a esse método.
Decoradores possuem um ponto de injeção especial, chamado de ponto de injeção delegado, com o mesmo tipo dos beans que eles decoram e a anotação @Delegate
. Deve haver exatamente um ponto de injeção delegado, que pode ser um parâmetro de construtor, um parâmetro de método inicializador ou um campo injetado.
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Inject @Delegate @Any Account account;
...
}
Um decorador é vinculado a qualquer bean que:
tenha o tipo do ponto de injeção delegado como um tipo de bean, e
tenha todos os qualificadores que estão declarados no ponto de injeção delegado.
Este ponto de injeção delegado especifica que o decorador está vinculado a todos os beans que implementam Account
:
@Inject @Delegate @Any Account account;
Um ponto de injeção delegado pode especificar qualquer número de anotações de qualificador. O decorador só será vinculado a beans com os mesmos qualificadores.
@Inject @Delegate @Foreign Account account;
O decorador pode invocar o objeto delegado, o que praticamente equivale a chamar InvocationContext.proceed()
a partir de um interceptador. A principal diferença é que o decorador pode invocar qualquer método de negócio sobre o objeto delegado.
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Inject @Delegate @Any Account account;
@PersistenceContext EntityManager em;
public void withdraw(BigDecimal amount) {
account.withdraw(amount);
if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
em.persist( new LoggedWithdrawl(amount) );
}
}
public void deposit(BigDecimal amount);
account.deposit(amount);
if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
em.persist( new LoggedDeposit(amount) );
}
}
}
Por padrão, todos decoradores estão desabilitados. Nós precisamos habilitar nosso decorador no descritor beans.xml
de um arquivo de beans. Esta ativação somente se aplica aos beans neste arquivo.
<beans
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<decorators>
<class
>org.mycompany.myapp.LargeTransactionDecorator</class>
</decorators>
</beans
>
Essa declaração tem o mesmo propósito para decoradores que a declaração <interceptors>
tem para os interceptadores:
isso possibilita-nos determinar a ordem total para todos os decoradores em nosso sistema, assegurando um comportamento determinístico, e
isso permite habilitarmos ou desabilitarmos as classes decoradas em tempo de implantação.