AspectJ tangent indicator-05-this

Posted by zenix on Thu, 30 Jan 2020 15:05:05 +0100

this() If the proxy class matches the specified class according to the type, then all connection points of the target class to be proxy match the tangent point


In general, this() and target() are used to match and define pointcuts. They are equivalent. The difference between them is reflected in the specific performance of generating proxy objects through the reference plane.

1,Factory

package com.test.aspectj.expression;

/**
 * Factory interface
 */
public interface Factory {

    // Make products
    void make();

    // transport
    void delivery(String address);
}

2,PhoneFactory

package com.test.aspectj.expression;

import com.test.aspectj.expression.args.FreshFoodFactory;
import com.test.aspectj.expression.args.FrozenFoodFactory;
import org.springframework.stereotype.Component;

/**
 * Food factory
 */
@Component
public class FoodFactory implements Factory {
    // How to make products
    @Override
    public void make() {
        System.out.println("From target class FoodFactory News of: food production");
    }

    // transport
    @Override
    public void delivery(String address) {
        System.out.println("From target class FoodFactory Sales of food to " + address);
    }

    // Match to @ args(com.test.aspectj.expression.args.Listen) pointcut
    public void testArgsAnnotation(FreshFoodFactory freshFoodFactory) {
    }

    // Cannot match @ args(com.test.aspectj.expression.args.Listen) pointcut
    public void testFrozenArgsAnnotation(FrozenFoodFactory frozenFoodFactory) {
    }
}

3. Introduce the interface Listener to be implemented

package com.test.aspectj.expression.thisexpression;

/**
 * Interface to be implemented in the introduction section
 */
public interface Listener {
    /**
     * Monitor
     */
    void listen();
}

4. Listener interface implementation class

package com.test.aspectj.expression.thisexpression;

/**
 * Listener Interface implementation class
 */
public class DefaultListener implements Listener {
    /**
     * Monitor
     */
    @Override
    public void listen() {
        System.out.println("Come from DefaultListener Start listening");
    }
}

5. Define the reference facet ListenerAspect, which populates the Listener interface for FoodFactory

package com.test.aspectj.expression.thisexpression;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.core.Ordered;

/**
 * Add a facet of the Listener interface to FoodFactory
 */
@Aspect
public class ListenerAspect implements Ordered {

    /**
     * Add interface implementation for FoodFactory. The interface to be implemented is Listener. The default implementation of the interface is DefaultListener
     */
    @DeclareParents(value = "com.test.aspectj.expression.FoodFactory", defaultImpl = DefaultListener.class)
    public static Listener listener;

    /**
     * If there are multiple cuts, pay attention to the order in which the cuts are woven
     */
    @Override
    public int getOrder() {
        return 2;
    }
}

6. Test this and target facets

package com.test.aspectj.expression.thisexpression;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.Ordered;

import javax.annotation.Resource;

/**
 * Test the tangent of this and target
 */
@Aspect
public class ThisAspect implements Ordered {
    /**
     * Weaving into a Bean whose runtime object is Listener type
     *
     * You can match not only the methods defined in the Listener interface, but also the methods in FoodFactory
     */
    @AfterReturning("this(com.test.aspectj.expression.thisexpression.Listener)")
    public void after() {
        System.out.println("Message from the section: ThisAspect after Method executed");
    }

    /**
     * Match only the methods defined in the Listener
     */
    @Before("target(com.test.aspectj.expression.thisexpression.Listener)")
    public void before() {
        System.out.println("Message from the section: ThisAspect before Method executed");
    }

    /**
     * If there are multiple cuts, pay attention to the order in which the cuts are woven
     */
    @Override
    public int getOrder() {
        return 1;
    }
}

7,xml

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd">
    
    <context:component-scan base-package="com.test.aspectj.expression"/>
    <bean id="listenerAspect" class="com.test.aspectj.expression.thisexpression.ListenerAspect"/>
    <bean id="thisAspect" class="com.test.aspectj.expression.thisexpression.ThisAspect"/>
    <aop:aspectj-autoproxy />
    
</beans>

8. Test code

package com.test.aspectj.expression.thisexpression;

import com.test.aspectj.expression.FoodFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * test
 */
public class ThisExpressionDemo {
    public static void main(String[] args) {
        System.out.println("=============== test this ===============");
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-chapter3-aspectjthisexpression.xml");
        FoodFactory foodFactory = (FoodFactory) context.getBean("foodFactory");
        foodFactory.make();
        System.out.println("-----Dividing line-----");
        Listener listener = (Listener) foodFactory;
        listener.listen();
    }
}

9. The theoretical results are as follows

===============Test this===============
Message from the target class FoodFactory: produce food
Message from aspect: ThisAspect after method executed
-----Dividing line-----
Message from the aspect: ThisAspect before method executed
Message from DefaultListener: start listening
Message from aspect: ThisAspect after method executed

However, errors are reported in the test process as follows (it is also necessary to verify the correctness of the conclusion)

Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy16 cannot be cast to com.test.aspectj.expression.FoodFactory
	at com.test.aspectj.expression.thisexpression.ThisExpressionDemo.main(ThisExpressionDemo.java:14)

10, summary

  • this(com.test.aspectj.expression.thisexpression.Listener) can match not only the methods defined in the listener interface, but also the methods in FoodFactory;
  • target(com.test.aspectj.expression.thisexpression.Listener) only matches the methods defined in the listener.

Topics: Programming Spring xml Java encoding