Série Spring: Spring AOP com annotations

 

Olá Pessoal,

No post de hoje vamos ver como usar annotations   para AOP é bem simples.Já vimos aqui  com XML e agora vamos para o que há de melhor  desde do Java 5 que é o uso de Annotations.

Lets go…

 Starting

O post é bem curto e procurei  ser bem objetivo, então considerando que você já tem seu arquivo de spring configurado  para usar aop, vamos apenas atualizar para habilitar o recurso de annotations  e aproveitei removi os beans  usando auto-discovering do Spring. Vamos começar pela configuração do arquivo springconfiguration.xml (o nome que dei ao meu arquivo de configuração).

Antes disso, crie um projeto novo e dê o nome que quiser.

Note: lembre-se de adicionar os .jars do Spring, AOP e AspectJ ao projeto:

 springaopannotationsproject

Configurando .xml do Spring

<beans xmlns=“http://www.springframework.org/schema/beans”

xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xmlns:context=“http://www.springframework.org/schema/context”

xmlns:aop=“http://www.springframework.org/schema/aop”

xsi:schemaLocation=“http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.2.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.2.xsd”>

 <context:component-scan base-package=“*”/>

<aop:aspectj-autoproxy/>

 </beans>

 

Deixei seu arquivo de configuração assim. A única coisa nova de aop, foi que adicionar a linha <aop:aspectj-autorproxy/>  que nos permite usar annotations.

Criando o bean

A seguir vamos criar o bean , nada demais neles:

@Component

@Scope(value=”prototype”)

public class Student {

      private String name;

//    this is DI via annotations

      @Autowired

      private Course course;

      public String getName() {

            return name;

      }

      public void setName(String name) {

            if (name==null) {

                  throw new IllegalArgumentException();

            }

            this.name = name;

      }

      public Course getCourse() {

            return course;

      }

      public void setCourse(Course course) {

            this.course = course;

      }     

      public void teste(){           

      }

}

O outro bean:

@Component

public class Course {

      private String nameCourse; 

      public String getNameCourse() {

            return nameCourse;

      } 

      public void setNameCourse(String nameCourse) {

            this.nameCourse = nameCourse;

      } 

}

 

Agora vamos criar uma classe que será responsável  por registrar uma mensagem antes;após de determinados métodos, ou seja, as regras do AOP estarão aqui:

@Aspect

@Component

public class Audit {

//    aqui com o metodo especifico

      @Pointcut(“execution(* br.com.camilolopes.bean.Student.setName(..))”)

      public void aopteste(){} 

      @Pointcut(“execution(* br.com.camilolopes.bean.Course.setNameCourse(..))”)

      public void aopcourse(){}     

      @Pointcut(“execution(* *.*test*(..))”)

      public void aopanywhere(){}     

      @AfterReturning(“aopteste()”)

      public void register(){

            System.out.println(“Student registred”);

      }

      @After(“aopcourse()”)

      public void finished(){

            System.out.println(“Course finished”);

      }

      @AfterThrowing(“aopteste()”)

      public void problem(){

            System.out.println(“Happened problem here”);

      }

      @Before(“aopteste()”)

      public void starting(){

            System.out.println(“application is starting…”);

      }

      @AfterReturning(“aopanywhere()”)

      public void anywhere(){

            System.out.println(“anywhere test”);

      }

}

Observe que anotei a classe com @Component para que o Spring saiba que precisa registrar ela no contexto. Caso contrário, nada rola. Agora vamos entender os pointcuts criados:

  • Primeiro: criamos um pointcut que sempre será chamado quando um método especifico for chamado nesse caso o método  setName da classe Student.
  • Segundo: o mesmo que acima, exceto que para a classe Course.
  • Terceiro :  agora criamos um que estou dizendo: “de qualquer lugar da aplicação e qualquer método que comece com test e terminar com qualquer coisa.

E  os métodos a seguir é o que serão chamados  com base no que tipo de anotação que definimos, observe que temos um que será chamado apenas no caso de acontecer uma exceção quando no método setName da classe Student.

Testando

Para testar aplicação criei uma classe de teste

Classe de Test

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations={“classpath:config/springconfiguration.xml”})

public class StudentTest {

      @Autowired

      private Student student;

      @Before

      public void setUp() throws Exception {

      } 

      @Test

      public void testNameCourse() {

            student.getCourse().setNameCourse(“TDD”);

            assertEquals(“TDD”,student.getCourse().getNameCourse());

      }     

      @Test

      public void testNameStudent(){

            student.setName(“Camilo”);

            assertEquals(“Camilo”, student.getName());

            student.teste();

      }

      @Test(expected=IllegalArgumentException.class)

      public void testNameIsNullException(){

            student.setName(null);

      }

}

Resultado:

resultaopunittest

Classe com o método main

Fiz uma pequena classe com método main, para quem não sabe unit test:

public class MainTest {

      public static void main(String[] args) {

            ApplicationContext  applicationContext = new ClassPathXmlApplicationContext(“config/springconfiguration.xml”);

            Student bean = (Student) applicationContext.getBean(“student”);

            bean.setName(“lopes”);

            bean.teste();           

      }

} 

O resultado será diferente pq as inovações são diferentes:

resultadoaopmaintest

 

Bom, pessoal. Vou ficando por aqui e espero que tenham gostado do post.

Abraços,