Understanding Spring AOP from an XML configuration perspective

This article is shared from the Huawei Cloud Community " Spring Master's Road 18 - Understanding Spring AOP from the perspective of XML configuration ", author: Zhuan Yeyang__.

1. Spring AOP and dynamic proxy

1.1 The relationship between Spring AOP and dynamic proxy

Spring AOPImplement aspect-oriented programming using dynamic proxies as its primary mechanism. This mechanism allows Springthe dynamic creation of proxy objects at runtime. These proxy objects wrap the target object (i.e. business component) to insert additional behaviors (such as security checks, transaction management, logging, etc.) before and after calling the target object's methods. .

  • JDK dynamic proxySpring AOP : The dynamic proxy used by default when the target object implements one or more interfaces JDK. JDKDynamic proxy uses the reflection mechanism to create a proxy object for the interface. This proxy object will intercept all calls to the target interface method.

  • CGLIB proxy : If the target object does not implement any interface, Spring AOPit will fall back to using CGLIBthe library to generate a subclass of the target class. CGLIB( Code Generation Library) is a powerful high-performance code generation library that extends Javaclasses at runtime and overrides methods in subclasses to implement method interception.

No matter which proxy method is used, the purpose is to insert additional behaviors at different stages of method execution through notifications defined by aspects without changing the original business logic code.

1.2 AOP basic terminology

Aspect : Aspect is the core of aspect-oriented programming. It is a construct that modularizes concerns across multiple classes (such as logging, transaction management, etc.). An aspect can contain multiple types of advice ( Advice) and one or more pointcuts ( Pointcut) that define where and when those advices are executed.

Join Point : A join point represents a specific location during program execution, Spring AOPlimiting these locations to method calls. Simply put, a join point is a point where aspect advice can be inserted.

Advice : Advice defines the action to be performed by the aspect at the connection point. Depending on the notification type, these actions can be performed before, after the method is called, after a result is returned, or when an exception is thrown. Notification types include:

  • Pre-notification ( Before advice): executed before the method is executed.
  • Post-notification ( After advice): Executed after the method is executed, regardless of its results.
  • Post-return notification ( After-returning advice): Executed after the method is successfully executed.
  • Post-exception notification ( After-throwing advice): Executed after the method throws an exception.
  • Surround advice ( Around advice): Executed before and after method execution, providing full control over method calls.

Pointcut (Pointcut) : Pointcut is an expression. Pointcut expressions allow matching connection points through method names, access modifiers and other conditions, which determines which methods should be triggered when notifications are executed.

Target Object : An object that is notified by one or more aspects. Also called a proxied object.

AOP Proxy : AOPAn object created by the framework to implement aspect contracts (defined by advice and pointcuts). In Spring AOP, AOPa proxy can be JDKa dynamic proxy or CGLIBa proxy.

Introduction : Introduction allows adding new methods or properties to an existing class. This is Introduction interfacesachieved by defining one or more additional interfaces ( ), and AOPthe framework creates a proxy for the target object that implements these interfaces.

If it still feels abstract, let’s give another example of film production as an analogy.

Aspect

Imagine someone is filming a movie, and the special effects in the movie (such as explosions and special lighting effects) are like cross-cutting concerns that need to be handled in the application (such as logging or transaction management). These special effects appear in many different scenes of the movie, not just in one specific scene. In AOPPython, these "effects" are aspects, and they can be applied to multiple parts of the program without changing the actual scene (or code).

Join Point

Continuing with the movie metaphor, a specific moment in each scene, such as the moment an explosion occurs, can be seen as a connecting point. In programming, this usually corresponds to a method call.

Advice

Notifications are like specific instructions from the director to the special effects team, such as "Add an explosion effect before this scene starts" or "Show the smoke dissipating effect after the scene ends." These instructions tell the special effects team at which specific effects should be added at specific moments in the film. In AOP, these "instructions" are notifications, specifying that aspects (special effects) should be executed before, after, or around join points (specific code execution moments).

Pointcut

If the notice is the director's instruction to the special effects team, then the cutting point is the specific conditions contained in the instruction, such as "all night location scenes." Pointcuts define which connection points (such as which specific method calls) should receive notifications (effect instructions).

