3 Spring AOP

3 Spring AOP

3.1 基础知识

3.1.1 AOP是什么

AOP是Aspect Oriented Programing的简称,译为面向切面编程。
AOP通过横向抽取机制为无法通过纵向继承体系进行抽象的重复新代码提供了解决方案。AOP将分散在各个业务逻辑代码中的相同代码通过横向切割的方式抽取到一个独立的模块中,去除和业务逻辑类的耦合。
AOP仅作为OOP的有益补充。

3.1.2 应用场景

具有横切逻辑的应用场合,如性能监控、访问控制、事务管理、日志记录。
如当某个方法需要进行性能监控时,必须调整方法代码,在方法体前后分别添加开启性能监控和结束性能监控的代码,这些非业务逻辑的性能监视代码破坏了业务类的纯粹性。通过代理的方式将业务方法中开启和结束性能监控的横切代码从业务类中完全移除,并通过JDK或CGLib动态代理技术将横切代码动态织入目标方法的相应位置。

3.1.3 实现方式

Spring AOP使用动态代理技术在运行期织入增强的代码。动态代理技术常用如下两种。

3.1.3.1 JDK动态代理

主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler。
InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。
Proxy利用InvacationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

3.1.3.2 CGLib 动态代理

CGLib采用底层的字节码技术,为类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。
实现MethodInterceptor接口,通过Enhancer为一个类创建动态代理对象,该代理对象通过扩展clazz实现代理,在该代理对象的intercept(Object obj, Method method, Object[] args,MethodProxy proxy)方法中,织入性能监视的横切逻辑。

3.1.3.3 JDK动态代理和CGLib 动态代理的区别

JDK在创建代理对象时的性能高于CGLib,而生成的代理对象的运行性能却比CGLib的低。如果是singleton 的代理,则推荐使用CGLib动态代理。

3.1.4 AOP术语

3.1.4.1.连接点(Joinpoint)

特定点是程序执行的某个特定位置,如类开始初始化前、类初始化后、类的某个方法调用前/调用后、方法抛出异常后。
一个类或一段代码拥有一些具有边界性质的特定点,这些代码中的特定点就被称为“连接点”。连接点即特定点。
Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时及方法调用前后这些程序执行点织入增强。
连接点由两个信息确定:一是用方法表示的程序执行点;二是用相对位置表示的方位。如在Test.foo()执行前的连接点,执行点为Test.foo(),方位是方法执行前的位置。Spring使用切点对执行点进行定位,而方位则在增强类型中定义

3.1.4.2.切点(Pointcut)

AOP通过切点定位特定的连接点。
连接点相当于数据库中的记录,而切点相当于查询条件,切点和连接点不是一对一的关系,一个切点可以匹配多个连接点。
Spring通过Pointcut接口描述切点

3.1.4.3.增强(Advice)

增强是织入目标类连接点上的一段代码。

3.1.4.4.目标对象(Target)

增强逻辑的织入目标类

3.1.4.5.引介(Introduction)

引介是一种特殊的增强,它为类添加一些属性和方法。

3.1.4.6.织入(Weaving)

织入是将增强添加到目标类的具体连接点上的过程。
AOP有3种织入方式
1.编译期织入,这要求使用特殊的Java编译器。
2.类装载器织入,这要求使用特殊的类装载器。
3.动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入,而AspectJ采用编译器织入和类装载期织入。

3.1.4.7.代理(Proxy)

一个类被AOP织入增强后,就产生了一个结果类,它是融合了原类和增强逻辑的代理类。
根据不通的代理方式,代理类既可能是和原类具有相同接口的类,也可能是原类的子类,所以可以采用与调用原类相同的方式调用代理类。

3.1.4.8.切面(Aspect)

切面由切点和增强(引介)组成,它既包括横切逻辑的定义,它既包括横切逻辑的定义,也包括连接点的定义。
Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入切面所指定的连接点中。

3.1.5 增强类型

3.1.5.1 前置增强

org.springframework.aop.BeforeAdvice 前置增强,表示在目标方法前实施增强

3.1.5.2 后置增强

org.springframework .aop.AfterReturningAdvice,表示在目标方法指向后实施增强

3.1.5.3 环绕增强

org.aopalliance.intercept.MethodInterceptor,表示在目标方法前后实施增强

3.1.5.4 异常抛出增强

