《精通Spring-4.x》Spring AOP


目录

  1. AOP相关概念
  2. AOP的实现原理
  3. 创建增强类
  4. 创建切面
  5. 通过AspectJ实现切面
  6. 基于schema配置切面

一、AOP的相关概念

  • 连接点 按照我的理解,连接点就是程序中的一个个方法(因为在Spring中仅支持方法的连接点),只能在方法的调用前后,方法抛出异常等地方织入增强。Spring中使用切点对执行点进行定位,方位定义在增强中。
  • 切点:因为程序中存在许多的连接点,则通过切点来定位特定的连接点,在Spring中切点通过org.springframework.aop.Pointcut接口进行描述。
  • 增强:增强是织入目标类连接点上的一段代码,同时增强也包含用于定位连接点的方位信息,所以在Spring中提供的增强接口都是带方位名的,比如BeforeAdvice、AfterReturningAdvice等。
  • 目标对象:增强的织入目标类
  • 引介:引介是一种特殊的增强,他为类添加一些属性和方法。利用引介,可以动态的为业务类添加其他接口的实现逻辑,让业务类成为这个接口的实现类.
  • 织入:织入是将增强添加到目标类的连接点上的过程。
  • 切面:切点和增强即组成切面
    二、AOP的实现原理
    SPring AOP的底层实现原理为动态代理。Java中提供了两种动态代理方式,JDK动态代理和CGLib动态代理。前者是针对接口的代理,而后者则是针对子类创建动态代理。对于这两种代理的学习,可以参考以下博客。
    https://blog.csdn.net/zs520ct/article/details/79593196
    https://blog.csdn.net/cckevincyh/article/details/54962920
    三、创建增强类
    按照增强在目标类方法中连接点的位置,可以分为如下五类
  • 前置增强
  • 后置增强
  • 环绕增强
  • 异常抛出增强
  • 引介增强
    以下实例均为《精通 Spring 4.x》中的源码
    前置增强
    首先定义一个接口
public interface Waiter {
   
   void greetTo(String name);
   void serveTo(String name);
}

之后是一个简单的实现类

public class NaiveWaiter implements Waiter {
   

	public void greetTo(String name) {
   
		System.out.println("greet to "+name+"...");
	}
	
	public void serveTo(String name){
   
		System.out.println("serving "+name+"...");
	}
}

接下来是增强类,用来保证NaiveWaiter类在每次执行动作时,都能进行"问候"!

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {
   
	public void before(Method method, Object[] args, Object obj) throws Throwable {
   
		String clientName = (String)args[0];
		System.out.println("How are you!Mr."+clientName+".");
	}
}

查看测试结果

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import static org.testng.Assert.*;
import org.testng.annotations.*;

public class BeforeAdviceTest {
   

    @Test
	public void before() {
   
        Waiter target = new NaiveWaiter();
        BeforeAdvice  advice = new GreetingBeforeAdvice();
        ProxyFactory pf = new ProxyFactory();
        pf.setInterfaces(target.getClass().getInterfaces());
        pf.setOptimize(true);
        pf.setTarget(target);
        pf.addAdvice(advice);

        Waiter proxy = (Waiter)pf.getProxy(); 
        proxy.greetTo("John");
        proxy.serveTo("Tom");
	}
}

程序的输出结果如下
在这里插入图片描述
如上测试结果,因为只是在目标类target中设置了增强,而没有具体的切点,此时增强是针对目标类中所有方法的。
在如上的测试代码中出现了pf.setOptimize(true); 代码,该方法让ProxyFactory启用代理优化,这样针对接口的代理也会使用CGLib的代理
在Spring中配置

<bean id="greetingBefore" class="com.smart.advice.GreetingBeforeAdvice" />
<bean id="target" class="com.smart.advice.NaiveWaiter" />
<bean id="waiter"
	class="org.springframework.aop.framework.ProxyFactoryBean"
	p:proxyInterfaces="com.smart.advice.Waiter" 
	p:target-ref="target"
	p:interceptorNames="greetingBefore"
/>

ProxyFactory的几个常用的可配置属性
target:代理的目标对象
proxyInterfaces:代理所要实现的接口,可以是多个接口,该属性还有一个别名,interfaces。
interceptorNames:需要织入目标对象的bean列表,采用Bean的名称指定,这些Bean必须实现了 org.aopalliance.interceptor.MethodInteceptor或org.springframework.aop.Advisior的bean
optimize:当设置为true时,强制使用CGLib动态代理。CGLib动态代理在创建时速度慢,但其创建出的代理对象运行效率较高,而JDK动态代理则正相反
proxyTargetClass:是否对类进行代理,当设置为true时,使用CGlib动态代理。
后置增强

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class GreetingAfterAdvice implements AfterReturningAdvice {
   

	public void afterReturning(Object returnObj, Method method, Object[] args,
			Object obj) throws Throwable {
   
		System.out.println("Please enjoy yourself!");
	}
}
<bean id="waiter"
	class="org.springframework.aop.framework.ProxyFactoryBean"
	p:proxyInterfaces="com.smart.advice.Waiter"
	p:target-ref="target"
	p:interceptorNames="greetingBefore,greetingAfter"
/>

执行结果如下
在这里插入图片描述
环绕增强

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class GreetingInterceptor implements MethodInterceptor {
   

	public Object invoke(MethodInvocation invocation) throws Throwable {
   
		Object[] args = invocation.getArguments();
		String clientName = (String)args[0];
		System.out.println("How are you!Mr."+clientName+".");
		
		Object obj = invocation.proceed();
		
		System.out.println("Please enjoy yourself!");
		
		return obj;
	}
}

异常抛出增强
首先定义一个异常抛出类

import java.sql.SQLException;

public class ForumService {
   
	public void removeForum(int forumId) {
   
		// do sth...
		throw new RuntimeException("运行异常。"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值