Target Object

The target objects are those scenes where special effects need to be added. In our programming metaphor, they are those objects that are affected by aspect logic (such as classes that require logging).

AOP Proxy

AOPA proxy is like a virtual, controllable copy of a scene provided by the special effects team. This copy appears to the audience to be the same as the original scene, but in fact it automatically adds special effects when the director needs them. In programming, a proxy is an AOPobject automatically created by the framework. It wraps the target object and ensures that notifications (special effect instructions) are executed at the correct time.

Introduction

Introduction is like adding a brand new character or scene to a movie that does not exist in the original script. In AOP, introduction allows us to add new methods or properties to an existing class, which is like extending the content of a movie without changing the original script.

2. Implement Spring AOP through XML configuration

SpringProvides rich AOPsupport, and can XMLdefine aspects, notifications ( advice) and pointcuts ( pointcuts) through configuration. This allows you to add additional behaviors (such as logging, transaction management, etc.) without modifying the source code.

Implementation steps:

  1. Add Spring dependenciespom.xml : Add Springframework and AOPrelated dependencies to the project .

  2. Define business interfaces and implementation classes : Create business logic interfaces and their implementations, such as a simple service class.

  3. Define aspect classes : Create an aspect class to define pre-, post-, and wrap-around notifications.

  4. Configuration XML : applicationContext.xmlConfigure aspects, business bean, and AOPrelated tags in XML.

2.1 Add Spring dependency

In pom.xmlthe file, add the following dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.10</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.10</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>
</dependencies>

2.2 Define business interfaces and implementation classes

First, we define a business logic interface MyServiceand its implementation MyServiceImpl.

MyService.java:

package com.example.demo.aop;
public interface MyService {
    String performAction(String input) throws Exception;
}

MyServiceImpl.java:

package com.example.demo.aop;
public class MyServiceImpl implements MyService {
    @Override
    public String performAction(String action) throws Exception {
        System.out.println("Performing action in MyService: " + action);
        if ("throw".equals(action)) {
            throw new Exception("Exception from MyService");
        }
        return "Action performed: " + action;
    }
}

2.3 Define aspect classes

Next, we define an aspect class MyAspectthat will contain a pre-advice ( advice) that is executed before MyServicethe performActionmethod is executed.

MyAspect.java:

package com.example.demo.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {

    // pre-notification
    public void beforeAdvice() {
        System.out.println("Before advice is running!");
    }

    // post notification
    public void afterAdvice() {
        System.out.println("After advice is running!");
    }

    // Notify after return
    public void afterReturningAdvice(Object retVal) {
        System.out.println("After returning advice is running! Return value: " + retVal);
    }

    // Notification after exception
    public void afterThrowingAdvice(Throwable ex) {
        System.out.println("After throwing advice is running! Exception: " + ex.getMessage());
    }

    //surround notification
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around advice: Before method execution");
        Object result = null;
        try {
            result = joinPoint.proceed();
        } finally {
            System.out.println("Around advice: After method execution");
        }
        return result;
    }
}

2.4 Configuration XML

Finally, we need to configure the above and related content in Springthe configuration file .applicationContext.xmlbeanAOP

applicationContext.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"
       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">
<!-- 
The above is the header declaration of the XML file, which defines the version and encoding type of the file, and introduces the namespace of Spring beans and AOP.
Through these namespaces, we can use <bean> and <aop:*> tags in XML.
-->
    <!-- Bean definitions -->
    <bean id="myService" class="com.example.demo.aop.MyServiceImpl"/>
    <bean id="myAspect" class="com.example.demo.aop.MyAspect"/>
	<!-- AOP configuration-->
    <aop:config>
        <!-- Define aspects and their notifications -->
        <aop:aspect id="myAspectRef" ref="myAspect">
            <!-- Define pointcuts and specify notifications that should be triggered when methods are executed -->
            <aop:pointcut id="serviceOperation" expression="execution(* com.example.demo.aop.MyService.performAction(..))"/>
            <!-- Apply pre-notification, specify operations before method execution -->
            <aop:before method="beforeAdvice" pointcut-ref="serviceOperation"/>
            <!-- Apply post-notification, specify the operation after the method is executed, whether the method is executed successfully or an exception is thrown -->
            <aop:after method="afterAdvice" pointcut-ref="serviceOperation"/>
            <!-- Notification after the application returns, operations after the specified method is successfully executed and returned -->
            <aop:after-returning method="afterReturningAdvice" pointcut-ref="serviceOperation" returning="retVal"/>
            <!-- Notification after application exception, action after specified method throws exception -->
            <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="serviceOperation" throwing="ex"/>
            <!-- Apply surrounding notifications to provide complete control before and after method execution -->
            <aop:around method="aroundAdvice" pointcut-ref="serviceOperation"/>
        </aop:aspect>
    </aop:config>
