Spring learning summary notes [VII. AOP aspect oriented programming]

Previous articles:

Spring learning summary notes [I. quick start]
Spring learning summary notes [II. IoC inversion of control]
Spring learning summary notes [III. annotation development]
Spring learning summary notes [IV. integrating Junit]
Spring learning summary notes [v. configuring data sources]
Spring learning summary notes [VI. integration of Mybatis]

1, Introduction to AOP

  • AOP is Aspect Oriented Programming, which is a technology to realize the unified maintenance of program functions through precompiled mode and runtime dynamic agent.
  • AOP is the continuation of OOP (Object Oriented Programming). It is a hot spot in software development, an important content in Spring framework, and a derivative paradigm of functional programming. AOP can isolate all parts of business logic, which reduces the coupling between all parts of business logic, improves the reusability of programs, and improves the efficiency of development.
  • Spring concept: non intrusive / non intrusive

1. Role and advantages of AOP

  • Function: enhance the function of the original design without disturbing it.
  • Advantages: reduce duplicate code, improve development efficiency, and facilitate maintenance.

2. AOP underlying implementation

The bottom layer of AOP is realized through the dynamic proxy technology provided by Spring. During the running period, Spring dynamically generates proxy objects through dynamic proxy technology. When the proxy object method is executed, it can enhance the function by calling the method of the target object.

3. Dynamic agent technology of AOP

Commonly used dynamic agent technology

  • JDK proxy: interface based dynamic proxy technology
  • cglib proxy: dynamic proxy technology based on parent class (third-party technology integrated by Spring)

1. JDK dynamic agent

JDK dynamic agent is implemented based on interceptors and reflection. It does not need the support of third-party libraries, but only the JDK environment

  • InvocationHandler interface must be implemented;
  • Use proxy Newproxyinstance generates proxy objects;
  • The proxy object must implement the interface;
  • asm technology is used internally to dynamically generate bytecode;

The steps are as follows:
① Define target interface

public interface TargetInterface {
    public void method();
}

② Define the target class and implement the TargetInterface

public class Target implements TargetInterface{
	@Override
	public void  method(){
		System.out.println("implement method......");
	}
}

③ Define enhanced classes

public class Advice {
	public void before(){
		System.out.println("before......");
	}
	public void after(){
		System.out.println("after......");
	}
}

④ Dynamic proxy code

public static void main(String[] args) {
	// Target object
	Target target = new Target();
	// Target object class loader
	ClassLoader classLoader = target.getClass().getClassLoader();
	// Enhancement object
	Advice advice = new Advice();
	
	// Three parameters for creating proxy objects
	TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
			classLoader,
			// An array of interface bytecode objects with the same target pair correlation
			new Class[]{TargetInterface.class},
			// The return value is the dynamically generated proxy object
			new InvocationHandler() {
				// Any method that invokes a proxy object actually executes the invoke method
				@Override
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					// Pre enhancement
					advice.before();
					Object result = method.invoke(target, args);// Implementation target method
					// Post enhancement
					advice.after();
					return result ;
				}
			}
	);
	// Call the method of the proxy object
	proxy.method();
}

Execution effect:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

The code itself is very simple, and the most important thing is proxy For the newproxyinstance method, it is important to understand the parameters. Explain the meanings of the following parameters respectively:

  • classLoader, class loader;
  • interfaces, target object interface;
  • InvocationHandler, which really completes the processor of the relevant method reflection agent;

The key step of JDK dynamic proxy is to execute the method reflection call of the target implementation class in the InvocationHandler

2. cglib dynamic proxy

JDK implementation of dynamic proxy requires implementation classes to define business methods through interfaces. For classes without interfaces, how to implement dynamic proxy? This requires cglib;
cglib adopts very low-level bytecode technology. Its principle is to create a subclass for a class through bytecode technology, and use method interception technology in the subclass to intercept the calls of all parent class methods, so as to weave crosscutting logic.
The steps are as follows:
① Import cglib coordinates (because cglib is a third-party tool, we need to import cglib coordinates before using it. In the early version of Spring, we need to import cglib coordinates manually, but the higher version of Spring has integrated cglib into the Spring framework, so we can use it directly)

② Define target class

public class Target  {
	public void  method(){
		System.out.println("implement method......");
	}
}

