Spring Aop源码解读

aop 是什么

AOP (Aspect-Oriented Programming,面向切面编程),可以说是 OOP 的补充和完善。OOP 引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP 则显得无能为力。OOP 允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切代码

面向切面编程,核心原理是使用动态代理模式在方法执行前后或出现异常时加入相关逻辑

aop 的使用场景
  • Authentication 权限的处理
  • Cache 缓存的处理
  • Transactions 事务的处理
  • Performance optimization 性能的优化等
aop 相关概念
  • 切入点 Pointcut: 指定一个通知将被引发的一系列连接点的集合。AOP 框架必须允许开发者指定切入点:例如,使用正则表达式。spring 定义了 Pointcut 接口,用来组合MethodMatcher 和 ClassFilter,可以通过名字很清楚的理解,MethodMatcher 是用来检查目标类的方法是否可以被应用此通知,而 ClassFilter 是用来检查 Pointcut 是否应该应用到目标类上
  • 连接点 Joinpoint: 程序执行过程中明确的点,如方法的调用或特定的异常被抛出
  • 通知 Advice: 在特定的连接点,AOP 框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。许多 AOP 框架包括 spring 都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。spring 中定义了四个 advice: BeforeAdvice, AfterAdvice, ThrowAdvice 和 DynamicIntroductionAdvice
  • 方面 Aspect:一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是 J2EE 应用中一个很好的横切关注点例子。方面用 spring 的 Advisor 或拦截器实现
  • 织入 Weaving: 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成
spring aop 的简单实现

引入 maven 依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.3.RELEASE</version>
</parent>	   
<dependency>      
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-aop</artifactId>  
</dependency>

创建接口及其实现类

public interface Person {
	void say();
}

public class Student implements Person{
 
	public void say(){
		System.out.println("这是一个苦逼的程序员");
	}
}

创建切面类

@Aspect
public class AspectJTest {
 
	@Pointcut("execution(* *.say(..))")
	public void test(){}
	
	@Before("test()")
	public void before(){
		System.out.println("before test..");
	}
	
	@After("test()")
	public void after(){
		System.out.println("after test..");
	}
	
	@Around("test()")
	public Object around(ProceedingJoinPoint p){
		System.out.println("before1");
		Object o = null;
		try {
			o = p.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println("after1");
		return o;
	}
}

测试类

public class Test {
 
	public static void main(String[] args) {
 
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
		Person bean2 = (Person)ac.getBean("student");
		bean2.say();
	}
}

测试结果

before1
    before test..
    这是一个苦逼的程序员
    after1
    after test..
spring aop 源码解读

读源码之前

  • 在使用 ApplicationContext 相关实现类加载 bean 的时候,会对所有单例且非懒加载的 bean在构造 ApplicationContext 的时候就会初始化好这些 bean,而不会等到使用的时候才去初始化。这也就是单例 bean 默认非懒加载的应用

  • 结合以上,被代理后的 bean,实际在 ApplicationContext 构造完成之后就已经被创建完成,getBean() 的操作直接从一级缓存 singletonObjects 中获取即可

beanPostProcessorbeanFactoryPostProcessor

  • beanPostProcessor 接口: bean 后置处理器。beanPostProcessor 能在 spring 容器实例化 bean 之后,bean 初始化前或后bean 做一些修改。而 aop 的功能实现正式基于此,在 bean 初始化后创建针对该 beanproxy,然后返回给用户该 proxy

  • beanFactoryPostProcessor 接口:beanFactoryPostProcessor 接口是针对 bean 容器的,它的实现类可以在当前 spring 容器加载 bean 定义后,bean 实例化之前修改 bean 的定义属性,达到影响之后实例化 bean 的效果

spring 中单例 bean 的初始化主要过程

  • createBeanInstance实例化,其实也就是调用对象的构造方法实例化对象
  • populateBean填充属性,这一步主要是多 bean 的依赖属性进行填充
  • initializeBean初始化,执行该 bean 的一些初始化方法

寻找 aop 注解对应的解析器

public class AopNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());// 就是该段代码
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
 
		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	}
}

AspectJAutoProxyBeanDefinitionParser 对应的行为

public class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
 
	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
        // 1.注册proxy creator
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		extendBeanDefinition(element, parserContext);
		return null;
	}
    ...
    
    // registerAspectJAnnotationAutoProxyCreatorIfNecessary()
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
        // 注册行为主要内容
		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		registerComponentIfNecessary(beanDefinition, parserContext);
	}
 
    // registerAspectJAnnotationAutoProxyCreatorIfNecessary()
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
        // 主要就是为了注册AnnotationAwareAspectJAutoProxyCreator类
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
 
    // 注册类相关代码
    private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
        
        // 类似于我们在使用BeanFactory.getBean()时候的操作,生成一个RootBeanDefinition,然后放入map中
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

通过以上的代码分析,可知 AspectJAutoProxyBeanDefinitionParser 主要的功能就是将 AnnotationAwareAspectJAutoProxyCreator 注册到 spring 容器中,把 bean 交给 spring 去托管

分析 AnnotationAwareAspectJAutoProxyCreator 主要行为

通过查看 AnnotationAwareAspectJAutoProxyCreator 的类层次结构,可知,其实现了 beanPostProcessor 接口,实现类为 AbstractAutoProxyCreator