</beans>

myService : This is business logic beanand points to MyServiceImplan instance of the class.

myAspect : This is aspect bean, pointing to MyAspectan instance of the class.

<aop:config>: This is AOPthe root element of the configuration. All AOPconfigurations, including aspect definitions, pointcuts and notification methods, need to be defined inside this element.

Aspect : Defined through <aop:aspect>elements, it contains a series of advices ( advice) and one or more pointcuts ( pointcut). This element associates aspect classes (classes that contain notification logic) with specific operations (how and when to enhance the target object).

Pointcut : Through <aop:pointcut>element definition, pointcut is specified by expression. When you need to precisely control which methods will trigger notifications when executed, you need to define pointcut. Pointcut expressions can specify methods very precisely, for example by method name, parameter types, annotations, etc. expressionIt defines the expression of the pointcut and specifies the matching rules of the pointcut. The expression here execution(* com.example.demo.aop.MyService.performAction(..))means that the pointcut matches the execution of the method MyServicein the interface performAction, and the pointcut is used to specify at which connection points ( Join Pointsuch as method calls) the notification is applied.

About parsing expressionsexecution(* com.example.demo.aop.MyService.performAction(..))

execution : is the most commonly used pointcut function, used to match the connection points of method execution.

*: Indicates that the return type of the method is arbitrary.

com.example.demo.aop.MyService.performAction : Specifies the full path of the interface name and method name.

(…) : Indicates that the method parameters are arbitrary and will match regardless of how many parameters the method has.

  • Join Point : A join point refers to a certain point during program execution, such as a method call. Join points are identified and matched  by pointcut ( ) expressions, which define a pointcut that specifies an explicit set of join points—that is, all invocations of methods of the interface . In this example, the interface method calls are potential connection points. Each time a method is called, a join point is reached . This connection point is where the application is notified of its timing.Pointcutexecution(* com.example.demo.aop.MyService.performAction(..))MyServiceperformActionMyServiceperformActionperformAction

  • Advice : This is an AOPaction that enhances the execution of a method by performing actions at specific times. methodThe attribute specifies the method name of the aspect that should be executed when the pointcut matches, pointcut-refreferencing the pointcut defined above. For example, here is the method that is called before beforeAdvicethe target method is executed. performActionThis means that whenever MyService.performAction(..)a method is called, beforeAdvicethe method will be executed first.

To sum up in one sentence: Spring AOPBy defining rules (cut points) in aspects to specify when (connection points) and how (notifications) to enhance specific methods, the modularization of the code and separation of concerns are achieved without modifying the original business logic.

In this way, Spring AOP you can define custom logic to be inserted before, after, or around execution of a specific method without modifying the original business logic code. This is a powerful mechanism for achieving separation of concerns, especially for cross-cutting concerns that span multiple parts of the application (such as logging, transaction management, etc.).

Note that if <aop:config>set to

<aop:config proxy-target-class="true">
    <!--Other configuration remains unchanged-->
</aop:config>

Setting this proxy-target-class="true"will cause the proxy Spring AOPto be used in preference CGLIBeven if the target object implements the interface. By default, proxy-target-classthe property does not need to be set, or if it is set false, a dynamic proxy is used JDK.

Main program:

DemoApplication.java:

package com.example.demo;

