[spring] AOP learning notes

[spring] AOP learning notes

I. Preface

1. Take a chestnut

Transfer case:

2. Transaction control

2, Dynamic agent

Enhance the method without modifying the source code
Spring formally introduces the characteristics of proxy: if JDK proxy is used for interface proxy; if Cglib proxy is used for class proxy.

1. JDK agent

The target object is interface oriented. The proxied class implements at least one interface. If not, it cannot be used (the default proxy mode of spring is JDK proxy)
Using the newProxyInstance method in the Proxy class, parameters of the newProxyInstance method:

  • ClassLoader: ClassLoader
    Used to load the proxy object bytecode. Use the same classloader as the proxied object. Fixed writing.
  • Class []: bytecode array
    Used to make the proxy object and the proxied object have the same method. Fixed writing.
  • InvocationHandler: code to provide enhancements
    Write agent details. Generally, it is to write an implementation class of the interface. Generally, it is an anonymous internal class, but it is not necessary.
public class Client {

    public static void main(String[] args) {
        final Producer producer = new ProducerImpl();

        Producer proxyProducer = (Producer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * Function: any interface method executing the proxied object will pass through this method
                     * Meaning of method parameters
                     * @param proxy   References to proxy objects
                     * @param method  Currently implemented method
                     * @param args    Parameters required for the current execution method
                     * @return Same return value as represented object method
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //Provide enhanced code
                        Object returnValue = null;
                        //1. Get the parameters of method execution
                        Float money = (Float) args[0];
                        //2. Judge whether the current method is sales or not
                        if ("saleProduct".equals(method.getName())) {
                            returnValue = method.invoke(producer, money * 0.8f);
                        }
                        return returnValue;
                    }
                });
        proxyProducer.saleProduct(10000f);
    }
}
2. CGLIB agent

The target object is a class, based on the dynamic proxy of subclass, the proxy class cannot be the final class, that is, the class decorated with final cannot create the proxy object.
Using the create method in the Enhancer class, the parameters of the create method are:

  • Class: bytecode
    Bytecode used to specify the proxy object.
  • Callback: code to provide enhancements
    Write the details of the agent. Generally, it is to write an implementation class of the interface. Generally, it is an anonymous internal class, but it is not necessary.
    The implementation classes of this interface are written by who. Generally, they are written by the sub interface implementation classes of this interface: MethodInterceptor
public class Client2 {

    public static void main(String[] args) {
        final Producer producer = new Producer();

        Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * Any method of executing the North Ali object will pass through this method
             * @param proxy
             * @param method
             * @param args
             *    The above three parameters are the same as those of the invoke method in the interface based dynamic proxy
             * @param methodProxy : Proxy object of current execution method (not commonly used)
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //Provide enhanced code
                Object returnValue = null;
                //1. Get the parameters of method execution
                Float money = (Float) args[0];
                //2. Judge whether the current method is sales or not
                if ("saleProduct".equals(method.getName())) {
                    returnValue = method.invoke(producer, money * 0.8f);
                }
                return returnValue;
            }
        });
        cglibProducer.saleProduct(12000f);
    }
}

3, Here comes the point

1. concept

AOP (aspect oriented programming) is called: aspect oriented programming, which is a kind of programming idea.
AOP adopts horizontal extraction mechanism to replace the traditional vertical inheritance system repetitive code writing method (application scenarios: performance monitoring, transaction management, security check, cache, log recording, etc.)

2. Relevant terms
  • Joinpoint:
    The so-called connection points refer to those intercepted points. In spring, these points refer to methods, because spring only supports connection points of method type.
  • Pointcut:
    The so-called entry point refers to the definition of which joinpoints we want to intercept.
  • Advice:
    The so-called notification refers to the notification that is the thing to be done after the Joinpoint is intercepted.
    Notification types: pre notification, post notification, exception notification, final notification, and surround notification.
  • Target:
    The target object of the agent.
  • Weaving:
    The process of applying enhancements to a target object to create a new proxy object.
    spring uses dynamic proxy weaving, while AspectJ uses compile time weaving and class load time weaving.
  • Proxy:
    When a class is enhanced by AOP weaving, a result proxy class is generated.
  • Aspect:
    Class is a combination of pointcuts and notifications (referrals).
  • Introduction:
    Introduction is a special kind of notification. Without modifying the class code, introduction can dynamically add some methods or fields to the class at runtime.
3. dependence
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.7</version>
</dependency>
4. Configuration steps of AOP based on XML
  • 4.1. Leave the notification Bean to spring for management
  • 4.2. Use the aop:config tab to indicate the start of AOP configuration
  • 4.3. Use aop:aspect tag to indicate configuration aspect
    id attribute: provides a unique id for the facet
    ref property: is the Id of the specified notification class bean
  • 4.4. Use the corresponding tag inside the aop:aspect tag to configure the notification type
    Let's say the printLog method is executed before the pointcut method is executed: so it's a pre notification
    aop:before: indicates configuration pre notification
    Method property: used to specify which method in the Logger class is a pre notification
    Pointcut property: used to specify the pointcut expression. The meaning of the expression refers to which methods in the business layer are enhanced

How to write pointcut expressions:
Keyword: execution (expression)

<!-- To configure Logger class -->
<bean id="logger" class="com.donglei.utils.Logger"></bean>

