AOP概念
AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华,OOP是纵向对事物的抽象,一个对象包含属性信息和动态的方法信息等,而AOP是横向对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而这种思想叫做界面编程
相关核心概念
名称 | 说明 |
Target | 目标对象,被增强方法所在的对象 |
proxy | 增强后的代理对象,实际调用的对象 |
joinpoint | 目标对象中可以被增强的方法 |
pointcut | 目标对象中实际被增强的方法 |
advice | 增强部分代码逻辑 就是通知 |
Aspect | 增强部分和切入点的组合 |
weaving | 将通知和切入点动态组合的过程 |
通知分类
通知 | 说明 |
before(前置通知) | 在切点方法之前执行增强方法 |
after(后置通知) | 在切点方法执行之后执行增强方法 |
after-returning(返回后通知) | 在切点方法返回之后执行增强方法 |
after-throwing(抛出异常通知) | 在切点方法抛出异常之后执行增强方法 |
around(环绕通知) | 通知方法封装切点方法环绕执行 |
Spring AOP两种使用方式
使用Spring自带的AOP
配置通知时需实现org.springframework.aop包下的一些接口
- 前置通知:MethodBeforeAdvice
- 后置通知:AfterReturningAdvice
- 环绕通知:MethodInterceptor
- 异常通知:ThrowsAdvice
public class LogAdvice implements MethodBeforeAdvice, AfterReturningAdvice,MethodInterceptor {
@Override
public void before(Method method, Object[] objects, Object target) throws Throwable {
//前置通知
}
@Override
public void afterReturning(Object result, Method method, Object[] objects, Object target) throws Throwable {
//后置通知
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
//环绕通知
//目标方法之前执行
methodInvocation.proceed(); //目标方法
//目标方法之后执行
return resultVal;
}
}
<bean id="userServiceBean" class="com.apesource.service.impl.UserServiceImpl"/>
<bean id="logAdviceBean" class="com.apesource.log.LogAdvice"/>
<bean id="createMethodPointcutBean" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<!--注入正则表达式:描述那些方法为切入点-->
<property name="pattern" value=".*creat.*"/>
</bean>
Advisor
Advisor(高级通知) = Advice(通知) + Pointcut(切入点)
<bean id="performanceAdvisorBean" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<!--注入切入点-->
<property name="pointcut" ref="createMethodPointcutBean"/>
<!--注入通知-->
<property name="advice" ref="logAdviceBean"/>
</bean>
使用Aspectj实现切面
<!--业务组件bean-->
<bean id="userServiceBean" class="com.apesource.service.impl.UserServiceImpl"/>
<!--日志Aspect切面-->
<bean id="logAspectjBean" class="com.apesource.log.LogAspectj"/>
<!--使用Aspectj实现切面,使用Spring AOP进行配置-->
<aop:config>
<!--配置切面-->
<!--注入切面bean-->
<aop:aspect ref="logAspectjBean">
<!--定义Pointcut:通过expression表达式,来查找 特定的方法(pointcut)-->
<aop:pointcut id="pointcut"
expression="execution(* com.apesource.service.impl.*.create*(..))"/>
<!--配置"前置通知"-->
<!--在pointcut切入点(serviceMethodPointcut)查找到 的方法执行"前",
来执行当前logAspectBean的doBefore-->
<aop:before method="beforeAdvice" pointcut-ref="pointcut"/>
<!--配置“后置通知”-->
<!--returning属性:配置当前方法中用来接收返回值的参数名-->
<aop:after-returning returning="returnVal"
method="afterReturningAdvice" pointcut-ref="pointcut"/>
<aop:after method="afterAdvice" pointcut-ref="pointcut"/>
<!--配置"环绕通知"-->
<aop:around method="aroundAdvice" pointcut-ref="pointcut"/>
<!--配置“异常通知”-->
<!--throwing属性:配置当前方法中用来接收当前异常的参数名-->
<aop:after-throwing throwing="ex" method="throwAdvice" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
Spring AOP的实现原理
Spring AOP 采用了两种混合的实现方式:JDK 动态代理和 CGLib 动态代理。
JDK动态代理:Spring AOP的首选方法。每当目标对象实现一个接口时,就会使用JDK动态代理。目标对象必须实现接口
CGLIB代理:如果目标对象没有实现接口,则可以使用CGLIB代理。文章来源:https://www.toymoban.com/news/detail-554759.htmlJDK动态代理基于接口,CGLIB代理基于类文章来源地址https://www.toymoban.com/news/detail-554759.html
spring注解实现AOP
package com.test.aop2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 注解方式声明aop
* 1.用@Aspect注解将类声明为切面(如果用@Component("")注解注释为一个bean对象,那么就要在spring配置文件中开启注解扫描,<context:component-scan base-package="com.cjh.aop2"/>
* 否则要在spring配置文件中声明一个bean对象)
* 2.在切面需要实现相应方法的前面加上相应的注释,也就是通知类型。
* 3.此处有环绕通知,环绕通知方法一定要有ProceedingJoinPoint类型的参数传入,然后执行对应的proceed()方法,环绕才能实现。
*/
@Component("annotationTest")
@Aspect
public class AnnotationTest {
//定义切点
@Pointcut("execution(* *.saying(..))")
public void sayings(){}
/**
* 前置通知(注解中的sayings()方法,其实就是上面定义pointcut切点注解所修饰的方法名,那只是个代理对象,不需要写具体方法,
* 相当于xml声明切面的id名,如下,相当于id="embark",用于供其他通知类型引用)
* <aop:config>
<aop:aspect ref="mistrel">
<!-- 定义切点 -->
<aop:pointcut expression="execution(* *.saying(..))" id="embark"/>
<!-- 声明前置通知 (在切点方法被执行前调用) -->
<aop:before method="beforSay" pointcut-ref="embark"/>
<!-- 声明后置通知 (在切点方法被执行后调用) -->
<aop:after method="afterSay" pointcut-ref="embark"/>
</aop:aspect>
</aop:config>
*/
@Before("sayings()")
public void sayHello(){
System.out.println("注解类型前置通知");
}
//后置通知
@After("sayings()")
public void sayGoodbey(){
System.out.println("注解类型后置通知");
}
//环绕通知。注意要有ProceedingJoinPoint参数传入。
@Around("sayings()")
public void sayAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("注解类型环绕通知..环绕前");
pjp.proceed();//执行方法
System.out.println("注解类型环绕通知..环绕后");
}
}
到了这里,关于spring 详解六 AOP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!