③ Define enhanced classes

public class Advice {
	public void before(){
		System.out.println("before......");
	}
	public void after(){
		System.out.println("after......");
	}
}

④ Dynamic proxy code

public static void main(String[] args) {
	// Target object
	final Target target = new Target();
	// Get enhanced object
	Advice advice = new Advice();
	// Create proxy object based on cglib
	// 1. Create intensifier
	Enhancer enhancer = new Enhancer();
	// 2. Set parent class
	enhancer.setSuperclass(Target.class);
	// 3. Set callback
	enhancer.setCallback(new MethodInterceptor() {
		@Override
		public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
			// Perform pre enhancement
			advice.before();
			// Implementation target method
			Object invoke = method.invoke(target, args);
			// Perform post enhancement
			advice.after();
			return invoke;
		}
	});
	// 4. Create proxy object
	Target proxy = (Target) enhancer.create();
	// The method that executes the proxy object ultimately executes the target method
	proxy.method();
}

Execution effect:

4. Core concepts of AOP

The bottom layer of Spring's AOP implementation is to encapsulate the code of the above dynamic proxy. After encapsulation, we only need to code the parts that need attention, and complete the method enhancement of the specified goal through configuration.
Before formally explaining the operation of AOP, we must understand the relevant terms of AOP. The commonly used terms are as follows:

  • Target: the target object of the proxy
  • Proxy: after a class is woven and enhanced by AOP, a resulting proxy class is generated
  • Joinpoint: the so-called connection point refers to the points that are intercepted. In Spring, these points refer to methods, because Spring only supports connection points of method types.
  • Pointcut: the so-called pointcut refers to the definition of which joinpoints we want to intercept.
  • Advice (notification / enhancement): the operation performed at the pointcut, that is, the common functions to be done after intercepting the Joinpoint. In Spring, the functions are finally presented in the form of methods.
  • Aspect: it is the combination of pointcut and notification (Introduction), which describes the corresponding relationship between notification and pointcut.
  • Weaving: refers to the process of applying enhancements to the target object to create a new proxy object. Spring uses dynamic proxy weaving, while AspectJ uses compile time weaving and class loading time weaving.

2, Clear matters of AOP development

1. Preparation content

  • Write core business code (target method of target class)
  • Write aspect classes, in which there are notifications (enhancement methods)
  • In the configuration file, configure the weaving relationship, that is, which notifications are combined with which connection points

2. Content of AOP technology implementation

The Spring framework monitors the execution of pointcut methods. Once the pointcut method is monitored to be running, the proxy mechanism is used to dynamically create the proxy object of the target object. According to the notification category, the corresponding function of the notification is woven into the corresponding position of the proxy object to complete the complete code logic operation.

3. Which proxy method is used at the bottom of AOP

In spring, the framework will decide which dynamic proxy method to adopt according to whether the target class implements the interface.

  • jdk dynamic proxy is used by default, which can proxy all interface types;
  • If the target object does not implement any interface, cglib proxy is used by default;
  • cglib can be used forcibly, specifying proxy target class = "true" or based on the annotation @EnableAspectJAutoProxy(proxyTargetClass = true)

3, AOP development based on xml

1. Introductory cases

① Import coordinates

<!--Import spring of context Coordinates, context rely on aop-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.0.5.RELEASE</version>
</dependency>
<!-- aspectj Weaving in of -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.13</version>
</dependency>

② Create target interface and target class (with internal tangency)

public interface TargetInterface {
	public void method();
}
public class Target  implements TargetInterface{
	public void  method(){
		System.out.println("implement method......");
	}
}

③ Create facet class

public class MyAspect {

	public void before(){
		System.out.println("Before advice ......");
	}
}

④ Give the object creation right of the target class and facet class to Spring

<!--    Target object-->
<bean id="target" class="com.tyt.xml.Target"/>
<!--    Tangent object-->
<bean id="myAspect" class="com.tyt.xml.aspect.MyAspect"/>

⑤ Configure weaving relationship

<!--    Configure weaving, tell Spring Framework, which methods (pointcuts) need to be enhanced (pre and post)-->
<aop:config>
	<!--    Declare facet-->
	<aop:aspect ref="myAspect">
		<!--Tangent plane: tangent point + notice-->
		<aop:before method="before" pointcut="execution(public void com.tyt.xml.Target.method())"/>
	</aop:aspect>
