









Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Este documento aborda a manipulação de componentes em tempo de compilação em java, permitindo a inserção de novos atributos e métodos em classes. Através do uso de pointcuts, advices e aspectos, é possível alterar a herança de classes e implementar tarefas como log, deixando os desenvolvedores se concentrarem na implementação das regras de negócio. Além disso, é apresentado o processo de compilação (weaving) para injetar bytecodes nas classes e gerar um jar com aspectos.
Tipologia: Teses (TCC)
1 / 16
Esta página não é visível na pré-visualização
Não perca as partes importantes!










Daniel Ferreira Martins UNIFENAS/IGAP/FIEMG – Trabalho de Conclusão de Curso Pós-graduação em Desenvolvimento Corporativo em Java [email protected] 2008, dezembro RESUMO
1. Introdução - Programação Orientada a Aspectos Durante anos a Engenharia de Software tem disponibilizado vários métodos, técnicas e ferramentas para auxiliar os desenvolvedores a produzirem com maior qualidade. Atualmente com o avanço tecnológico, o processo de desenvolvimento de softwares exige que os profissionais pensem em preocupações variadas, como por exemplo, interface amigável, distribuição, paralelismo ou concorrência, componentização, reutilização, persistência e segurança. O desenvolvimento de software baseando em objetos trouxe muitos benefícios, tanto em nível de modelagem quanto de implementação, facilitando a manutenibilidade a componentização e a reutilização, mas possui limites e não elimina totalmente problemas de manutenibilidade, reusabilidade, entrelaçamento (tangled code) e espalhamento (spread code). Visando solucionar tais problemas, reduzir a complexidade e aumentar a produtividade no desenvolvimento de software, surge um novo paradigma, a Programação Orientada a Aspectos (POA). Baseada na teoria da separação de preocupações (Separation of Concerns) que busca organizar os requisitos de software em nichos de responsabilidades, interesses, preocupações, funcionalidades, a POA tem o objetivo de reduzir a complexidade do desenvolvimento de software, permitindo que estas diversas preocupações possam ser componentizadas independentemente de sua natureza, funcional ou não funcional. Desde as primeiras atividades de desenvolvimento de um software, os desenvolvedores mais experientes dividem os requisitos, principalmente, segundo suas funcionalidades, responsabilidades e entidades relacionadas. Ao dividir as preocupações, propicia-se ao desenvolvedor concentrar esforços no desenvolvimento de uma solução de um problema menor, ocorrendo consequentemente uma redução no número de erros de cada módulo e do sistema como um todo. Os desenvolvedores e analistas investem mais tempo com soluções ditas “dificuldades secundárias” (distribuição, segurança, persistência, auditoria, portabilidade...) do que com as regras de negócio, o principal motivo de se desenvolvedor o software. A POA tem facilitado principalmente a implementação de aspectos não funcionais que demandam soluções que não podem ser
contidas em apenas um módulo, mas que se estão espalhadas ao logo do sistema, permitindo que tais aspectos e mesmo os funcionais sejam trabalhados individualmente em paralelo por diferentes equipes para posterior integração. O estilo programação da POA não deve ser vista como substituta da Programação Orientada a Objetos, mas sim como um complemento que propicia: A implementação e integração de requisitos funcionais e não funcionais que foram divididos em interesses, preocupações, podendo tais divisões serem fisicamente pacotes, classes ou aspectos. A alteração da estrutura dos componentes em tempo de compilação, podendo-se inserir novos atributos e métodos. A alteração do fluxo de execução de um sistema inserindo uma funcionalidade que não existia anteriormente, sem alterar o código fonte do módulo ou componente alterado.
2. AspectJ A orientação a aspectos não é suportada nativamente pela linguagem Java, porém existem várias implementações maduras que permitem sua adoção em uma implementação real. A implementação mais famosa é o AspectJ , porém existem outras maduras como o JBoss AOP e o Spring AOP. 3. Conceitos Básico de POA com AspectJ Joinpoint: é um ponto termo utilizado na teoria de POA que significa um ponto bem definido na execução de um sistema no qual o aspecto pode agir. Os tipos de joinpoints suportados dependem da implementação utilizada. Pointcut: é um conjunto de joinpoints no qual um aspecto pode agir. Um pointcut declara os pontos onde se deseja interromper a execução de um sistema para inserir outro comportamento. Cada implementação provê uma forma de definição dos pointcuts de um aspecto. Normalmente pode-se usar diversos critérios para sua definição, como por exemplo, nome da classe, nome do método, tipo de retorno ou tipo de parâmetros. Um pointcut está para atributo assim como o aspect está para class. Advice: equivale a métodos (ou funções), é onde é implementado o comportamento do aspecto que será executado quando o fluxo de execução atingir um dos pointcuts. Estes também dependem da implementação, sendo os mais comuns before (executado antes do pointcut ), after (executado após o pointcut ) e around (executado “em volta” do pointcut ). O AspectJ apresenta mais dois advices , after returning e after throwing. Introduction: é uma forma de adicionar comportamentos em uma classe e alterar sua estrutura, introduzindo novos atributos, métodos, construtores, herança e interface. Normalmente estes novos comportamentos estão ligados com um
4.2 Declaração de Pointcuts Um ponto de corte é uma construção sintáxica para se agrupar um conjunto de pontos de junção, tendo a seguinte sintaxe básica: [ modifiers ] pointcut name ( ): [ pointcut type ] [ joinpoint signing ] Os modificadores como ditos anteriormente, têm a mesma funcionalidade de quando aplicado a atributos de classes Java. A assinatura do joinpoint é uma expressão que especifica todos os joinpoints aos quais o pointcut se refere. Os tipos de pointcuts são os seguintes: call – para chamadas de métodos e construtores. execution – para execução de métodos e construtores. get e set – para métodos de acesso a campos. handler – para chamada de exceção. initialization , preinitialization , staticinitialization – para inicialização de Classe. cflow , cflowbelow – para controle de fluxo. this, target, args – para avaliação de contexto. if – para teste de condição. Para criar pointcuts para a chamada ou execução de construtores basta acrescentar a palavra reservada new ao nome da classe (ex: call ou execution (void Vector. new ( ) ). Pointcut s de chamada se diferenciam dos de execução pelo momento em que ocorre a interceptação, os de chamada interceptam o fluxo de execução após o sistema terminar a avaliação dos argumentos que serão passados na chamada antes da mudança do fluxo para o método a ser chamado, já os de execução interceptam o fluxo de execução antes da execução do primeiro comando. Os pointcuts de chamada de exceção capturam e interceptam a execução do bloco catch das exceções especificadas, podendo ser executado um advice antes do bloco. Para os pointcuts de inicialização é importante conhecer o momento das interceptações que estão diretamente relacionadas aos construtores das classes. O de pré-inicialização ocorre quando os construtores estão se preparando para criar uma classe, ou seja, na chamada do construtor e ocorre sempre do nível hierárquico mais baixo para o mais alto. Já o pointcut de inicialização ocorre após a execução do construtor e sempre do nível hierárquico mais alto para o mais baixo. O pointcut de inicialização estática é sempre o primeiro a ocorrer e a denunciar a ordem em que os objetos serão criados. Os pointcuts de controle de fluxo interceptam as chamadas de métodos baseando-se no controle de fluxo de execução de um programa. Um fluxo de controle consiste de todos os comandos que são executados entre a entrada em um método e a
saída deste, inclusive considerando comandos em outros métodos chamados pelo primeiro. Com este pointcut é possível capturar todas as chamadas métodos, de getters e setters e de exceção que ocorreram devido à chamada de um determinado método. A única diferença entre eles é que cflow inclui entre os pontos de junção resultantes o próprio ponto de junção dado como parâmetro, enquanto cflowbelow inclui apenas os pontos de junção que estão "abaixo" do ponto dado. Os pointcuts de avaliação de contexto permitem obter informações do joinpoint interceptado, como a referência ao objeto que está sendo chamado e referência aos parâmetros passados na chamada do método. Os pointcuts de teste de condição interceptam os joinpoints baseando-se na verificação de uma condição em um joinpoint e sua declaração segue a forma if(condicao). Para facilitar o trabalho de escrever os pointcuts , pode-se utilizar curingas (wildcards) como +, * e .. (dois pontos sequenciais), operadores lógicos como “e” (&&), “ou” ( || ) e “não” (! ) , e estrutura léxica. A listagem-2 apresenta alguns exemplos de declaração de pointucts utilizando wildcards, operadores lógicos e estrutura léxica: public aspect ExemploAspect { pointcut all_parameters( ): call ( void Vector. addElement ( .. ) ); pointcut all_returnType( ): call ( ***** Vector. addElement ( Object ); pointcut all_methods( ): call ( void Vector.( Object ) ); pointcut all_Vector( ): call ( ***** Vector. ***** ( .. ) ); pointcut all_classes( ): call ( public ***** br.util ... ***** ( .. ) ); pointcut all_sub( ): call ( ***** Vector +. ***** ( .. ) ); pointcut juncao1( ): call ( ***** Vector. ***** ( Object ) ) && execution ( public Object Vector. elementAt ( int ) ); pointcut juncao2( ): call ( public void Vector. addElement ( Object ) ); pointcut juncao3( ): juncao1 && !juncao2; pointcut Classe( ): within ( Vector ); pointcut All_Classe( ): within ( Merc* ); pointcut All_Calls( ): withincode ( ***** Vector. addElement ( .. ) ); } Listagem 2 – Declaração de pointcuts utilizando wildcards, operadores lógicos e estrutura léxica. 4.2.1. Pointcuts com uso de wildcards: Pointcut all_parameters( ) : captura todas as chamadas de métodos addElement da classe Vector que retornam void e possuam qualquer argumento. Pointcut all_returnType( ) : captura todas as chamadas de métodos addElement da classe Vector que possuam qualquer tipo de retorno e receba um argumento do tipo Object.
public aspect IntroductionAspect { private int Pessoa.idade; private String Pessoa.nome; public void Pessoa.setNome(String var){ this.nome = var; } public void Pessoa.setIdade(int var){ this.idade = var; } public String Pessoa.getNome() { return this.nome; } public int Pessoa.getIdade() { return this.idade; } } Listagem 3 – Aspecto para introdução de atributos e métodos. 4.3.2. Herança É possível em determinadas situações alterar a herança das classes herdadas de outras classes por extends ou implements, tomando os cuidados para não violar as regras de herança da linguagem java. As alterações da hierarquia não podem, por exemplo, declarar superclasses para interfaces, ou definir superclasses de tal forma que se obtenha herança múltipla. As sintaxes para introdução de herança são as seguintes: declare parents: [ class_name ] extends [ superclass_name ] declare parents: [ class_name ] implements [ interface_name ] A listagem-4 mostra um exemplo de herança por introdução cuja saída da chamada ao método print da classe Filho1 imprime o retorno da chamada ao método toString da superclasse e ao seu próprio. A chamada do método print da classe Filho1 no método main do aspecto Heranca gera a seguinte saída: PAI 1 FILHO 1
public class Pai1 { public String toString( ){ return "PAI 1"; } } public class Filho1 { public String toString( ){ return "FILHO 1"; } public void print( ) { System.out.print( super.toString( ) ); System.out.println( this.toString( ) ); } } public aspect Heranca { declare parents: Filho1 extends Pai1; public static void main(String[] args) { Filho1 f1 = new Filho1(); f1.print(); } } Listagem 4 – Introdução de herança com Aspecto.
5. Criando um Projeto com Eclipse e AspectJ Este projeto será uma implementação simples para demonstrar o uso de aspecto. Em muitos sistema o log de informações é um dos requisitos não funcionais de grande importância, e que se faz necessário em todos os módulos do sistema. Como o uso de aspecto para realizar a tarefa de log os desenvolvedores podem se concentrar na implementação das regras de negócio e deixar que uma outra equipe implemente o mecanismo de log, sendo que a integração será feita posteriormente. Para tanto a equipe que irá implementar as regras de negócio, deverá apenas fazer com que suas classes de negócio implementem uma interface comum, “Business”. O Eclipse é um IDE ( Integrated Development Environment , ou ambiente integrado de desenvolvimento) gratuito, produzido pela IBM, totalmente desenvolvido usando tecnologia Java. O Eclipse é extensível através de plugins. Existem inúmeros plugins disponíveis. Um deles, o AJDT , fornece suporte ao desenvolvimento com o AspectJ. As telas a seguir ilustram o uso do Eclipse (versão 3.3.2) com o AspectJ. 5.1 Instalando o ajdt No eclipse acesse o menu Help --> Software Updates --> Find and Install... Clique no botão “New Remote Site...” Entre com o nome ajdt. Entre com a url http://download.eclipse.org/tools/ajdt/33/u pdate Clique em OK. Selecione AspectJ. Clique em “next” e
package br.fiemg.domain; import java.io.Serializable; import java.util.Date; public class Pessoa implements Serializable { private static final long serialVersionUID = 6527239924301654575L; private Long id; private String nome; private Date dataNascimento; public Pessoa() { } public Pessoa(Long id, String nome, Date dataNascimento) { super(); this.id = id; this.nome = nome; this.dataNascimento = dataNascimento; } /*... implementação de getters e setters */ } Listagem 6 – Definição da classe Pessoa. Após definir a implementação da classe Pessoa, clique no pacote br.fiemg.business” e selecione New --> Class, informe o nome “PessoaBusiness” e clique em “Finish”. Na listagem 7 temos a definição da classe. package br.fiemg.business; import br.fiemg.domain.Pessoa public class PessoaBusiness implements Business { @Override public void atualizar(Long id, String nome, Date dataNascimento) { System. out .println("===== INICIO ATUALIZAR ==="); Pessoa pessoa = new Pessoa(); pessoa.setId(id); pessoa.setNome(nome); pessoa.setDataNascimento(dataNascimento); System. out .println("Atualizando dados: " + pessoa.getNome()); System. out .println("===== FIM ATUALIZAR ===");
@Override public void excluir(Pessoa pessoa) { System. out .println("===== INICIO EXCLUIR ==="); System.out.println(“Excluindo: ” + pessoa.getNome()); System. out .println("===== FIM EXCLUIR ==="); } @Override public void salvar(Pessoa pessoa) { System. out .println("===== INICIO SALVAR ==="); System.out.println(“Salvando: ” + pessoa.getNome()); System. out .println("===== FIM SALVAR ==="); } } Listagem 7 – Definição da classe PessoaBusiness. Agora vamos implementar um aspecto para interceptar não somente as chamadas aos métodos da interface Business, mas também todas as chamadas dos métodos públicos das classes que implementem a interface. Clique no botão direito sobre o pacote “br.fiemg.aspect” e selecione New --> Other..., e digite “Aspect” e marque a primeira opção “Create an Aspect”. A listagem 8 exibe a definição do aspecto. package br.fiemg.aspect; import br.fiemg.business.Business; public aspect LoggerAspect { pointcut businessLog() : execution(public * Business+.*(..)); before() : businessLog() { Object target = thisJoinPoint.getTarget(); System.out.println("Instancia logada: " + target.getClass()); String methodName = thisJoinPoint.getSignature().getName(); System.out.println("Metódo: " + methodName); Object[] args = thisJoinPoint.getArgs(); StringBuilder sb = new StringBuilder("Argumentos: ");
A saída da execução da classe de teste é exibida na listagem 10. Instancia logada: class br.fiemg.business.PessoaBusiness Método: atualizar Argumentos: Long:1; String:Maria de Lourdes; Date:Mon Jan 12 23:11:15 BRST 2009; ===== INICIO ATUALIZAR === Atualizando dados: Maria de Lourdes ===== FIM ATUALIZAR === Instancia logada: class br.fiemg.business.PessoaBusiness Metódo: salvar Argumentos: Pessoa:Maria de Lourdes; ===== INICIO SALVAR === Salvando: Maria de Lourdes ===== FIM SALVAR === Instancia logada: class br.fiemg.business.PessoaBusiness Metódo: excluir Argumentos: Pessoa:Maria de Lourdes; ===== INICIO EXCLUIR === Excluindo: Maria de Lourdes ===== FIM EXCLUIR === Listagem 10 – Saída no console da execução da classe TestLog 5.3. Compilação (Weaving) 5.3.1 Injetando os bytecodes nas classes e gerando um jar com Aspectos Para compilar os aspectos e injetar os bytecodes nas classes de nosso projeto ou de outros projetos que utilizem um jar de aspectos, vamos utilizar uma task do ant que facilita o weaving. Para tando devemos acrescentar ao classpath de compilação o aspectjtools.jar. Este jar irá fornecer a implementação da funcionalidade da task. Vale lembrar, que os aspectos dependem diretamente do aspectjrt.jar, o qual não é necessário ser acrescentado ao classpath de projetos, quando estes forem projetos de natureza do plugin AJDT do eclipse_._ A listagem 11 exibe as tasks que são responsáveis por realizar o weaving:
E
Listagem 11 – Tasks do Ant responsáveis pela compilação e injeção dos bytecodes dos aspectos (weaving). A task iajc substitui a já conhecida task javac utilizada para compilar classes java sem aspecto, e é a principal responsável pela realização do weaving. No entando é necessário carregar o arquivo de resource aspectjTaskdefs.properties e colocar o aspectjtools.jar no classpath de compilação. Feito isso já existe a possibilidade de aplicar seus aspectos a outros projetos. A listagem 12 exibe um exemplo completo do build.xml do projeto de exemplo.
Compila as classe, os aspectos e gera o jar
** **
Claudiney Calixto da Silva. Programação Orientada a Aspectos em Java, Desenvolvimento de Software Orientado a Aspectos, 2005. [2]. Eduardo Guerra. Proxys Estáticos e Dinâmicos, Revista Mundo Java Edição 32 Ano VI, 2008. [3]. AspectJ - http://eclipse.org/aspectj [4]. Eclipse AJDT – http://eclipse.org/ajdt [5]. Spring - http://www.springframework.org [6]. JBoss AOP - http://www.jboss.org/jbossaop/