书接上文《第4章:Java中代理模式的实现》 我们先使用Spring中自带的AOP来实现切片编程然后我们继续展开JavaSpring的AOP技术点。
1. 使用Pointcut切入点
1.1. 切入点表达式
- 最精确的匹配方式
//execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
@Pointcut("execution(* calc.MyCalculator.*(..))")
public void myPointCur(){}
@Before(value="myPointCur()")
public void start(JoinPoint pjp){
}
- 在实际生产环境中,更多地时候使用通配符的方式
- ‘*’ 多个字符匹配
- 可以匹配一个或多个字符
- 匹配任意类型的参数
- *在进行匹配的时候只能匹配一层路径,不能匹配多层
- *不能够匹配访问修饰符,如果不确定可以省略不写
- 返回值可以使用*代替
- ‘.’ 单个字符匹配
- 可以匹配多个参数,任意类型
- 可以匹配多层路径
- 在使用表达式的时候还支持逻辑运算
- ‘&&’ 两个或多个条件必须满足
- ‘||’ 两个中有一个满足
- ‘!’ 取反
括号中各个pattern分别表示:
- 修饰符匹配(modifier-pattern?)
- 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
- 类路径匹配(declaring-type-pattern?)
- 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
- 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(…)表示零个或多个任意参数
- 异常类型匹配(throws-pattern?)
其中后面跟着“?”的是可选项
我们使用Pointcut来实现切片,Pointcut多个匹配的表达式相同,使用Pointcut做抽象
2. 代码实现
2.1. pom文件引用
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringDemo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>SpringLearn</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.7</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
</dependencies>
</project>
2.2. 配置文件 applicationContextAspect.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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启包的扫描-->
<context:component-scan base-package="calc"></context:component-scan>
<!--开启包的扫描-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
2.3. 接口和实现代码
package calc;
import org.springframework.stereotype.Service;
public interface ICalculator {
/**
* 相加
* @param i
* @param j
* @return
*/
public Integer add(Integer i,Integer j);
/**
* 相减
* @param i
* @param j
* @return
*/
public Integer sub(Integer i,Integer j);
/**
* 相乘
* @param i
* @param j
* @return
*/
public Integer mul(Integer i,Integer j);
/**
* 相除
* @param i
* @param j
* @return
*/
public Integer div(Integer i,Integer j);
}
package calc;
import icoClass.IOCDemoClass;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
/**
* @Classname MyCalculator
* @Description 我的计算演示类
* @Date 2021/5/23 22:13
* @Created by xiaocai
*/
@Service
public class MyCalculator implements ICalculator {
public MyCalculator() {
System.out.println("MyCalculator初始化");
}
@Override
public Integer add(Integer i, Integer j) {
return i + j;
}
@Override
public Integer sub(Integer i, Integer j) {
return i - j;
}
@Override
public Integer mul(Integer i, Integer j) {
return i * j;
}
@Override
public Integer div(Integer i, Integer j) {
return i / j;
}
// @Autowired
// @Qualifier("IOCDemoClass")
private IOCDemoClass refIOCDemoClass=null;
public IOCDemoClass getRefIOCDemoClass() {
return refIOCDemoClass;
}
public void setRefIOCDemoClass(IOCDemoClass refIOCDemoClass) {
this.refIOCDemoClass = refIOCDemoClass;
}
}
2.4 纳入Spring管理的切片代码
package calc;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @Classname LogUtilAspect
* @Description 日志Spring切片
* @Date 2021/6/2 18:20
* @Created by xiaocai
*/
@Aspect
@Component
public class LogUtilAspect {
@Pointcut("execution(* calc.MyCalculator.*(..))")
public void myPointCur(){}
/**
* 函数开始执行信息
* @param method
* @param pars
*/
@Before(value="myPointCur()")
public void start(JoinPoint pjp){
System.out.println(String.format("函数[%s]开始执行,参数为:%s",pjp.getSignature().getName(), Arrays.asList(pjp.getArgs())));
}
/**
* 函数结束执行信息
* @param method
* @param pars
*/
@AfterReturning(value="myPointCur()")
public void stop(JoinPoint pjp){
System.out.println(String.format("函数[%s]开始完毕,返回值为:%s",pjp.getSignature().getName(),pjp.getSignature()));
}
/**
* 函数异常信息
* @param method
* @param pars
*/
@AfterThrowing(value="myPointCur()",throwing = "e")
public void logException(JoinPoint joinPoint,Exception e){
System.out.println(String.format("函数[%s]执行异常,异常信息为:%s",joinPoint.getSignature().getName(),joinPoint.getSignature().getName()));
}
/**
* 函数完毕信息
* @param method
* @param pars
*/
@After(value="myPointCur()")
public void logFinally(JoinPoint pjp){
System.out.println(String.format("函数[%s]开始完毕",pjp.getSignature().getName()));
}
}
2.5. Main函数
import calc.*;
import icoClass.IOCDemoClass;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.lang.reflect.Array;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @Classname SpringAspectDemoMain
* @Description 演示Mian方法
* @Date 2021/5/24 12:42
* @Created by xiaocai
*/
public class SpringAspectDemoMain {
static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContextAspect.xml");
public static void main(String[] args) {
// staticProxy();
// dynamicProxy();
// cGLibProxy();
ICalculator bean = context.getBean("myCalculator", ICalculator.class);
System.out.println(bean.add(10,10));
System.out.println(bean.sub(10,10));
System.out.println(bean.mul(10,10));
System.out.println(bean.div(10,10));
System.out.println(bean.div(10,0));
}
2.6. 执行结果
Connected to the target VM, address: '127.0.0.1:62162', transport: 'socket'
MyCalculator初始化
函数[add]开始执行,参数为:[10, 10]
函数[add]开始完毕,返回值为:Integer calc.ICalculator.add(Integer,Integer)
函数[add]开始完毕
20
函数[sub]开始执行,参数为:[10, 10]
函数[sub]开始完毕,返回值为:Integer calc.ICalculator.sub(Integer,Integer)
函数[sub]开始完毕
0
函数[mul]开始执行,参数为:[10, 10]
函数[mul]开始完毕,返回值为:Integer calc.ICalculator.mul(Integer,Integer)
函数[mul]开始完毕
100
函数[div]开始执行,参数为:[10, 10]
函数[div]开始完毕,返回值为:Integer calc.ICalculator.div(Integer,Integer)
函数[div]开始完毕
1
函数[div]开始执行,参数为:[10, 0]
函数[div]执行异常,异常信息为:div
函数[div]开始完毕
Exception in thread "main" java.lang.ArithmeticException: / by zero
at calc.MyCalculator.div(MyCalculator.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:49)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy17.div(Unknown Source)
at SpringAspectDemoMain.main(SpringAspectDemoMain.java:36)
Disconnected from the target VM, address: '127.0.0.1:62162', transport: 'socket'
Process finished with exit code 1