org.springframework.aop. ThrowsAdvice,表示在目标方法抛出异常后实施增强

3.1.5.5 引介增强

org.springframework.aop.IntroductionInterceptor,表示在目标类中添加一些新的方法和属性,引介增强接口IntroductionInterceptor没有定义任何方法,Spring为该类提供了默认实现类DelegatingIntroductionInterceptor,通过扩展该类定义自己的引介增强类。

3.1.6 切面类型

3.1.6.1 静态普通方法名匹配切面

3.1.6.2 静态正则表达式方法匹配切面

3.2 环境搭建及代码演示

3.2.1 引入依赖

maven配置文件在IOC的基础上新增AOP联盟、Spring AOP依赖包、CGLib依赖包。

<?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">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.fxy</groupId>
  <artifactId>spring</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>spring Maven Webapp</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>4.3.14.RELEASE</spring.version>
    <asm.version>4.0</asm.version>
    <cglib.version>3.0</cglib.version>
  </properties>
  <!--统一版本-->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-framework-bom</artifactId>
        <version>${spring.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--Spring IoC Start-->
    <!-- Spring的核心工具包。-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
    </dependency>

    <!--Spring IOC的基础实现,包含访问配置文件、创建和管理bean等。-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
    </dependency>

    <!--Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等. -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
    </dependency>

    <!-- Spring表达式语言. -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
    </dependency>
    <!--Spring IoC End-->

    <!--Spring AOP Start-->
    <!-- Spring的面向切面编程,提供AOP(面向切面编程)实现 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
    </dependency>


    <!-- Spring提供的对AspectJ框架的整合 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
    </dependency>

    <!-- aopalliance包是AOP联盟的API包,里面包含了针对面向切面的接口,使项目支持aop。SpringAOP接口是由AOP联盟定义接口拓展而来的 -->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>

    <!-- cglib依赖(spring依赖) -->

    <dependency>
      <groupId>org.ow2.asm</groupId>
      <artifactId>asm</artifactId>
      <version>${asm.version}</version>
    </dependency>
    <dependency>
      <groupId>org.ow2.asm</groupId>
      <artifactId>asm-util</artifactId>
      <version>${asm.version}</version>
    </dependency>
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>${cglib.version}</version>
      <exclusions>
        <exclusion>
          <artifactId>asm</artifactId>
          <groupId>org.ow2.asm</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <!--Spring AOP End-->
  </dependencies>
</project>

3.2.2 代码演示:监控方法执行时长

3.2.2.1 不使用代理的演示

新建PersonManageService接口及实现类PersonManageServiceImpl模拟人员的新增、变更、删除。代码如下

3.2.2.1.1 PersonManageService.java
package com.fxy.spring.aop;

import com.fxy.spring.ioc.Person;

public interface PersonManageService {
    public void add(Person p);
    public void remove(Person p);
    public void update(Person p);
}
3.2.2.1.2 PersonManageServiceImpl.java 模拟人员的新增、变更、删除
package com.fxy.spring.aop;

import com.fxy.spring.ioc.Person;

public class PersonManageServiceImpl implements PersonManageService{

    public void add(Person p){
        PerformanceMonitor.begin("PersonManage.add");
        System.out.println("模拟人员新增...");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        PerformanceMonitor.end();
    }

    public void remove(Person p){
        PerformanceMonitor.begin("PersonManage.remove");
        System.out.println("模拟人员删除...");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        if ("1".equals(p.getId())){
            throw new RuntimeException("id为1人员不能删除");
        }
       PerformanceMonitor.end();
    }

    @Override
    public void update(Person p) {
        System.out.println("模拟人员变更...");
        try {
            Thread.sleep(150);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
3.2.2.1.3 PerformanceMonitor.java 耗时监控工具类

为每一个线程存储一个耗时监控对象

package com.fxy.spring.aop;

public class PerformanceMonitor {
	private static ThreadLocal<MethodPerformace> performaceRecord = new ThreadLocal<MethodPerformace>();

	public static void begin(String method) {
		System.out.println("监控开始...");
		MethodPerformace mp = performaceRecord.get();
		if(mp == null){
			mp = new MethodPerformace(method);
			performaceRecord.set(mp);
		}else{
		    mp.reset(method);	
		}
	}
	public static void end() {
		System.out.println("监控结束...");
		MethodPerformace mp = performaceRecord.get();
		mp.printPerformace();
	}
}
3.2.2.1.4 MethodPerformace.java 耗时监控对象

存储开始时间,结束时间,方法名。

public class MethodPerformace {
	private long begin;
	private long end;
	private String serviceMethod;
    public MethodPerformace(String serviceMethod){
    	reset(serviceMethod);
    }
    public void printPerformace(){
        end = System.currentTimeMillis();
        long elapse = end - begin;
        System.out.println(serviceMethod+"花费"+elapse+"毫秒。");
    }
    public void reset(String serviceMethod){
    	this.serviceMethod = serviceMethod;
    	this.begin = System.currentTimeMillis();
    }
}
3.2.2.1.5 TestAOP.java 测试代码
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {
    /**
     * 不使用代理,性能监控代码需要嵌入业务代码前后
     */
    @Test
    public void testOri(){
        PersonManageServiceImpl pm = new PersonManageServiceImpl();
        pm.add(new Person());
        pm.remove(new Person());
    }
}
3.2.2.1.6 TestAOP.java 执行结果
监控开始...
模拟人员新增...
监控结束...
PersonManage.add花费101毫秒。
监控开始...
模拟人员删除...
监控结束...
PersonManage.remove花费200毫秒。

可以看到实现监控方法耗时的代码侵入方法内部,下面使用动态代理进行解耦。

3.2.2.1.7 PersonManageServiceImpl.java 删除监控代码
package com.fxy.spring.aop;

import com.fxy.spring.ioc.Person;

public class PersonManageServiceImpl implements PersonManageService{

    public void add(Person p){
        System.out.println("模拟人员新增...");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public void remove(Person p){
        System.out.println("模拟人员删除...");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        if ("1".equals(p.getId())){
            throw new RuntimeException("id为1人员不能删除");
        }
    }

    @Override
    public void update(Person p) {
        System.out.println("模拟人员变更...");
        try {
            Thread.sleep(150);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

3.2.2.2 JDK动态代理演示

3.2.2.2.1 PerformanceHandler.java
package com.fxy.spring.aop.jdk;

import com.fxy.spring.aop.PerformanceMonitor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PerformanceHandler implements InvocationHandler {
    private Object target;//target为目标业务类

    public PerformanceHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName());
        Object obj = method.invoke(target, args);//通过反射调用目标业务类的目标方法
        PerformanceMonitor.end();
        return obj;
    }
}
3.2.2.2.2 TestAOP.java 测试代码
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {
    /**
     * 测试jdk动态代理
     */
    @Test
    public  void TestJdkProxy() {
        PersonManageService target = new PersonManageServiceImpl();
        PerformanceHandler handler = new PerformanceHandler(target);
        PersonManageService proxy = (PersonManageService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
        Person person = new Person();
        proxy.add(person);
        proxy.remove(person);
    }
}

执行结果

监控开始...
模拟人员新增...
监控结束...
com.fxy.spring.aop.PersonManageServiceImpl.add花费100毫秒。
监控开始...
模拟人员删除...
监控结束...
com.fxy.spring.aop.PersonManageServiceImpl.remove花费200毫秒。

无侵入的将耗时监控代码织入了业务方法前后,实现耗时监控的功能。

3.2.2.3 Cglib动态代理演示

3.2.2.3.1 CglibProxy .java
package com.fxy.spring.aop.cglib;

import com.fxy.spring.aop.PerformanceMonitor;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz){
        enhancer.setSuperclass(clazz);// 设置需要创建子类的类
        enhancer.setCallback(this);
        return enhancer.create();// 创建子类实例
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        PerformanceMonitor.begin(o.getClass().getName()+"."+method.getName());
        Object result = methodProxy.invokeSuper(o, objects);//通过代理类调用父类中的方法
        PerformanceMonitor.end();
        return result;
    }
}
3.2.2.3.2 TestAOP.java
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {
/**
     * 测试cglib动态代理
     */
    @Test
    public  void TestCglibProxy() {
        CglibProxy proxy = new CglibProxy();
        PersonManageServiceImpl personManageService = (PersonManageServiceImpl)proxy.getProxy(PersonManageServiceImpl.class);
        Person person = new Person();
        personManageService.add(person);
        personManageService.remove(person);
    }
}

执行结果:

监控开始...
模拟人员新增...
监控结束...
com.fxy.spring.aop.PersonManageServiceImpl$$EnhancerByCGLIB$$ef3e9fc6.add花费116毫秒。
监控开始...
模拟人员删除...
监控结束...
com.fxy.spring.aop.PersonManageServiceImpl$$EnhancerByCGLIB$$ef3e9fc6.remove花费200毫秒。

同样无侵入的将耗时监控代码织入了业务方法前后,实现耗时监控的功能。

3.2.2.4 Sping 增强演示

3.2.2.4.1 MonitorBeforeAdvicce.java 前置增强
package com.fxy.spring.aop.spring.advice;

import com.fxy.spring.aop.PerformanceMonitor;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class MonitorBeforeAdvicce implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        PerformanceMonitor.begin(o.getClass().getName()+"."+method.getName());
    }
}
3.2.2.4.2 MonitorAfterAdvicce.java 后置增强
package com.fxy.spring.aop.spring.advice;

import com.fxy.spring.aop.PerformanceMonitor;
import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class MonitorAfterAdvicce implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        PerformanceMonitor.end();
    }
}
3.2.2.4.3 MonitorInterceptorAdvice.java 环绕增强
package com.fxy.spring.aop.spring.advice;



import com.fxy.spring.aop.PerformanceMonitor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;

public class MonitorInterceptorAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        Object[] arguments = methodInvocation.getArguments();//获取入参
        Object argument = arguments[0];
//        System.out.println("入参:"+argument.toString());
        System.out.println("环绕增强.....");
        Object o = methodInvocation.getThis();
        Method method = methodInvocation.getMethod();
        PerformanceMonitor.begin(o.getClass().getName()+"."+method.getName());
        Object proceed = methodInvocation.proceed();//通过反射调用目标方法
        PerformanceMonitor.end();
        return proceed;
    }
}
3.2.2.4.4 MonitorThrowsAdvice .java 异常抛出增强
package com.fxy.spring.aop.spring.advice;

