Spring:AOP学习笔记
什么是AOP?
AOP,面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。也就是代码在运行期间不改变源码,而是将类动态织入到源码指定位置而增加功能的一种编程思想。
AOP的实现方式
方式一(使用spring的API接口)
- 先创建一个类,实现spring的API接口实现你想实现的功能。
package com.huang.log;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//method:要执行目标对象的方法
//objects:参数
//o:目标对象
public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行前");
}
}
实现MethodBeforeAdvice接口在被代理方法执行前执行实现类方法。
package com.huang.log;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
//returnValue:返回值
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
}
}
实现AfterReturningAdvice接口在被代理方法执行后执行实现类方法。
- 配置aop:config:
<bean id="userService" class="com.huang.service.UserServiceImpl"/>
<bean id="log" class="com.huang.log.Log"/>
<bean id="afterLog" class="com.huang.log.AfterLog"/>
<!--方式一:使用spring的API接口-->
<!--配置AOP:导入AOP约束-->
<aop:config>
<!--切入点:id自取,expression:表达式,execution(返回值类型 类的完全限定名(.*(..))表示该类中的所有方法,方法后的参数不限)-->
<aop:pointcut id="pointcut" expression="execution(* com.huang.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加,将log类切入到上面定义的切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
方式二(自定义类实现)
- 先自定义一个类,并在类中创建需要动态织入的方法。
package com.huang.diy;
import org.aspectj.lang.ProceedingJoinPoint;
public class DiyPointCut {
public void before(){
System.out.println("==========方法执行前==========");
}
public void after(){
System.out.println("==========方法执行后==========");
}
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("方法环绕前");
Object proceed = jp.proceed();
System.out.println("方法环绕后");
}
}
配置aop:config:
<!--方式2:自定义类-->
<bean id="diy" class="com.huang.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面,ref 为要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.huang.service.UserServiceImpl.*(..))"/>
<!--method为自定义切面的方法,pointcut-ref为切入点-->
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
发现的问题?
<aop:around method="around" pointcut-ref="pointcut"/>
around属性定义在after和before前输出的值与定义在after和before后输出的值不一样。
around定义在after和before前:
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
输出:
around定义在after和before后:
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
输出:
方式三(注解配置)
自定义一个类,通过注解实现AOP:
package com.huang.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect //标注这个类只一个切面
public class AnnotationPointcut {
@Before("execution(* com.huang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("=============注解方法执行前=============");
}
@After("execution(* com.huang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("=============注解方法执行后=============");
}
//在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
@Around("execution(* com.huang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed();//执行方法
System.out.println("环绕后");
}
}
配置aop:config:
<!--方式3-->
<bean id="annotation" class="com.huang.diy.AnnotationPointcut"/>
<!--开启注解支持, JDK(默认proxy-target-class="false") cglib(proxy-target-class="true")-->
<aop:aspectj-autoproxy/>
发现问题:
当我使用最新版的Spring依赖时(5.2.8):
依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
输出结果为:
around()方法中的环绕后在after()方法的=注解方法执行后=输出之后才输出。
而我使用Spring的依赖为(5.2.0)时:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
输出结果:
around()方法的环绕后在after()方法的=注解方法执行后=输出之前又输出了。
注:以上两个问题我还没有搞懂,以后学习过程中再做补充说明。