详述SpringAOP实现及执行过程

       AOP(Aspect Oriented Programming 面向切面编程)是一种通过运行期动态代理实现代码复用的机制,是对传统OOP(Object Oriented Programming,面向对象编程 )的补充。目前,Aspectj是Java社区里最完整最流行的AOP框架,在Spring 2.0以上版本中可以通过Aspectj注解或基于XML配置AOP。
       AOP的一个作用就是对一个简单方法的增强,并且这种增强可以重用到其它方法,下面详细讲述增强过程。(具体场景见JDK动态代理)

Aspectj注解实现AOP

1、添加jar类库

详述SpringAOP实现及执行过程_第1张图片

2、配置Spring Bean 配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

	<context:component-scan base-package="com.zzu">context:component-scan>
	<aop:aspectj-autoproxy proxy-target-class="false">aop:aspectj-autoproxy>
beans>

context:component-scan是扫描指定包下的所有注解,aop:aspectj-autoproxy设置Spring自动为有@Aspect注解的对象产生动态代理对象,其中proxy-target-class="false"代表采用JDK动态代理,proxy-target-class="true"代表采用CGLib动态代理。

3、自定义一个@Aspect修饰的切面类

package com.zzu.calculator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect//将该类声明为切面类
public class CalculatorAspect {
     

	@Before("execution(public int com.zzu.calculator.CalculatorService.mul(int, int))")
	public void before(JoinPoint jp) {
     
		Object obj = jp.getTarget();
		Object[] args = jp.getArgs();
		System.out.println(obj.getClass().getName()+":The mul method begins.");
		System.out.println(obj.getClass().getName()+":Parameters of the mul method: ["+args[0]+","+args[1]+"]");
	}
}

Before为一种前置增强,其中的参数为切入点表达式,用于指定执行哪些类中的哪些方法时触发增强方法, Spring AOP支持execution、within、this、target、args、@within、@target、@args和@annotation等AspectJ切入点表达式,其中execution最常使用。
execution语法: execution([修饰符] 返回值类型 [包名.类名/接口名.]方法名([参数])[异常])。
下面是测试代码:

package com.zzu.calculator;

import org.springframework.stereotype.Service;

@Service
public class CalculatorService implements ICalculatorService {
     

	@Override
	public int mul(int a, int b) {
     
		int result = a*b;
		return result;
	}

	@Override
	public int div(int a, int b) {
     
		int result = a/b;
		return result;
	}
}
//test类
package com.zzu.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.zzu.calculator.ICalculatorService;

public class Test {
     

	public static void main(String[] args) {
     
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
		ICalculatorService calculator = applicationContext.getBean(ICalculatorService.class);
		int result = calculator.mul(1, 2);
		System.out.println(result);
		applicationContext.close();
	}
}

执行结果:

com.zzu.calculator.CalculatorService:The mul method begins.
com.zzu.calculator.CalculatorService:Parameters of the mul method: [1,2]
2

成功对简单方法进行了增强,接下来分析执行过程。

执行过程

new ClassPathXmlApplicationContext(“beans.xml”);加载配置文件得到context:component-scan扫描指定包下的所有类,若有@Service,@Component,@Repository,@Controller等这些注解的类,则把这些类注册为bean 。
然后执行aop:aspectj-autoproxy:

  1. Spring在IOC容器中寻找@Aspect类,上面例子中为CalculatorAspect
  2. 找到该切面类中的有增强注解的方法
  3. 判断增强注解类型
  4. 根据注解内参数来匹配IOC容器中的每个类中的每个方法
    例如此例中:execution(public int com.zzu.calculator.CalculatorService.mul(int, int))就是匹配到类全名为com.zzu.calculator.CalculatorService的类中的参数为两个int类型数据的mul方法
  5. 为匹配到的类创建代理对象

注意:

  • 从Spring 3.2开始spring-core-xxx.jar包已集成CGLib和ASM 相关jar包,所以Spring工程不需再额外引入这些jar包,如下图:
    详述SpringAOP实现及执行过程_第2张图片
  • 即使proxy-target-class设置为false,如果目标类没有声明接口,则Spring将自动使用CGLib生成代理对象。

你可能感兴趣的:(框架,AOP)