import org.springframework.aop.ThrowsAdvice;

public class MonitorThrowsAdvice implements ThrowsAdvice{
    public void afterThrowing(Exception ex){
        System.out.println("捕获异常=="+ex.getMessage());
    }
}
3.2.2.4.5 编码方式使用增强
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {
    /**
     * 编码方式测试spring提供的aop
     */
    @Test
    public void tesSpringAOPAdvice1(){
        PersonManageService target = new PersonManageServiceImpl();
        MonitorBeforeAdvicce beforeAdvicce = new MonitorBeforeAdvicce();
        MonitorAfterAdvicce afterAdvicce = new MonitorAfterAdvicce();
        ProxyFactory pf = new ProxyFactory();
        pf.setOptimize(true);// 使用cglibproxy
//        pf.setInterfaces(target.getClass().getInterfaces());// 使用jdk proxy
        pf.setTarget(target);
        pf.addAdvice(beforeAdvicce);
        pf.addAdvice(afterAdvicce);
        PersonManageService proxy = (PersonManageService) pf.getProxy();
        Person person = new Person();
        proxy.add(person);
        proxy.remove(person);
    }
}
3.2.2.4.5 xml配置方式使用增强
3.2.2.4.5.1 新增配置文件 aop.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!--前置、后置增强-->
    <bean id="monitorAfterAdvicce" class="com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce" />
    <bean id="monitorBeforeAdvicce" class="com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce" />

    <bean id="target" class="com.fxy.spring.aop.PersonManageServiceImpl"/>

    <bean id="personManageService" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorAfterAdvicce,monitorBeforeAdvicce"
          p:target-ref="target">

    </bean>
    <!--p:optimize="true" 强制使用cglib动态代理-->
    <!--p:proxyTargetClass="true" 是否对类进行代理,为true将使用cglib动态代理-->

    <!--环绕增强,异常增强-->
    <bean id="monitorInterceptor" class="com.fxy.spring.aop.spring.advice.MonitorInterceptorAdvice"/>
    <bean id="monitorThrowsAdvice" class="com.fxy.spring.aop.spring.advice.MonitorThrowsAdvice"/>
    <bean id="personManageServiceInterceptor" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorInterceptor,monitorThrowsAdvice"
          p:target-ref="target">
    </bean>