</aop:config>

Test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestXmlDemo {

	@Autowired
	private TargetInterface target;
	
	@Test
	public void test1(){
		target.method();
	}
}

2. Detailed explanation of XML configuration AOP

1. Detailed explanation of tangent expression

Expression syntax:

execution([Modifier ] Return value type package name.Class name.Method name(parameter))
  • Access modifiers can be omitted
  • The return value type, package name, class name and method name can be represented by an asterisk *
  • A point between the package name and the class name Represents the class under the current package, two points Represents the classes under the current package and its sub packages
  • The parameter list can use two points Represents any number and any type of parameter list

e.g:

 <!--Specify full-->
execution(public void com.tyt.aop.Target.method())
<!--Omit the modifier, any method, parameter: Target Any method and any parameter under class-->
execution(void com.tyt.aop.Target.*(..)) 
<!--Omit the modifier, any class, method, parameter: aop Any method and any parameter of any class under the package-->
execution(* com.tyt.aop.*.*(..)) 
 <!--Omit the modifier, any class, method, parameter: aop Any method and any parameter of any class of package and its sub package-->
execution(* com.tyt.aop..*.*(..))
 <!--All arbitrary-->
execution(* *..*.*(..))

2. Notification type

Notification configuration syntax format:

<aop:Notification type method="Method name in facet class " pointcut="Tangent expression"></aop:Notification type>

Notification type:

1. Advance notice

The pre notification demonstrated in the above entry case specifies that the enhanced method is executed before the pointcut method.

2. Post notification

Specifies that the enhanced method is executed after the pointcut method.

① Configure post enhancement methods in facet classes

public class MyAspect {
	public void afterReturning(){
		System.out.println("Post notification......");
	}
}

② Configure weaving relationship

<aop:config>
	<!--    Declare facet-->
	<aop:aspect ref="myAspect">
		<!--Tangent plane: tangent point + notice-->
		<aop:after-returning method="afterReturning" pointcut="execution(public void com.tyt.xml.Target.method())"/>
	</aop:aspect>
</aop:config>

3. Surround notification

Specifies that the enhanced method is executed before and after the pointcut method.

① Configure the surround enhancement method in the facet class

public class MyAspect {
	/**
	*
	*  @Params ProceedingJoinPoint: Executing connection point = = tangent point
	*  @Return
	*/
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		System.out.println("Pre surround notification......");
		// Tangent method
		Object result = proceedingJoinPoint.proceed();
		System.out.println("Post surround notification......");
		return result;
	}
}

② Configure weaving relationship

<aop:config>
	<!--    Declare facet-->
	<aop:aspect ref="myAspect">
		<!--Tangent plane: tangent point + notice-->
		<aop:around method="around" pointcut="execution(public void com.tyt.xml.Target.method())"/>
	</aop:aspect>
</aop:config>

4. Abnormal notice

Specifies that the enhanced method is executed when an exception occurs.

① Configure exception throwing methods in faceted classes

public class MyAspect {
	public void afterThrowing(){
	 	System.out.println("Exception throw notification......");
	}
}

② Configure weaving relationship

<aop:config>
	<!--    Declare facet-->
	<aop:aspect ref="myAspect">
		<!--Tangent plane: tangent point + notice-->
		<aop:after-throwing method="afterThrowing" pointcut="execution(public void com.tyt.xml.Target.method())"/>
	</aop:aspect>
</aop:config>

③ Add 1 / 0 to the execution method to create a bug

public class Target  implements TargetInterface{
	public void  method(){
		int i = 1 / 0;
		System.out.println("implement method......");
	}
}

5. Final notice

Specifies that the enhanced method is executed whether there is an exception or not.

① Configure the final notification method in the facet class

public class MyAspect {
	public void after(){
		System.out.println("Final notice......");
	}
}

② Configure weaving relationship

<aop:config>
	<!--    Declare facet-->
	<aop:aspect ref="myAspect">
		<!--Tangent plane: tangent point + notice-->
		<aop:after-throwing method="afterThrowing" pointcut="execution(public void com.tyt.xml.Target.method())"/>
		<aop:after method="after" pointcut="execution(public void com.tyt.xml.Target.method())"/>
	</aop:aspect>
