首页 > 数据库 > 数据库开发技术 > SpringAOP源码解析
掌握Spring AOP是基于代理的这一事实很重要。
springAop用处:
提供声明性企业服务。最重要的服务是声明性事务管理。
让用户实现自定义方面,用AOP补充他们对OOP的使用。
SpringAOP默认使用JDK动态代理,本篇文章将介绍spring如何基于JDK动态代理实现AOP的。
SpringAop组成部分:
1、aspect: 切面 @AspectJ 事务管理是企业Java应用程序中横切关注点的一个很好的例子。在Spring AOP中,方面是通过使用正则类(基于模式的方法)或使用@Aspect注释的正则类(@AspectJ样式)来实现的。
2、join point 连接点:程序执行过程中的一个点,如方法的执行或异常的处理。在Spring AOP中,连接点总是表示方法执行。
3、Advice 切面在特定连接点上采取的操作。不同类型的建议包括“前后”建议、“前后”建议。(稍后将讨论通知类型。)许多AOP框架(包括Spring)将通知建模为拦截器,并围绕连接点维护一系列拦截器。
包含的通知类型:
Before advice:前置通知
After returning advice 返回后(正常)通知
After throwing advice 抛出异常后通知
After (finally) advice 完全执行后(正常或异常)通知
Around advice:环绕通知
4、Pointcut 匹配连接点的谓词。通知与切入点表达式相关联,并在切入点匹配的任何连接点上运行(例如,执行具有特定名称的方法)。连接点与切入点表达式匹配的概念是AOP的核心,Spring默认使用AspectJ切入点表达式语言。
5、Introduction 说明/引入 可以对目标类进行扩展新的接口方法
6、Target object 目标对象,一个或多个切面进行通知的对象,即代理对象
7、AOP proxy 通过jdk动态代理或者cglib创建的代理对象
8、Weaving 织入
使用SpringAop步骤
1、Enabling @AspectJ Support with Java Configuration / Enabling @AspectJ Support with XML Configuration
2、Declaring an Aspect 定义切面 (切面在java中就是具体的一个方法):
3、Declaring a Pointcut 定义切点 定义方法(方法必须返回void)并提供表达式注解:按照定义方法的规则定义 execution(public * com.fox.aop..*.*(..)))
4 Declaring Advice 定义通知
注意的问题:
如果目标类方法是一个final修饰,cglib不能进行代理
如下是一个拥有执行后通知案例
1、开启切面支持
@Configuration
@EnableAspectJAutoProxy
public class AspectConfig {
}
2、定义切面以及切点
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Aspect //声明为切面
public class LogAopAspect {
//声明切点
@Pointcut(value = "execution(* com.lm.blog.service.*.*(..))")
public void pointcut() {}
//后置通知
@After(value = "pointcut()")
public void after() {
log.info("system init after");
}
}
3、具体目标类
import com.lm.blog.service.SystemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class SystemServiceImpl implements SystemService {
@Override
public void init() {
log.info("system init start");
}
}
4、测试类
import com.lm.blog.service.SystemService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class BlogApplicationTests {
@Autowired
private SystemService systemService;
@Test
public void contextLoads() {
systemService.init();
}
}
5.结果
2019-04-21 18:30:14.495 INFO 17576 --- [main] c.l.blog.service.impl.SystemServiceImpl : system init start
2019-04-21 18:30:14.793 INFO 17576 --- [main] com.lm.blog.aop.LogAopAspect : system init after
上面通过spring提供的几个注解就使用到了springaop的功能,下面剖析下具体怎么springaop生效的。
首先看下spring是如何结合JDK动态代理实现aop的:
1、spring提供了JdkDynamicAopProxy类,用来创建代理对象,并织入各种通知方法的,看到类定义,实现了InvocationHandler
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
2、JdkDynamicAopProxy类提供的获取代理实例方法
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//调用JDK提供的api创建代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
3、实现了InvocationHandler的invoke方法
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//equals和hashCode方法不走拦截器链
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
//获取到初始化好的方法拦截器链,一个集合
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 递归的调用方法拦截器方法,即真正应用各种通知
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
4、retVal = invocation.proceed(); 是ReflectiveMethodInvocation 类的方法
首先看定义
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
@Override
@Nullable
public Object proceed() throws Throwable {
//We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//获取下一个可执行的方法拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
// 调用拦截器方法
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 递归调用
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 根据通知类型执行各种通知操作
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
5.((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 执行不同类型的通知操作
比如AspectJAfterAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
// 目标方法执行后,进行后置通知操作
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
看下几种通知实现类以及对于的拦截器实现类


springAop使用到的设计模式:
抽象工厂模式
动态代理模式
原文作者:服务端技术栈;如有侵权,请联系管理员删除。