</beans>
3.2.2.4.5.2 测试示例
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {

    /**
     * 通过配置文件测试springaop中的前置增强、后置增强
     */
    @Test
    public void tesSpringAOPAdvice2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/aop.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageService");
        Person person = new Person();
        bean.add(person);
        bean.remove(person);
    }
    /**
     * 通过配置文件测试AOP联盟定义的环绕增强
     */
    @Test
    public void tesSpringAOPAdvice3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/aop.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageServiceInterceptor");
        Person person = new Person();
        bean.add(person);
        bean.remove(person);
    }

    /**
     * 通过配置文件测试异常抛出增强
     */
    @Test
    public void tesSpringAOPAdvice4(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/aop.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageServiceInterceptor");
        Person person = new Person();
        person.setId("1");
        bean.remove(person);
    }
}

3.2.2.5 Sping 切面演示

3.2.2.5.1 静态普通方法名匹配切面
3.2.2.5.1.1 MonitorStaticAdvisor.java 静态普通方法名匹配切面
package com.fxy.spring.aop.spring.advisor;

import com.fxy.spring.aop.PersonManageServiceImpl;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

import java.lang.reflect.Method;

public class MonitorStaticAdvisor extends StaticMethodMatcherPointcutAdvisor {
    /**
     * 切点方法匹配规则
     * @param method
     * @param aClass
     * @return
     */
    @Override
    public boolean matches(Method method, Class<?> aClass) {
        return "add".equals(method.getName());
    }