34A8F2F2-8966-44D3-4372-CB3BC41C21C1.png

AbstractAutoProxyCreator 类主要方法

@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}
 
    // 主要看这个方法,在 bean 初始化之后对生产出的 bean 进行包装
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
 
    // wrapIfNecessary
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}
 
        // 意思就是如果该类有 advice 则创建 proxy,
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 1.通过方法名也能简单猜测到,这个方法就是把 bean 包装为 proxy 的主要方法,
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
            
            // 2.返回该 proxy 代替原来的 bean
			return proxy;
		}
 
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	
	// 获取提前访问指定bean的引用,用于解析循环依赖。在目标bean实例完全初始化之前调用
	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}
  • 通过 AspectJAutoProxyBeanDefinitionParser 类将AnnotationAwareAspectJAutoProxyCreator 注册到 spring 容器中
  • AnnotationAwareAspectJAutoProxyCreator 类的 postProcessAfterInitialization() 方法将所有有 advicebean 重新包装成 proxy

创建 proxy 过程分析

通过之前的代码结构分析,我们知道,所有的 bean 在返回给用户使用之前都需要经过 AnnotationAwareAspectJAutoProxyCreator 类的 postProcessAfterInitialization() 方法,而该方法的主要作用也就是将所有拥有 advicebean 重新包装为 proxy,那么我们接下来直接分析这个包装为 proxy 的方法即可,看一下 bean 如何被包装为 proxyproxy 在被调用方法时,是具体如何执行的

以下是 AbstractAutoProxyCreator.wrapIfNecessary(Object bean, String beanName, Object cacheKey) 中的 createProxy() 代码片段分析

protected Object createProxy(
			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
 
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
 
        // 1.创建 proxyFactory,proxy 的生产主要就是在 proxyFactory 做的
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);
 
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
 
        // 2.将当前 bean 适合的 advice,重新封装下,封装为 Advisor 类,然后添加到ProxyFactory 中
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		for (Advisor advisor : advisors) {
			proxyFactory.addAdvisor(advisor);
		}
 
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);
 
		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
 
        // 3.调用 getProxy 获取 bean 对应的 proxy
		return proxyFactory.getProxy(getProxyClassLoader());
	}

创建何种类型的ProxyJDKProxy 还是 CGLIBProxy

// getProxy()方法
	public Object getProxy(ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}
 
    
    // createAopProxy()方法就是决定究竟创建何种类型的proxy
	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
        // 关键方法 createAopProxy()
		return getAopProxyFactory().createAopProxy(this);
	}
 
    // createAopProxy()
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 1.config.isOptimize()是否使用优化的代理策略,目前使用与CGLIB
        // config.isProxyTargetClass() 是否目标类本身被代理而不是目标类的接口
        // hasNoUserSuppliedProxyInterfaces()是否存在代理接口
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
            
            // 2.如果目标类是接口或者是代理类,则直接使用 JDKproxy
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
            
            // 3.其他情况则使用 CGLIBproxy
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

getProxy() 方法

由上面可知,通过 createAopProxy() 方法来确定具体使用何种类型的 Proxy

针对于该示例,我们具体使用的为 JdkDynamicAopProxy,下面来看下JdkDynamicAopProxy.getProxy() 方法

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable// JdkDynamicAopProxy类结构,由此可知,其实现了InvocationHandler,则必定有invoke方法,来被调用,也就是用户调用bean相关方法时,此invoke()被真正调用
    // getProxy()
    public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        
        // JDK proxy 动态代理的标准用法
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

invoke() 方法

以上的代码模式可以很明确的看出来,使用了 JDK 动态代理模式,真正的方法执行在 invoke() 方法里,下面我们来看下该方法,来看下 bean 方法如何被代理执行的

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		Object oldProxy = null;
		boolean setProxyContext = false;
 
		TargetSource targetSource = this.advised.targetSource;
		Class<?> targetClass = null;
		Object target = null;
 
		try {
            // 1.以下的几个判断,主要是为了判断 method 是否为 equals、hashCode 等 Object 的方法
			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;
			}
 
			// May be null. Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}
 
			// 2.获取当前 bean 被拦截方法链表
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 
			// 3.如果为空,则直接调用 target 的 method
			if (chain.isEmpty()) {
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
            // 4.不为空,则逐一调用 chain 中的每一个拦截方法的 proceed
			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();
			}
 
			...
			return retVal;
		}
		...
	}

拦截方法真正被执行调用 invocation.proceed()

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;
			if (dm.methodMatcher.matches(this.method, this.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);
		}
	}

依次遍历拦截器链的每个元素,然后调用其实现,将真正调用工作委托给各个增强器

spring aop 源码小结

纵观以上过程可知:实际就是为 bean 创建一个 proxyJDKproxy 或者CGLIBproxy,然后在调用 bean 的方法时,会通过 proxy 来调用 bean 方法

重点过程可分为:

  1. 通过 AspectJAutoProxyBeanDefinitionParser 类将AnnotationAwareAspectJAutoProxyCreator 注册到 spring 容器中
  2. AnnotationAwareAspectJAutoProxyCreator 类的 postProcessAfterInitialization() 方法将所有有 advicebean 重新包装成 proxy
  3. 调用 bean 方法时通过 proxy 来调用,proxy 依次调用增强器的相关方法,来实现方法切入

参考:Spring源码深度解析(AOP功能源码解析)

收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据