Spring AOP - Create Aspects with Annotations

Keywords: Junit Spring xml Attribute

1 Target object

package com.musi.bean;
import org.springframework.stereotype.Component;
@Component
public class Animal {

    public void run(){
        System.out.println("animal is running .....");
    }

    public void run(String  name){
        System.out.println(name+" is running ........");
    }

    public void run(int times){
        System.out.println("animal running times:"+times);
    }
}

2 Sections

package com.musi.aop.annotationaspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AnimalAspect {

    @Before("execution(* com.musi.bean.Animal.run(..))")
    public void beforeRunning(){
        System.out.println("annotation before running .......");
    }

    @After("execution(* com.musi.bean.Animal.run(..))")
    public void afterRunning(){
        System.out.println("annotation after running .......");
    }

    @AfterReturning("execution(* com.musi.bean.Animal.run(..))")
    public void afterReturning(){
        System.out.println("annotation afterReturning running .......");
    }

    @AfterThrowing("execution(* com.musi.bean.Animal.run(..))")
    public void afterThrowing(){
        System.out.println("annotation afterThrowing running .......");
    }
}

Simplified Writing:

package com.musi.aop.annotationaspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AnimalAspectSimple {

    @Pointcut("execution(* com.musi.bean.Animal.run())")
    public void run(){}

    @Before("run()")
    public void beforeRunning(){
        System.out.println("before running .......");
    }

    @After("run()")
    public void afterRunning(){
        System.out.println("after running .......");
    }

    @AfterReturning("run()")
    public void afterReturning(){
        System.out.println("afterReturning running .......");
    }

    @AfterThrowing("run()")
    public void afterThrowing(){
        System.out.println("afterThrowing running .......");
    }
}

Note: The @Pointcut annotation is used in the above code, in which the name and actual content of the performance() method are not important. In this case, it should be empty. It is only an identifier itself for the @Pointcut annotation to attach. It is important to note that at this time, except for the annotation and the performance() method without actual operation, the Audience class depends on However, it's a pojo, which is no different from ordinary Java classes. It's just that annotation table names are the most widely used.

3 If you stop at this point, Audience will only be a common bean in the spring container. Even if AspectJ is used, it will not be regarded as an aspect and needs to be configured separately. With Javaconfig, you can enable the automatic proxy function at the class level of the configuration class by using the EnableAspectJ-AutoProxy annotation, as follows:

package com.musi.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.musi")
public class SystemConfig {

}

The corresponding xml configuration is as follows:

<?xml version="1.0" encoding="UTF-8" ?>
<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.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.musi"/>
    <aop:aspectj-autoproxy />

</beans>

4 test classes

package com.musi.test.bean;

import com.musi.aop.annotationaspect.Encoreable;
import com.musi.bean.Animal;
import com.musi.config.SystemConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SystemConfig.class)
public class SpringBeanTest {

    @Autowired
    private Animal animal;

    @Test
    public void test(){
        animal.run();
    }
}

Test classes using xml configuration

package com.musi.test.bean;

import com.musi.bean.Animal;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:application.xml"})
public class SpringXmlTest {
    @Autowired
    private Animal animal;

    @Test
    public void test(){
        animal.run();
    }
}

5 Create surround notifications

package com.musi.aop.annotationaspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AnimalRoundAspect {
    @Pointcut("execution(* com.musi.bean.Animal.run(..))")
    public void run(){}

    @Around("run()")
    public void aroundRunning(ProceedingJoinPoint pjp){
        try {
            System.out.println("around before ....");
            pjp.proceed();
            System.out.println("around after ....");
        }catch (Throwable throwable) {
            System.out.println("around trowing ....");
            throwable.printStackTrace();
        }
    }
}

Test Class Ibid.

6 Processing parameters in notifications

package com.musi.aop.annotationaspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AnimalArgsAspect {

    @Pointcut("execution(* com.musi.bean.Animal.run(int))&&args(times)")
    public void run(int times){}

    @Before("run(times)")
    public void beforeRunning(int times){
        System.out.println("before running times:"+times);
    }

    @After("run(times)")
    public void afterRunning(int times){
        System.out.println("after running times:"+times);
    }

    @AfterReturning("run(times)")
    public void afterReturning(int times){
        System.out.println("afterReturning running times:"+times);
    }

    @AfterThrowing("run(times)")
    public void afterThrowing(int times){
        System.out.println("afterThrowing running times:"+times);
    }
}

Test class

package com.musi.test.bean;

import com.musi.bean.Animal;
import com.musi.config.SystemConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SystemConfig.class)
public class SpringBeanArgsTest {

    @Autowired
    private Animal animal;

    @Test
    public void test(){
        animal.run(11);
    }
}

7 Introducing new functions through annotations

  1. Creating Introduced Agents
package com.musi.aop.annotationaspect;

public interface Encoreable {
    void jump();
}
  1. Proxy default implementation class
package com.musi.aop.annotationaspect;

public class EncoreableImpl implements Encoreable {
    public void jump() {
        System.out.println("this is EncoreableImpl.....");
    }
}

3) Setting up agents through DeclareParents

package com.musi.aop.annotationaspect;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class EncoreableIntroducer  {

    @DeclareParents(value="com.musi.bean.Animal",defaultImpl=EncoreableImpl.class)
    public static Encoreable encoreable;
}

Note: @DeclareParents annotation consists of three parts:
The value attribute specifies which type of bean is to be introduced into the interface. In this case, Animal. (If Animal is an interface, add a plus sign after Animal, that is, "com.musi.bean.Animal+", which means all subtypes of Animal, not Animal itself.)
The defaultImpl attribute specifies the class that provides the implementation for the introduction of functionality. Here we specify the DefaultEncoreable implementation.
@ The static properties annotated in the DeclareParents annotation indicate the interface to be introduced. Here we introduce the Encoreable interface.
In addition, we need to declare Encoreable Introducer as a bean:

4) Test class

package com.musi.test.bean;

import com.musi.aop.annotationaspect.Encoreable;
import com.musi.bean.Animal;
import com.musi.config.SystemConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SystemConfig.class)
public class SpringBeanTest {

    @Autowired
    private Animal animal;

    @Test
    public void test(){
        animal.run();
        Encoreable encoreable = (Encoreable)animal;
        encoreable.jump();
    }
}

Posted by rsammy on Wed, 14 Aug 2019 05:59:52 -0700