书接上文《第4章:Java中代理模式的实现》 我们先使用Spring中自带的AOP来实现切片编程然后我们继续展开JavaSpring的AOP技术点。

1. 使用Pointcut切入点

1.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){
    }
  1. 在实际生产环境中,更多地时候使用通配符的方式
  • ‘*’ 多个字符匹配
  • 可以匹配一个或多个字符
  • 匹配任意类型的参数
  • *在进行匹配的时候只能匹配一层路径,不能匹配多层
  • *不能够匹配访问修饰符,如果不确定可以省略不写
  • 返回值可以使用*代替
  • ‘.’ 单个字符匹配
  • 可以匹配多个参数,任意类型
  • 可以匹配多层路径
  1. 在使用表达式的时候还支持逻辑运算
  • ‘&&’ 两个或多个条件必须满足
  • ‘||’ 两个中有一个满足
  • ‘!’ 取反

括号中各个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