Considerações sobre o Design do Aplicativo Asynchronous Request Dispatcher
ARD (Asynchronous Request Dispatcher) não é uma solução única para a programação de servlet. É necessário avaliar as necessidades de seu aplicativo e os cuidados de uso do ARD. Alternar todas as inclusões para iniciar de forma assíncrona não é a solução para os cenários, mas, quando utilizado prudentemente, o ARD pode aumentar o tempo de resposta.
Implementação do Asynchronous Request Dispatcher do Lado do Cliente
- JavaScript é gravado dinamicamente na saída da resposta.
- Este JavaScript resulta em pedidos de Ajax retornados a um provedor de resultados do lado do servidor.
- Devido aos recursos de entrada/saída assíncrona (AIO) do canal, a solicitação de Ajax não liga um encadeamento e, em vez disso, é notificado para conclusão por meio de um retorno de chamada de inclusão.
- O cliente só faz uma solicitação de cada vez para as inclusões assíncronas por causa das limitações do navegador no número de conexões.
- A conexão original deve ser válida para o tempo de vida das inclusões. Ela não pode ser reutilizada para os pedidos de Ajax.
- Nós de comentário, como os seguintes,
são colocados no modelo de objeto do navegador, uma vez que não afetam o layout da página.<!--uniquePlaceholderID--><!--1-->
- Sempre que existir um fragmento completo, uma resposta poderá ser enviada ao cliente e o nó do comentário com o mesmo ID será substituído. Os pedidos são feitos até que todos os fragmentos sejam recuperados.
- Verifique os aplicativos em todos os navegadores suportados ao utilizar a agregação do lado do cliente. Os princípios JavaScript orientados por objeto são usados, para que os aplicativos precisem somente evitar o uso do nome do método getDynamicDataIBMARD. Qualquer window.onload especificado anteriormente é iniciado antes do método onload do ARD.
Serviço de Resultados de Canal do Asynchronous Request Dispatcher
Os pedidos para inclusão de dados a partir do código JavaScript assíncrono são enviados para Identificadores Uniformes de Recursos conhecidos, URIs, também conhecidos como URLs, que o canal ARD pode interceptar para impedir a transmissão por meio do identificador de pedidos do contêiner da Web. Esses URIs são exclusivos para cada reinicialização de servidor.
Por exemplo, /IBMARD01234567/asyncInclude.js é o URI do JavaScript que força a recuperação dos resultados e /IBMARD01234567/IBMARDQueryStringEntries?=12000 é utilizado para recuperar os resultados da entrada com o ID 12000.
Para evitar acesso a resultados não autorizados, são gerados IDs exclusivos para o URI de serviço e para as entradas de ARD. Um gerador de ID comum é compartilhado entre a sessão e o ARD, portanto, a exclusividade pode ser configurada pela configuração de sessão. Os IDs de sessão são considerados seguros, mas não são tão seguros quanto o uso de um token LTPA (Lightweight Third-Party Authentication).
Agregação do Lado do Cliente Customizado
<!--uniquePlaceholderID--><!--x-->
em que
x é a ordem das inclusões. O terminal para recuperar os resultados são recuperados
do atributo de pedido com.ibm.websphere.webcontainer.ard.endpointURI.<div id="2"><BR>Servlet 3--dispatcher3 requesting Servlet3 to sleep for 0 seconds at: 1187967704265
<BR> Servlet 3--Ok, tudo pronto! Isso deve imprimir o pop-up: terceiro em: 1187967704281 </div>
Para obter mais informações sobre as interfaces AsyncRequestDispatcherConfig e AsyncRequestDispatcher, reveja o pacote com.ibm.websphere.webcontainer.async na documentação da API (interface de programação de aplicativos). A documentação da API gerada está disponível no índice de documentação a partir do caminho
.Agregação do Lado do Servidor
Como na agregação do lado do cliente, a agregação do lado do servidor utiliza o canal ARD como um serviço de resultados. O canal ARD sabe quais inclusões assíncronas ocorreram para determinado conjunto de buffers. Será possível então procurar um sinalizador de substituição de inclusão nesses buffers. Em razão dos problemas de armazenamento em buffer da JSP, o sinalizador de substituição da inclusão poderá não estar nos buffers procurados. Se isso ocorrer, o próximo conjunto de buffers também deverá procurar algum sinalizador de substituição de inclusão não obtido no conjunto anterior. O ARD tenta agregar iterativamente conforme as inclusões são retornadas, para que o conteúdo da resposta possa ser enviado ao cliente o mais rápido possível.
Concorrência
Um gerenciador de trabalho é usado para iniciar as inclusões. Se o número de inclusões solicitadas no momento for maior que o tamanho máximo do conjunto de encadeamentos do gerenciador de trabalho e esse tamanho não crescer além disso, ele iniciará o trabalho no encadeamento atual e ignorará a gravação do sinalizador de substituição. O uso do Concurrency Utilities for Java™ EE permite a propagação do contexto do Java EE do encadeamento original incluindo a área de trabalho, internacionalização, perfil do aplicativo, gerenciamento de carga de trabalho do sistema operacional z/OS, segurança, transação e contexto de conexão.
Cronômetro
Um único cronômetro é utilizado para o ARD e tarefas de cronômetros são criadas para todos os tipos de tempo limite de pedidos de ARD. As tarefas que são registradas com o cronômetro não poderão ser executadas no momento exato em que são especificadas, porque o cronômetro é executado em um único encadeamento, portanto, um tempo limite pode precisar aguardar até que outras ações de tempo limite sejam concluídas. O cronômetro é utilizado como último recurso.
Remote Request Dispatcher
Opcionalmente, o ARD pode ser utilizado em conjunto com o Remote Request Dispatcher. O Remote Request Dispatcher executa a inclusão em um servidor de aplicativos diferente em um grupo principal, serializando o contexto da solicitação em uma mensagem SOAP e usando serviços da web para chamar o servidor remoto. Isto é útil quando o custo de criação e envio de uma mensagem SOAP por meio dos serviços da Web é excedido pela emissão do pedido localmente.
Exceções
No caso de uma exceção em um servlet incluído, o contêiner da Web passa pelas definições da página de erro mapeadas para os tipos de exceções. Portanto, uma página de erro que é definida no descritor de implementação é mostrada como uma parte da página agregada. Insira lógica na própria página de erro se o comportamento for diferente para uma inclusão. Como a inclusão é executada de forma assíncrona, o servlet de nível superior poderá não estar em serviços ainda, portanto, a exceção não é propagada de volta de uma inclusão assíncrona como uma inclusão normal. Outras inclusões terminam para permitir a exibição de páginas parciais.
Se o gerenciador de trabalho ARD trabalhar sem encadeamentos do trabalhador, a inclusão será processada como uma inclusão síncrona. Essa é a configuração padrão, mas o gerenciador de trabalho também pode aumentar de forma a não resultar nessa condição. Essa alteração no processamento é invisível para o usuário durante o processamento, mas é observada uma vez nos logs do sistema como uma mensagem de aviso e no restante do tempo nos logs de rastreio, quando ativados. Outros estados que podem acionar a ocorrência de inclusão de forma síncrona é atingir a porcentagem máxima de pedidos expirados em um intervalo de tempo e atingir o tamanho máximo do armazenamento de resultados.
Exceções poderão ocorrer fora do escopo de manipulação normal da página de erro. Por exemplo, o trabalho pode ser rejeitado pelo gerenciador de trabalho. Um cronômetro pode expirar ao aguardar o retorno de uma resposta de inclusão. O canal ARD, ao agir como um serviço genérico para recuperar os resultados, pode receber um ID que não é válido. Nesses casos, não há nenhum caminho para a manipulação da página de erro porque o contexto, como ServletRequest, ServletResponse e ServletContext está faltando, para que o pedido funcione. Para atenuar esses problemas, você pode utilizar a interface AsyncRequestDispatcherConfig para fornecer mensagens de erro customizadas. Padrões são fornecidos e internacionalizados conforme necessário.
Também é possível ocorrer exceções fora do escopo do pedido em que a configuração customizada foi definida, como nos XMLHttpRequests subsequentes do lado do cliente. Nesse caso, a configuração global deve ser alterada. Isso pode ser recuperado por meio de com.ibm.wsspi.ard.AsyncRequestDispatcherConfigImpl.getRef().
- Início da inclusão
- O gerenciador de trabalho fornece um tempo limite para o tempo que precisará ser aguardado para o início de uma inclusão. Em geral, como isso acontece imediatamente, não há uma maneira programática para ativá-lo. No entanto, é possível que seja configurado nas definições do gerenciador de trabalho. Por padrão, você não o encontra por causa da verificação de encadeamentos máximos antes de planejar o trabalho. O trabalho poderá ser tentado novamente se setRetriable(true) for chamado ao utilizar AsyncRequestDispatcherConfig.
- Término da inclusão
- O início do tempo limite começa depois que o trabalho é aceito. Ele pode ser configurado por meio do console ou programaticamente por meio do método AsyncRequestDispatcherConfig.setExecutionTimeoutOverride. O valor padrão é 60000 ms, ou um minuto. No lugar dos resultados da inclusão, a mensagem do AsyncRequestDispatcherConfig.setExecutionTimeoutMessage é enviada. Se esse tempo limite iniciado for atingido, mas os resultados da inclusão real estiverem prontos quando os dados puderem ser liberados, a preferência será fornecida para os resultados reais. Além disso, isso não se aplica às chamadas insertFragmentBlocking que sempre aguardam até que a inclusão seja concluída.
- Expiração de resultados
- Como o lado do cliente deve manter os resultados em um serviço para enviar para a solicitação do Ajax, você precisará de uma maneira de expirar os resultados, se o cliente for desativado e nunca recuperar a entrada. O padrão de um minuto é suficiente para um pedido típico porque o pedido de Ajax viria imediatamente após o envio da resposta. O cronômetro pode ser configurado programaticamente utilizando o método setExpirationTimeoutOverride de AsyncRequestDispatcherConfig. A mensagem do método getOutputRetrievalFailureMessage de AsyncRequestDispatcherConfig é exibida quando alguém tenta acessar uma entrada que expirou e foi removida do cache. Essa mensagem é a mesma enviada para alguém que solicita um resultado com um ID que nunca existiu.
Inclusões ou fragmentos
Considere as operações que podem ser realizadas de forma assíncrona e quando podem iniciar. Idealmente, todas as inclusões serão concluídas quando as chamadas de getFragment forem feitas no início da solicitação, para que as inclusões possam ter mais tempo para ser concluídas, e na inserção de fragmentos, haverá menos armazenamento em buffer e agregação extras se tiverem sido concluídos. No entanto, chamada de uma inclusão assíncrona é mais fácil porque segue o mesmo padrão de uma inclusão de dispatcher de solicitação normal.
Contêiner de Web
- ServletContext
- Ao realizar inclusões entre contextos, o contexto que for um destino da inclusão também deverá ter o ARD ativado, pois o aplicativo da Web deve ter sido inicializado para o ARD para que seu contexto de servlet tenham métodos válidos para recuperação de um AsyncRequestDispatcher. O tipo de agregação é determinado pela configuração do contexto original porque os tipos de agregação não podem ser misturados.
- ServletRequest
- É necessário clonar o pedido para cada inclusão. Caso contrário, poderá ocorrer conflitos entre os encadeamentos. Como os aplicativos podem agrupar os objetos de pedido padrão, seus wrappers devem implementar a interface com.ibm.wsspi.webcontainer.servlet.IServletRequest, que possui um método, o método de clone de objeto, que cria a CloneNotSupportedException.
- O não agrupamento ocorre até que um wrapper de pedido que implemente essa interface seja localizado. Wrappers de não implementação são perdidos; no entanto, um filtro de servlet configurado para a inclusão pode reagrupar a resposta.
- As mudanças feitas no ServletRequest não são propagadas de volta para o servlet de nível superior, a não ser que transferState na AsyncRequestDispatcherConfig esteja ativado e insertFragmentBlocking seja chamado.
- ServletResponse
- Uma resposta agrupada que estende com.ibm.websphere.servlet.response.StoredResponse é criada pelo ARD e enviada para as inclusões, porque a saída da resposta deve ser recuperada além do ciclo de vida da resposta original.
- Os cabeçalhos internos configurados em inclusões assíncronas não são suportados em razão de restrições de ciclo de vida, a não ser que transferState na configuração de AsyncRequestDispatcher esteja ativado e insertFragmentBlocking seja chamado. Os cabeçalhos normais não são suportados em uma inclusão síncrona, conforme especificado pela especificação de servlet.
- Os filtros de inclusão podem reagrupar a nova resposta e devem ser esvaziados na conclusão.
- ServletInputStream
- Um aplicativo que lê parâmetros utilizando getParameter não representa problema. A análise dos parâmetros é forçada antes da primeira inclusão assíncrona para evitar o acesso simultâneo ao fluxo de entrada.
- HttpSession
- Chamadas iniciais getSession que resultam em um cabeçalho Set-Cookie devem ser chamadas a partir do servlet de nível superior por ser imprevisível quando as inclusões forem iniciadas e se os cabeçalhos já foram liberados. A exceção é quando transferState na AsyncRequestDispatcherConfig é ativado e um insertFragmentBlocking é chamado. Isso normalmente cria uma exceção quando o cabeçalho é incluído.
- Filtros
- Se houver um filtro para uma inclusão, ele será emitido no encadeamento assíncrono.
- Inclusões assíncronas aninhadas
- As inclusões assíncronas aninhadas não são suportadas porque complicam a agregação. No entanto, uma inclusão assíncrona pode ter inclusões assíncronas aninhadas. Qualquer tentativa para executar uma inclusão assíncrona aninhada reverte em uma inclusão síncrona.
Transações
Cada tarefa que é enviada para o gerenciador de trabalho é chamado utilizando sua própria transação, muito semelhante às transações gerenciadas por contêiner em enterprise beans típicos. O tempo de execução inicia uma transação local antes de iniciar o método. A tarefa pode iniciar sua própria transação global, se essa transação for possível para o componente de chamada Java EE.
Se a tarefa criar uma exceção, todas as transações locais serão recuperadas. Se o método retornar normalmente, todas as transações locais incompletas serão concluídas de acordo com o critério de ação não resolvida configurado para o bean. Se a tarefa iniciar sua própria transação global e não confirmar essa transação global, a transação será recuperada quando o método for retornado.
Gerenciamento de conexões
- O nome JNDI é codificado permanentemente no aplicativo, por exemplo, como uma propriedade ou literal de sequência.
- As connection factories não são compartilhadas, porque não há como especificar um escopo de compartilhamento.
Desempenho
Como as inclusões são concluídas de maneira assíncrona, os dados de desempenho totais para uma solicitação devem considerar o desempenho das inclusões assíncronas. O tempo total da solicitação pode ser entendido anteriormente quando o servlet de nível superior for concluído, mas agora esse servlet está saindo antes da conclusão das inclusões. O servlet de nível superior ainda conta muito no tempo de configuração adicional necessário para cada inclusão.
Portanto, uma nova métrica de desempenho do ARD foi incluída na Infra-estrutura de Monitoramento de Desempenho para medir o tempo de um pedido completo por meio do canal ARD. A granularidade dessas métricas ocorre no nível de URI do pedido.
Como o ARD é um recurso opcional que deve ser ativado, nenhuma recusa de desempenho será vista quando não utilizar o ARD. No entanto, aplicativos não ARD residentes em um servidor de aplicativos ativado pelo ARD sofreriam com a camada extra do ARDChannel. A camada de canais não sabe para qual aplicativo está indo, portanto, fica ativada ou desativada para todos os aplicativos de uma cadeia de canais. A definição é feita de acordo com o host virtual.
Segurança
A segurança não é chamada em dispatches de inclusão síncrona de acordo com a especificação de servlet. No entanto, o contexto de segurança é transmitido por meio de Concurrency Utilities for Java EE para suportar o uso programático dos métodos isUserInRole e getUserPrincipal no ServletRequest. Esse contexto de segurança também pode ser propagado através de um despacho de solicitação remota usando o Web Services Security.