<!--To configure AOP-->
<aop:config>
	<!--Configuration section -->
	<aop:aspect id="logAdvice" ref="logger">
	<!-- Configure the type of notification and associate the notification method with the pointcut method-->
	<aop:before method="printLog" pointcut="execution(void   com.donglei.service.AccountServiceImpl.saveAccount())"></aop:before>
	<aop:before method="printLog" pointcut="execution(void com.donglei.service.AccountServiceImpl.updateAccount(int))"></aop:before>
	<aop:before method="printLog" pointcut="execution(int com.donglei.service.AccountServiceImpl.deleteAccount())"></aop:before>
	</aop:aspect>
</aop:config>
5. Writing of pointcut expression

Keyword: execution (expression)
Expression:
Parameter 1: access modifier (not required)
Parameter 2: return value (required)
Parameter 3: package name. Class name (not required)
Parameter 4: method name (parameter) (required)
Parameter 5: exception (not required)
Access modifier return value package name. Package name. Package name Class name. Method name (parameter list)

Standard expression:
    public void com.donglei.service.AccountServiceImpl.saveAccount()
Access modifiers can be omitted
    void com.donglei.service.AccountServiceImpl.saveAccount()
The return value can use the wildcard (*: for any) to represent any return value
    * com.donglei.service.AccountServiceImpl.saveAccount()
The package name can use wildcards to represent any package. But if there are several levels of packages, you need to write several *
    * *.*.*.*.AccountServiceImpl.saveAccount())
The package name can use.. to represent the current package and its subpackages
    * *..AccountServiceImpl.saveAccount()
Class name and method name can use * to implement generic matching
    * *..*.*()
Parameter list:
    Data types can be written directly:
    Basic type write name int directly
    Reference type write package name. The way of class name is java.lang.String
    You can use wildcards to represent any type, but you must have parameters
    You can use.. to indicate whether there are parameters or not. Parameters can be of any type
 Full match method: * *. *. * (..)
The common way to write pointcut expressions in actual development: switch to all methods under the business layer implementation class: * com.donglei.service.. * (..)
Give an example:
<aop:before method="printLog" pointcut="execution(* com.donglei.service..*.*(..))">
</aop:before>
6. Five notification types

Pre notice, post notice, exception notice, final notice, surround notice

To configure

<! -- configure AOP -- >
<aop:config>
    <! -- configure the pointcut expression id property to specify the unique identity of the expression. The expression property specifies the expression content
          This label can only be used in the current section when written inside the aop:aspect label
          It can also be written outside aop:aspect, which becomes available for all aspects
      -->
    <aop:pointcut id="pt1" expression="execution(* com.donglei.service..*.*(..))"></aop:pointcut>
    <! -- configure facets -- >
    <aop:aspect id="logAdvice" ref="logger">
        <! -- configure pre notification: execute before the pointcut method executes
        <aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before>-->

        <! -- configure post notification: value after the pointcut method executes normally. It and exception notification can only execute one
        <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->

        <! -- configure exception notification: execute after the pointcut method execution generates an exception. It and post notification can only execute one
        <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->

        <! -- configure final notification: whether the pointcut method executes normally or not, it will execute after it
        <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->

        <! -- please refer to the Logger class for detailed comments on the configuration of surround notification -- >
        <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
    </aop:aspect>
</aop:config>

Example: log

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class Logger {
    /**
     * Before advice
     */
    public void beforePrintLog(JoinPoint jp) {
        System.out.println("Before advice Logger Class beforePrintLog Method started logging...");
    }
    /**
     * Post notification
     */
    public void afterReturningPrintLog(JoinPoint jp) {
        System.out.println("Post notification Logger Class afterReturningPrintLog Method started logging...");
    }
    /**
     * Exception notification
     */
    public void afterThrowingPrintLog(JoinPoint jp) {
        System.out.println("Exception notification Logger Class afterThrowingPrintLog Method started logging...");
    }
    /**
     * Final notice
     */
    public void afterPrintLog(JoinPoint jp) {
        System.out.println("Final notice Logger Class afterPrintLog Method started logging...");
    }
    /**
     * Around Advice
     * Question:
     * When we configured the orbit notification, the pointcut method did not execute, while the notification method did.
     * Analysis:
     * By comparing the dynamic proxy's surround notification code, we find that there are clear pointcut method calls in the dynamic proxy's surround notification code, but we don't have them in our code.
     * Solve:
     * Spring The framework provides us with an interface: ProceedingJoinPoint. The interface has a method, proceed(), which is equivalent to explicitly calling the pointcut method.
     * This interface can be used as the method parameter of surround notification. When the program is executed, the spring framework will provide us with the implementation class of this interface for us to use.
     * 
     * spring Orbit notification in:
     * It is a way that the spring framework provides us with the ability to manually control when the enhanced methods are executed in the code.
     */
    public Object aroundPringLog(ProceedingJoinPoint pjp) {
        Object rtValue = null;
        try {
            Object[] args = pjp.getArgs();//Get the parameters needed for method execution
            System.out.println("Logger Class aroundPringLog Method started logging... Preposition");
            rtValue = pjp.proceed(args);//Explicitly call business layer methods (pointcut methods)
            System.out.println("Logger Class aroundPringLog Method started logging... Postposition");
            return rtValue;
        } catch (Throwable t) {
            System.out.println("Logger Class aroundPringLog Method started logging... abnormal");
            throw new RuntimeException(t);
        } finally {
            System.out.println("Logger Class aroundPringLog Method started logging... Final");
        }
    }
}
Published 12 original articles, won praise 1, visited 91
Private letter follow

Tags: Spring JDK Programming xml

Posted on Wed, 15 Jan 2020 03:04:52 -0500 by bluejay002