Spring advanced source code notes: Code implementation and detailed analysis of three AOP configuration methods in Spring!

1. The configuration of AOP in Spring

In Spring's AOP configuration, like IoC configuration, 3 types of configuration methods are supported.

The first category: use XML configuration

The second category: use XML + annotation combination configuration

The third category: use pure annotation configuration

Two, three configuration AOP method code implementation in Spring

Requirement: The crosscutting logic code is to print the log, and hope to weave the logic of the print log into a specific location of the target method ( service layer transfer method )



This article refers to "Spring Advanced Source Notes", students who need to add assistant VX: C18173184271,备注一下从哪个平台加我的工作几年了!get it for free

1. XML Schema

SpringIt is a framework for modular development , use aop to introduce aop jar

  • coordinate
<dependency>
 	<groupId>org.springframework</groupId>
 	<artifactId>spring-aop</artifactId>
 	<version>5.1.12.RELEASE</version>
</dependency> 
<dependency>
 	<groupId>org.aspectj</groupId>
 	<artifactId>aspectjweaver</artifactId>
 	<version>1.9.4</version>
</dependency>
  • AOP core configuration
<!--
 Spring基于XML的AOP配置前期准备:在spring的配置文件中加入aop的约束
 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd 
 
 Spring基于XML的AOP配置步骤:
 	第一步:把通知Bean交给Spring管理
 	第二步:使用aop:config开始aop的配置
 	第三步:使用aop:aspect配置切面
 	第四步:使用对应的标签配置通知的类型
 		入门案例采用前置通知,标签为aop:before
-->
<!--把通知bean交给spring来管理-->
<bean id="logUtil" class="com.lagou.utils.LogUtil"></bean>

<!--开始aop的配置-->
<aop:config>
<!--配置切⾯-->
 	<aop:aspect id="logAdvice" ref="logUtil">
<!--配置前置通知-->
 	<aop:before method="printLog" pointcut="execution(public *
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou
.pojo.Account))"></aop:before>
 	</aop:aspect>
</aop:config>
  • detail
    • About pointcut expression
      above configuration enables to TransferServiceImplthe updateAccountByCardNomethod of enhanced before its implementation, the output of the logging statement. Here, we have come across a relatively unfamiliar name: pointcut expression , what does it do? Let's look down.
    • Concept and function
      Pointcut expression, also known as AspectJ pointcut expression , refers to a string that follows a specific grammatical structure, and its role is to enhance the connection point that conforms to the grammatical format . It is part of the AspectJ expression.
    • About AspectJ
      AspectJ is an AOP framework based on the Java language. Since version 2.0, the Spring framework has integrated the pointcut expression part of the AspectJ framework and began to support AspectJ pointcut expressions.
    • Example of using pointcut expression
全限定法名 	  访问修饰符 	  返回值 	  包名.包名.包名.类名.方法名(参数列表)
 			全匹配方式:
		public void
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
om.lagou.pojo.Account)
 访问修饰符可以省略
 		void
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
om.lagou.pojo.Account)
 返回值可以使用*,表示任意返回值
 *
com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
om.lagou.pojo.Account)
包名可以使用.表示任意包,但是有几级包,必须写几个
 *
....TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Accou
nt)
 包名可以使用..表示当前包及其子包
 *
..TransferServiceImpl.updateAccountByCardNo(com.lagou.pojo.Account
)
 		类名和方法名,都可以使用.表示任意类,任意方法
 		* ...(com.lagou.pojo.Account)
 		参数列表,可以使用具体类型
 		基本类型直接写类型名称 : int
 		引用类型必须写全限定类名:java.lang.String
 		参数列表可以使用*,表示任意参数类型,但是必须有参数
 		* *..*.*(*)
 		参数列表可以使用..,表示有无参数均可。有参数可以是任意类型
		 * *..*.*(..)
 		全通配方式:
 		* *..*.*(..)
  • Changing the configuration of the proxy mode
    As we have said before, when Spring chooses to create a proxy object, it will choose according to the actual situation of the proxy object. If the proxy object implements the interface, the dynamic proxy based on the interface is used. When the proxy object does not implement any interface, Spring will automatically switch to the dynamic proxy mode based on subclasses.
    But we all know that regardless of whether the proxy object implements an interface, as long as it is not a final modified class, the proxy object can be created in the way provided by cglib. Therefore, Spring also takes this situation into consideration and provides a configuration method to enforce the use of subclass-based dynamic proxy (ie cglib method). There are two ways to configure
  • Use aop:configlabel configuration
<aop:config proxy-target-class="true">
  • Use aop:aspectj-autoproxylabel configuration
<!--此标签是基于XML和注解组合配置AOP时的必备标签,表示Spring开启注解配置AOP的支持-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectjautoproxy>
  • Five notification types
    • Pre-notification
      configuration method: aop:beforelabel
<!--
 作用:
	 用于配置前置通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
 	method:用于指定前置通知的方法名称
 	pointcut:用于指定切入点表达式
 	pointcut-ref:用于指定切入点表达式的引用
-->
<aop:before method="printLog" pointcut-ref="pointcut1">
</aop:before>