import com.example.demo.aop.MyService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoApplication {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        MyService myService = (MyService) context.getBean("myService");

        try {
            System.out.println(myService.performAction("normal"));
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("=======================");

        try {
            System.out.println(myService.performAction("throw"));
        } catch (Exception e) {
            System.out.println("Exception caught in main: " + e.getMessage());
        }

        context.close();
    }
}

operation result:

By combining dynamic proxy technology with these AOPconcepts, Spring AOPapplications can be provided with support for cross-cutting concerns in a non-intrusive way, allowing developers to modularize these concerns and keep business logic components focused and simple.

If you are interested in the dynamic proxy, you can debug it again. JDKThe dynamic proxy here is because public class MyServiceImpl implements MyService the interface is implemented. The debugging is as follows:

Let’s briefly talk about the key classes and interfaces that can be seen here.

ProxyFactory : This is Spring AOPa factory class used to create proxy objects. It can decide to use JDKdynamic proxy or proxy based on whether the target object implements the interface CGLIB.

AopProxy : This interface defines methods for obtaining proxy objects. It has two main implementations: JdkDynamicAopProxy(for JDKdynamic proxies) and CglibAopProxy(for CGLIBproxies).

JdkDynamicAopProxy : Implements AopProxythe interface and uses JDKdynamic proxy technology to create a proxy. It implements InvocationHandlerthe interface and intercepts all method calls to the proxy object.

CglibAopProxy : Also implements AopProxythe interface, but uses CGLIBa library to create proxy objects. For classes that do not implement the interface, Springthis method will be chosen to create the proxy.

If you want to understand Spring AOPthe source code in depth, you can directly view JdkDynamicAopProxythe CglibAopProxyimplementation of these two classes. This is not the focus of this article, just briefly mention:

For example, JdkDynamicAopProxysee the implementation of dynamic proxy in:

  1. JdkDynamicAopProxyClasses implement InvocationHandlerinterfaces, which are JDKthe core of dynamic proxying. In its invokemethod, there will be logic to determine whether the call needs to be intercepted, and corresponding notifications will be applied before and after the call.

  2. The process of creating a proxy is mainly done ProxyFactoryby calling createAopProxy()a method, which returns an instance of JdkDynamicAopProxyor according to the configuration CglibAopProxy.

  3. Use of proxy: The client code ProxyFactoryobtains the proxy object and calls the target method through this proxy object. The proxy object uses JdkDynamicAopProxyor internally CglibAopProxyto intercept these calls and AOPperform notifications based on configuration. The process of obtaining ProxyFactorya proxy object Springis usually done implicitly in the configuration and usage, especially when using Springcontainer management AOP. This process does not require the developer to call ProxyFactorythe class directly. When Springone is defined in the configuration beanand an aspect is applied to it, Springthe container automatically handles the process of creating the agent and applying notifications. This is achieved through Springpost-processor and AOPnamespace support, and developers usually only need to configure aspects and advice declaratively.

If you want to see CGLIBthe agent, here 2is a way

The third 1method is to remove the MyServiceImplimplemented interface, and then change the corresponding place between MyServicethe main program and the expression . The third way is to explicitly set the label's properties in the configuration file to achieve this. as follows:expressionMyServiceImpl
2Spring<aop:config>proxy-target-class="true"

<aop:config proxy-target-class="true">
    <!--Other configuration remains unchanged-->
</aop:config>

Debugging is as follows:

 

Welcome to one-click triple connection~

If you have any questions, please leave a message and let’s discuss and learn together.

Click to follow and learn about Huawei Cloud’s new technologies as soon as possible~

 

RustDesk suspended domestic service Taobao (taobao.com) due to rampant fraud, restarted web version optimization work, Apple released M4 chip, high school students created their own open source programming language as a coming-of-age ceremony - Netizens commented: Relying on the defense, Yunfeng resigned from Alibaba, and plans to produce in the future Visual Studio Code 1.89, the destination for independent game programmers on the Windows platform, is officially announced by Huawei. Yu Chengdong’s job adjustment was nailed to the “FFmpeg Pillar of Shame” 15 years ago, but today he has to thank us - Tencent QQ Video avenges its previous shame? The open source mirror station of Huazhong University of Science and Technology is officially open to external network access
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4526289/blog/11106069