ITPub博客

首页 > 数据库 > 数据库开发技术 > SpringAOP源码解析

SpringAOP源码解析

原创 数据库开发技术 作者:服务端技术栈 时间:2019-04-21 21:27:12 0 删除 编辑

掌握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使用到的设计模式:

抽象工厂模式

动态代理模式



原文作者:服务端技术栈;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-03-08

  • 博文量
    97
  • 访问量
    41429