xml-based AOP in Spring

Keywords: Java Spring xml Maven Programming

1. The whole process of Aop is Aspect Oriented Programming, which is a technology for facet-oriented programming, to achieve the same maintenance of program functions through pre-compilation and run-time dynamic agents.Aop is the continuation of oop, a hot spot in software development, and an important content in Spring framework.It is a derived example of functional programming, which can be used to split parts of business logic with Aop, thus reducing the coupling between parts of business logic, improving the reusability of programs, and improving development efficiency.Simply put, it is to extract duplicate code from our program and enhance it by using dynamic proxy technology and existing methods without modifying the source code when it needs to be executed.

Related Terms

JoinPoint: Link points Those that are intercepted refer to methods in spring because spring only supports connection points of method type

Pointcut: The entry point is the definition of which JoinPont s we want to intercept

Advice: Notification/Enhancement Notification is what you do after intercepting a Joinpoint

Notification Type: Pre Notification, Post Notification, Exception Notification, Final Notification, Surround Notification

Introduction: Introduction is a special notification that Introductions can dynamically add methods or field s to a class at run time without modifying its class code

Target: Target object, target object of proxy

Weaving weaving is the process of applying enhancements to target objects to create new proxy objects. spring uses dynamic proxy weaving, AspectJ uses compile-time weaving and class-loading weaving

Proxy: Proxy, a result proxy class produced when a class is enhanced by Aop weaving

Aspect: Aspect is the combination of entry point and notification (introductory)

In spring, the framework decides which dynamic proxy method to use based on whether the target class implements an interface or not.

XMl-based AOP steps

1. Create a Maven project to introduce spring coordinates

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mingqi</groupId>
    <artifactId>SpringIOC</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2. Create business-tier interfaces:

package com.mingqi.services;
public interface IAccountService {
    /**
     * Simulate login account
     */
    void saveAccount();

    /**
     * Simulate account updates
     * @param id
     */
    void updateAccount(int id);

    /**
     * Simulate account deletion
     * @return
     */
    int deleteAccount();

}

3. Create Business Tier Implementation Class

package com.mingqi.services.impl;
import com.mingqi.services.IAccountService;
public class AccountServicesImpl implements IAccountService {
    public void saveAccount() {
        System.out.println("Save performed");
    }

    public void updateAccount(int id) {
        System.out.println("Update performed"+id);
    }

    public int deleteAccount() {
        System.out.println("Delete performed");
        return 0;
    }
}

4. Create Tool Class

package com.mingqi.utils;
import org.aspectj.lang.ProceedingJoinPoint;
/**
 * Tool class for user logging, which provides common code
 */
public class Logger {
    /**
     * For printing logs: plan for them to execute before the entry point method is executed (the entry point method is the business layer method)
     */
    public  void beforePrintLog(){
        System.out.println("Logger In class pringLog Method started logging.");
    }
    public  void afterReturningPrintLog()
    {
        System.out.println("after returning advise Logger In class beforePrintLog Method started logging.");
    }
    /**
     * Exception Notification
     */
    public void afterThrowingPrintLog()
    {
        System.out.println("Exception Notification Logger In class afterThrowingPrintLog Method started logging.");

    }
    /**
     * Final Notification
     */
    public void afterPrintLog()
    {
        System.out.println("Final Notification Logger In class afterPrintLog Method started logging.");
    }

    /**
     * Around Advice
     * Problem When we configured the surround notification, the entry point method did not execute and the notification method executed
     * Analysis: By comparing the surround notification codes in the dynamic proxy, we found that surround notifications in the dynamic proxy have explicit entry point method calls, but not in our code.
     * Solution: The Spring framework provides us with an interface: ProceedingJoinPoint.The interface has a method proceed(), which is equivalent to explicitly calling the method of the entry point
     *        This interface can be used as a parameter method to surround notifications, and the spring framework provides us with implementation classes for this interface to use when the program executes
     * spring Surround notifications in
     *      He's one of the ways the spring framework gives us manual control over when enhancements will execute in code
     * @param pjp
     * @return
     */
    public Object aroundPringLog(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try{
            Object[] args = pjp.getArgs();//Get the parameters required for method execution

            System.out.println("Logger In class aroundPringLog Method started logging.Front");

            rtValue = pjp.proceed(args);//Explicitly invoke business tier methods (entry point methods)

            System.out.println("Logger In class aroundPringLog Method started logging.Rear");

            return rtValue;
        }catch (Throwable t){
            System.out.println("Logger In class aroundPringLog Method started logging.abnormal");
            throw new RuntimeException(t);
        }finally {
            System.out.println("Logger In class aroundPringLog Method started logging.Final");
        }
    }
}