Timing of execution

Pre-notification will always be executed before the pointcut method (business core method) is executed.

detail

Pre-notification can obtain the parameters of the pointcut method and enhance it.

  • Notification configuration method during normal execution
<!--
 作用:
 	用于配置正常执行时通知
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定后置通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
 -->
<aop:after-returning method="afterReturningPrintLog" pointcutref="pt1"></aop:after-returning>
  • Exception notification

Configuration method

<!--
 作用:
 	用于配置异常通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定异常通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
 
 -->
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"
></aop:after-throwing>

Timing of execution

The execution timing of the exception notification is after the execution of the entry point method (business core method) produces an exception, the exception notification is executed. If the execution of the pointcut method does not produce an exception, the exception notification will not be executed.

detail

The exception notification can not only obtain the parameters of the pointcut method execution, but also obtain the exception information generated by the pointcut method execution.

  • Final notification
    configuration
<!--
 作用:
 	用于配置最终通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定最终通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
-->
<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>

Timing of execution

The execution timing of the final notification is executed after the pointcut method (business core method) is executed and before the pointcut method returns. In other words, regardless of whether the execution of the pointcut method generates an exception, it will be executed before returning.

detail

When the final notification is executed, the parameters of the notification method can be obtained. At the same time it can do some cleaning operations.

  • Surround notification
    configuration
<!--
 作用:
 	用于配置环绕通知。
 出现位置:
 	它只能出现在aop:aspect标签内部
 属性:
	 method:用于指定环绕通知的方法名称
 	 pointcut:用于指定切入点表达式
	 pointcut-ref:用于指定切入点表达式的引用
 
 -->
<aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>

2. XML+ annotation mode

  • Open Spring's support for annotation AOP in XML
<!--开启spring对注解aop的支持-->
<aop:aspectj-autoproxy/>
  • Example
/**
* 模拟记录日志
* @author 应癫
*/

@Component
@Aspect
public class LogUtil {
    
    

 /**
 * 我们在xml中已经使用了通用切入点表达式,供多个切面使用,那么在注解中如何使用呢?
 * 第一步:编写一个方法
 * 第二步:在方法使用@Pointcut注解
 * 第三步:给注解的value属性提供切入点表达式
 * 细节:
 * 1.在引用切入点表达式时,必须是方法名+(),例如"pointcut()"。
 * 2.在当前切面中使用,可以直接写方法名。在其他切面中使用必须是全限定方法名。
 */
 @Pointcut("execution(* com.lagou.service.impl.*.*(..))")
 public void pointcut(){
    
    }
 
 @Before("pointcut()")
 public void beforePrintLog(JoinPoint jp){
    
    
 	Object[] args = jp.getArgs();
 	System.out.println("前置通知:beforePrintLog,参数是:"+ Arrays.toString(args));
 }
 
 @AfterReturning(value = "pointcut()",returning = "rtValue")
 public void afterReturningPrintLog(Object rtValue){
    
    
 	System.out.println("后置通知:afterReturningPrintLog,返回值是:"+rtValue);
 }
 
 @AfterThrowing(value = "pointcut()",throwing = "e")
 public void afterThrowingPrintLog(Throwable e){
    
    
 	System.out.println("异常通知:afterThrowingPrintLog,异常是:"+e);
 }
 
 @After("pointcut()")
 public void afterPrintLog(){
    
    
 	System.out.println("最终通知:afterPrintLog");
 }
 
 /**
 * 环绕通知
 * @param pjp
 * @return
 */
 
 @Around("pointcut()")
 public Object aroundPrintLog(ProceedingJoinPoint pjp){
    
    
 	//定义返回值
 	Object rtValue = null;
 	try{
    
    
 	
 		//前置通知
 		System.out.println("前置通知");
 		
 		//1.获取参数
 		Object[] args = pjp.getArgs();
 		
 		//2.执⾏切⼊点⽅法
 		rtValue = pjp.proceed(args);
 		
 		//后置通知
 		System.out.println("后置通知");
 	}catch (Throwable t){
    
    
 		//异常通知
 		System.out.println("异常通知");
 		t.printStackTrace();
 	}finally {
    
    
 		//最终通知
 		System.out.println("最终通知");
 		}
 	return rtValue;
	}
}

3. Annotation mode

When using annotation-driven development of aop, we have to make it clear that the annotation replaces the following line of configuration in the configuration file:

<!--开启spring对注解aop的支持-->
<aop:aspectj-autoproxy/>

Use the following annotations in the configuration class to replace the above configuration

/**
* @author 应癫
*/
@Configuration
@ComponentScan("com.lagou")
@EnableAspectJAutoProxy //开启spring对注解AOP的支持
public class SpringConfiguration {
    
    
}

If you need this full version 《Spring高级源码笔记》, you only need to support me in this article.

A lot of support, you can get information for free-after three consecutive years (promise: 100% free)

Quick start channel: add assistant VX: C18173184271,备注一下从哪个平台加我的工作几年了!get it for free! Full of sincerity! ! !

Spring interview feature article click here! ! !

Guess you like

Origin blog.csdn.net/Java_Caiyo/article/details/113096250