    /**
     * 切点类匹配规则
     * @return
     */
    @Override
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            @Override
            public boolean matches(Class<?> aClass) {
                return PersonManageServiceImpl.class.isAssignableFrom(aClass);//判断是否为某个类的父类
            }
        };
    }
}
3.2.2.5.1.2 aop.xml中添加MonitorStaticAdvisor.java的配置
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!--前置、后置增强-->
    <bean id="monitorAfterAdvicce" class="com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce" />
    <bean id="monitorBeforeAdvicce" class="com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce" />

    <bean id="target" class="com.fxy.spring.aop.PersonManageServiceImpl"/>

    <bean id="personManageService" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorAfterAdvicce,monitorBeforeAdvicce"
          p:target-ref="target">

    </bean>
    <!--p:optimize="true" 强制使用cglib动态代理-->
    <!--p:proxyTargetClass="true" 是否对类进行代理,为true将使用cglib动态代理-->

    <!--环绕增强,异常增强-->
    <bean id="monitorInterceptor" class="com.fxy.spring.aop.spring.advice.MonitorInterceptorAdvice"/>
    <bean id="monitorThrowsAdvice" class="com.fxy.spring.aop.spring.advice.MonitorThrowsAdvice"/>
    <bean id="personManageServiceInterceptor" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorInterceptor,monitorThrowsAdvice"
          p:target-ref="target">
    </bean>


    <!--静态普通方法名匹配切面-->
    <bean id="monitorStaticAdvisor" class="com.fxy.spring.aop.spring.advisor.MonitorStaticAdvisor"
          p:advice-ref="monitorInterceptor"/>
    <bean id="personManageServiceStaticAdvisor" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorStaticAdvisor"
          p:target-ref="target">
    </bean>
</beans>
3.2.2.5.1.2 测试示例
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {
    /**
     * 测试静态普通方法名匹配切面
     */
    @Test
    public void tesMonitorStaticAdvisor(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/aop.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageServiceStaticAdvisor");
        Person person = new Person();
        bean.add(person);
        bean.remove(person);
    }
}
3.2.2.5.2 静态正则表达式方法匹配切面
3.2.2.5.2.1 aop.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!--前置、后置增强-->
    <bean id="monitorAfterAdvicce" class="com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce" />
    <bean id="monitorBeforeAdvicce" class="com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce" />

    <bean id="target" class="com.fxy.spring.aop.PersonManageServiceImpl"/>

    <bean id="personManageService" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorAfterAdvicce,monitorBeforeAdvicce"
          p:target-ref="target">

    </bean>
    <!--p:optimize="true" 强制使用cglib动态代理-->
    <!--p:proxyTargetClass="true" 是否对类进行代理,为true将使用cglib动态代理-->

    <!--环绕增强,异常增强-->
    <bean id="monitorInterceptor" class="com.fxy.spring.aop.spring.advice.MonitorInterceptorAdvice"/>
    <bean id="monitorThrowsAdvice" class="com.fxy.spring.aop.spring.advice.MonitorThrowsAdvice"/>
    <bean id="personManageServiceInterceptor" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorInterceptor,monitorThrowsAdvice"
          p:target-ref="target">
    </bean>


    <!--静态普通方法名匹配切面-->
    <bean id="monitorStaticAdvisor" class="com.fxy.spring.aop.spring.advisor.MonitorStaticAdvisor"
          p:advice-ref="monitorInterceptor"/>
    <bean id="personManageServiceStaticAdvisor" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="monitorStaticAdvisor"
          p:target-ref="target">
    </bean>


    <!--静态正则表达式方法匹配切面-->

    <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:advice-ref="monitorInterceptor">
        <property name="patterns">
            <list>
                <value>.*add.*</value>
                <value>.*remove.*</value>
            </list>
        </property>
    </bean>

    <bean id="personManageServiceRegexpAdvisor" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.fxy.spring.aop.PersonManageService"
          p:interceptorNames="regexpAdvisor"
          p:target-ref="target">
    </bean>