</aop:config>

③ Add 1 / 0 to the execution method to create a bug

public class Target  implements TargetInterface{
	public void  method(){
		int i = 1 / 0;
		System.out.println("implement method......");
	}
}

3. Extraction of tangent expression

When multiple enhanced pointcut expressions are the same, the pointcut expression can be extracted. In the enhancement, the pointcut ref attribute is used instead of the pointcut attribute to reference the extracted pointcut expression.

<!--Configure weaving, tell Spring Framework, which methods (pointcuts) need to be enhanced (pre and post)-->
<aop:config>
	<!--    Declare facet-->
	<aop:aspect ref="myAspect">
		<!--Extract tangent expression-->
		<aop:pointcut id="myPointcut" expression="execution(public void com.tyt.xml.Target.method())"/>
		
		<!--Tangent plane: tangent point + notice-->
		<!--<aop:before method="before" pointcut="execution(public void com.tyt.xml.Target.method())"/>-->
		<!--<aop:after-returning method="afterReturning" pointcut="execution(public void com.tyt.xml.Target.method())"/>-->
		<!--<aop:around method="around" pointcut="execution(public void com.tyt.xml.Target.method())"/>-->
		<!--<aop:after-throwing method="afterThrowing" pointcut="execution(public void com.tyt.xml.Target.method())"/>-->
		<!--<aop:after method="after" pointcut="execution(public void com.tyt.xml.Target.method())"/>-->
		
		<!--use pointcut-ref Attribute substitution pointcut Property to reference the extracted tangent expression-->
		<aop:before method="before" pointcut-ref="myPointcut"/>
		<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
		<aop:around method="around" pointcut-ref="myPointcut"/>
		<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
		<aop:after method="after" pointcut-ref="myPointcut"/>
	</aop:aspect>
</aop:config>

4, Annotation based AOP development

1. Introductory cases

① Create target interface and target class (with internal tangency)

public interface TargetInterface {
	public void method();
}
public class Target  implements TargetInterface{
	public void  method(){
		System.out.println("implement method......");
	}
}

② Create facet class

public class MyAspect {
	
	public void before(){
		System.out.println("Before advice ......");
	}
	
	public void afterReturning(){
		System.out.println("Post notification......");
	}
	
	/**
	*
	*  @Params ProceedingJoinPoint: Executing connection point = = tangent point
	*  @Return
	*/
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		System.out.println("Pre surround notification......");
		// Tangent method
		Object result = proceedingJoinPoint.proceed();
		System.out.println("Post surround notification......");
		return result;
	}
	
	public void afterThrowing(){
		System.out.println("Exception throw notification......");
	}
	
	public void after(){
		System.out.println("Final notice......");
	}
}

③ Give the object creation right of the target class and facet class to Spring

④ Using annotations to configure weaving relationships in faceted classes

⑤ Define Spring configuration classes

@Configuration
@ComponentScan("com.tyt.anno")
@EnableAspectJAutoProxy
public class SpringConfig {

}

Test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
public class TestAnnoDemo {
	@Autowired
	private TargetInterface target;
	
	@Test
	public void test1(){
		target.method();
	}
}

2. Detailed explanation of annotation configuration AOP

1. Annotation notification type

Configuration syntax:

@Notice notes("Tangent expression")

Notification type:

2. Extraction of tangent expression

Like configuring AOP with xml, we can extract the Pointcut expression. The extraction method is to define a method in the facet, define the Pointcut expression on this method with the @Pointcut annotation, and then reference it in the enhanced annotation. The details are as follows:

① Define tangent expression

@Component("myAspect")
@Aspect // Mark that the current class is a faceted class
public class MyAspect {

	// Define tangent expression
	@Pointcut("execution(public void com.tyt.anno.Target.method())")
	public void myPointcut(){}
	
	// Configure pre notification
	// @Before("execution(public void com.tyt.anno.Target.method())")
	@Before("myPointcut()")
	public void before(){
		System.out.println("Before advice ......");
	}
}

Next issue:

Spring learning summary notes [viii. Integrated Web environment]

Tags: Back-end Spring Proxy Pattern

Posted by bigsid on Sun, 17 Jul 2022 05:15:10 +0930