4. Create a bean configuration file

<?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"
       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">
       <!--Configure spring's IOC and service objects in it-->
       <bean id="accountSevice" class="com.mingqi.services.impl.AccountServicesImpl"></bean>
       <!-- xml-based OP configuration steps in spring
         1. Give the notification beans to spring to manage
         2. Use aop:config tag table name to start AOP configuration
         3. UseAop:aspectLabel indicates configuration facet
             id property: is to provide a unique identification for the facet
             ref attribute: is the id of the specified notification class
         4. InAop:aspectInside the label, use the corresponding label to configure the type of notification
             Our example now is to have the printlog method execute before the entry point method executes, so it is a pre-notification
             aop:before: Identify pre-notifications
                Method property: Used to specify which method in the Logger class is a pre-notification
                pointcut property: Used to specify an entry point expression that means which enhancements are made to methods in the business tier
                Writing of the entry point expression:
                   Keyword: execution
                   Expression: Access modifier return value package name. Package name. Package name.... Class name. Method name (parameter list)
                   Standard writing: public voidCom.mingqi.service.Impl.AccountServiceImpl.saveAccount()
                   Access modifiers can be omitted:voidCom.mingqi.service.Impl.AccountServiceImpl.saveAccount()
                   Return values can use wildcards to identify any return value: *com.mingqi.service.impl.AccountServiceImpl.saveAccount()
                   Package names can use wildcards to represent any package, but several levels of packages require writing * *. *. *.AccountServiceImpl.saveAccount()
                   Package names can be used..To represent the current package and its subpackages: * *.AccountServiceImpl.saveAccount()
                   Both class and method names can use * to achieve uniformity *. *. *();
                   Parameter list: You can write data types directly:
                                 The base type writes the name directly: int
                                 Write package names by reference type. How class names are written:java.lang.String
                                Wildcards can be used to identify any type, only parameters are required
                                You can use..To identify whether parameters are available or not, and parameters can be of any type

                      Full wildcard writing:
                    * *..*.*(..)
                   A common way to write entry point expressions in real-world development:
                          Cut to all methods of the business tier implementation class,*com.mingqi.service.impl. *. *(.));
         -->
       <!--Configure Logger class-->
       <bean id="logger" class="com.mingqi.utils.Logger"></bean>
       <!--Use aop:config tag table name to start AOP configuration-->
       <aop:config>
              <aop:pointcut id="pt1" expression="execution(* com.mingqi.services.impl.*.*(..))"></aop:pointcut>
              <!--UseAop:aspectLabel indicates configuration facet-->
              <aop:aspect id="LogAdvice" ref="logger">
                     <!--Configure Pre-Notification: Execute before the entry point method executes
                     <aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>-->

                     <!--Configuration Post Notification: Value after the entry point method has been properly executed.It and exception notifications can always execute only one
                          <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->
                     <!--Configure exception notifications: execute after the entry point method execution has generated an exception.It and post-notification can never execute more than one
                         <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->
                     <!--Configure final notification: the entry point method will execute after it whether it executes properly or not
                        <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->
                     <!--Configure surround notifications for detailed comments see the Logger class-->
                        <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
                    </aop:aspect>
             </aop:config>
       </beans>

6. Create test classes

package com.mingqi.test;
import com.mingqi.services.IAccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringIoc {
    @Test
    public void TestAccount()
    {
        ApplicationContext ac= new ClassPathXmlApplicationContext("beam.xml");
        IAccountService accountService=(IAccountService) ac.getBean("accountSevice");
        accountService.saveAccount();
        accountService.updateAccount(22);
        accountService.deleteAccount();
    }
}

 

Posted by Bikkebakke on Fri, 19 Jun 2020 17:58:24 -0700