</beans>
3.2.2.5.2.2 测试示例
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {
    @Test
    public void tesMonitorRegexpAdvisor(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/aop.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageServiceRegexpAdvisor");
        Person person = new Person();
        bean.add(person);
        bean.remove(person);
        bean.update(person);
    }
}

3.2.2.6 Sping 自动代理

3.2.2.6.1 新建autoAop.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!--目标-->
    <bean id="personManageService" class="com.fxy.spring.aop.PersonManageServiceImpl"/>

    <!--环绕增强,异常增强-->
    <bean id="monitorInterceptor" class="com.fxy.spring.aop.spring.advice.MonitorInterceptorAdvice"/>
    <bean id="monitorThrowsAdvice" class="com.fxy.spring.aop.spring.advice.MonitorThrowsAdvice"/>
    <!--自动代理实现类BeanNameAutoProxyCreator,根据名称进行匹配-->
    <!--<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
          p:beanNames="personManageService"
          p:interceptorNames="monitorInterceptor,monitorThrowsAdvice"
          p:optimize="true"/>-->
    
    <!--自动代理实现类DefaultAdvisorAutoProxyCreator,根据正则表达式进行匹配-->
    <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:advice-ref="monitorInterceptor">
        <property name="patterns">
            <list>
                <value>.*add.*</value>
                <value>.*remove.*</value>
            </list>
        </property>
    </bean>
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>
3.2.2.6.2 测试示例
package aop;

import com.fxy.spring.aop.cglib.CglibProxy;
import com.fxy.spring.aop.jdk.PerformanceHandler;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.advice.MonitorAfterAdvicce;
import com.fxy.spring.aop.spring.advice.MonitorBeforeAdvicce;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.reflect.Proxy;

public class TestAOP {
    @Test
    public void tesMonitorAutoProxy(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/autoAop.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageService");
        Person person = new Person();
        bean.add(person);
        bean.remove(person);
        bean.update(person);
    }
}

3.2.2.7 AspectJ

3.2.2.7.1 监控注解类 MonitorAnnotation.java
package com.fxy.spring.aop.spring.aspectj;

public @interface MonitorAnnotation {
}
3.2.2.7.2 切面 MonitorAspect.java
package com.fxy.spring.aop.spring.aspectj;

import com.fxy.spring.aop.PerformanceMonitor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MonitorAspect  {
    // 匹配所有标注了注解MonitorAnnotation的 add方法
    @Before("@annotation(com.fxy.spring.aop.spring.aspectj.MonitorAnnotation) && execution(* add(..))")
    public void before(JoinPoint jp){
        Object target = jp.getTarget();
        Signature signature = jp.getSignature();
        String name = signature.getName();
        PerformanceMonitor.begin(target.getClass().getName()+"."+name);
    }
    // 匹配所有标注了注解MonitorAnnotation的 add方法
    @AfterReturning("@annotation(com.fxy.spring.aop.spring.aspectj.MonitorAnnotation) && execution(* add(..))")
    public void after(){
        PerformanceMonitor.end();
    }
}
3.2.2.7.3 PersonManageServiceImpl.java的add方法添加MonitorAnnotation 主键
package com.fxy.spring.aop;

import com.fxy.spring.aop.spring.aspectj.MonitorAnnotation;
import com.fxy.spring.ioc.Person;

public class PersonManageServiceImpl implements PersonManageService{
    @MonitorAnnotation
    public void add(Person p){
        System.out.println("模拟人员新增...");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    @MonitorAnnotation
    public void remove(Person p){
        System.out.println("模拟人员删除...");
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        if ("1".equals(p.getId())){
            throw new RuntimeException("id为1人员不能删除");
        }
    }

    @Override
    public void update(Person p) {
        System.out.println("模拟人员变更...");
        try {
            Thread.sleep(150);
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

3.2.2.7.4 测试代码 TestAspectJAOP.java
package aop;

import com.fxy.spring.aop.PetManager;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.aspectj.MonitorAspect;
import com.fxy.spring.ioc.Cat;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAspectJAOP {
    @Test
    public void tesMonitorAspectj(){
        PersonManageService target = new PersonManageServiceImpl();
        AspectJProxyFactory factory = new AspectJProxyFactory();
        factory.setTarget(target);
        factory.addAspect(MonitorAspect.class);
        PersonManageService proxy = (PersonManageService)factory.getProxy();

        Person person = new Person();
        proxy.add(person);
        proxy.remove(person);
    }
}
3.2.2.7.5 测试结果:标注了MonitorAnnotation注解且方法名为add才被织入监控代码

···
监控开始…
模拟人员新增…
监控结束…
com.fxy.spring.aop.PersonManageServiceImpl.add花费120毫秒。
模拟人员删除…
···

3.2.2.7.6 自动创建代理
3.2.2.7.6.1 使用AnnotationAwareAspectJAutoProxyCreator自动创建代理
3.2.2.7.6.1.1 新建aop-aspectj.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 目标Bean -->
    <bean id="personManageService" class="com.fxy.spring.aop.PersonManageServiceImpl"/>
    <!--使用了@AspectJ注解的切面类-->
    <bean class="com.fxy.spring.aop.spring.aspectj.MonitorAspect"/>
    <!--自动代理创建器,自动将@AspectJ注解切面类织入目标Bean中-->
    <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
</beans>
3.2.2.7.6.1.2 测试代码
package aop;

import com.fxy.spring.aop.PetManager;
import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.aspectj.MonitorAspect;
import com.fxy.spring.ioc.Cat;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAspectJAOP {
    @Test
    public void tesMonitorAspectj2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/aop-aspectj.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageService");
        Person person = new Person();
        bean.add(person);
        bean.remove(person);
    }
}

测试结果:

监控开始...
模拟人员新增...
监控结束...
com.fxy.spring.aop.PersonManageServiceImpl.add花费101毫秒。
模拟人员删除...
3.2.2.7.6.2 使用基于Schema的aop命名空间配置自动代理
3.2.2.7.6.2.1 新建aop-aspectj-auto.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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    <!-- 目标Bean -->
    <bean id="personManageService" class="com.fxy.spring.aop.PersonManageServiceImpl"/>
    <!--使用了@AspectJ注解的切面类-->
    <bean class="com.fxy.spring.aop.spring.aspectj.MonitorAspect"/>
    <!--③基 于@AspectJ切面的驱动器 完成切面织入。Spring 在内部依旧采用AnnotationAwareAspectJAutoOProxyCreator进行自动代理的创建工作,但具体的实现细节已经被<aop:aspectj-autoproxy />隐藏起来。
-->
    <aop:aspectj-autoproxy/>
</beans>
3.2.2.7.6.2.2 测试代码
package aop;

import com.fxy.spring.aop.PersonManageService;
import com.fxy.spring.aop.PersonManageServiceImpl;
import com.fxy.spring.aop.spring.aspectj.MonitorAspect;
import com.fxy.spring.ioc.Cat;
import com.fxy.spring.ioc.Person;
import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAspectJAOP {
    @Test
    public void tesMonitorAspectj3(){
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop/aop-aspectj-auto.xml");
        PersonManageService bean = (PersonManageService)context.getBean("personManageService");
        Person person = new Person();
        bean.add(person);
        bean.remove(person);
    }
}

测试结果:

监控开始...
模拟人员新增...
监控结束...
com.fxy.spring.aop.PersonManageServiceImpl.add花费101毫秒。
模拟人员删除...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值