aop源碼

有關於Spring,咱們最經常使用的兩個功能就是IOC和AOP,前幾篇文章從源碼級別介紹了Spring容器如何爲咱們生成bean及bean之間的依賴關係程序員

    下面咱們接着來看AOP的源碼實現。面試

 

    有關於AOP,咱們在面試中也被無數次問到,AOP是什麼?AOP有什麼做用與優點?AOP在項目中是如何用到的?spring

    這些還都是比較簡單的,有些可能會問你AOP的實現是怎樣的?架構

    哪怕沒有看過源碼的同窗也應該知道,AOP是經過動態代理實現的,動態代理又分爲兩個部分:JDK動態代理和CGLIB動態代理maven

    確實,Spring也就是經過這兩種方式來實現AOP相關功能,下面就經過源碼來簡單求證下ide

 

1.AOP功能簡單實現
    1)引入maven依賴(筆者使用SpringBoot開發)
<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> 
    2)建立接口及其實現類
public interface Person {
    void say();
}
public class Student implements Person{
 
    public void say(){
        System.out.println("這是一個苦逼的程序員");
    }
}
    3)建立切面類
@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;
    }
}
    4)建立beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<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"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 
    <aop:aspectj-autoproxy/>
    <bean id="student" class="test.Student"/>
    <bean class="test.AspectJTest"/>
</beans>
    5)測試類
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..
    總結:AOP功能的使用仍是比較簡單的,把相關bean注入到Spring容器中,編寫好相應的Aspect類便可spring-boot

 

2.寫在分析AOP功能源碼以前
    1)在使用ApplicationContext相關實現類加載bean的時候,會針對全部單例且非懶加載的bean,在構造ApplicationContext的時候就會建立好這些bean,而不會等到使用的時候纔去建立。這也就是單例bean默認非懶加載的應用post

    2)讀者須要瞭解BeanPostProcessor的相關使用,全部實現BeanPostProcessor接口的類,在初始化bean的時候都會調用這些類的方法,通常用於在bean初始化前或後對bean作一些修改。而AOP的功能實現正式基於此,在bean初始化後建立針對該bean的proxy,而後返回給用戶該proxy測試

 

    3)結合以上兩點,被代理後的bean,實際在ApplicationContext構造完成以後就已經被建立完成,getBean()的操做直接從singletonObjects中獲取便可優化

 

3.AOP源碼架構分析
    1)尋找 <aop:aspectj-autoproxy/> 註解對應的解析器
        但凡註解都有對應的解析器,以用來解析該註解的行爲。全局搜索以後可發現

org.springframework.aop.config.AopNamespaceHandler類中有對應的解析行爲,代碼以下:
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());
    }
}
    2)瞭解AspectJAutoProxyBeanDefinitionParser對應的行爲
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的功能咱們大膽猜想一下:應該也就是生成對象的代理類的相關功能,這個咱們接下來再看。

    

    問題:

    那麼問題來了,咱們最開始的類AopNamespaceHandler.init()方法是在何時被調用的呢?何時生效的?這個決定了咱們註冊到Spring的AnnotationAwareAspectJAutoProxyCreator的生效時間?讀者可自行思考下。

 

    3)分析AnnotationAwareAspectJAutoProxyCreator主要行爲
        經過查看AnnotationAwareAspectJAutoProxyCreator的類層次結構,可知,其實現了BeanPostProcessor接口,實現類爲AbstractAutoProxyCreator

        類層次結構以下:


   4)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;
        }
 
        // Create proxy if we have advice.
        // 意思就是若是該類有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;
    }
   總結:

    1)經過AspectJAutoProxyBeanDefinitionParser類將AnnotationAwareAspectJAutoProxyCreator註冊到Spring容器中

    2)AnnotationAwareAspectJAutoProxyCreator類的postProcessAfterInitialization()方法將全部有advice的bean從新包裝成proxy

 

 

4.建立proxy過程分析
    經過以前的代碼結構分析,咱們知道,全部的bean在返回給用戶使用以前都須要通過AnnotationAwareAspectJAutoProxyCreator類的postProcessAfterInitialization()方法,而該方法的主要做用也就是將全部擁有advice的bean從新包裝爲proxy,那麼咱們接下來直接分析這個包裝爲proxy的方法便可,看一下bean如何被包裝爲proxy,proxy在被調用方法時,是具體如何執行的

 

    如下是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());
    }
    1)建立何種類型的Proxy?JDKProxy仍是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);
        }
    }
    2)getProxy()方法
    由1)可知,經過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);
    }
    3)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;
        }
        ...
    }
    4)攔截方法真正被執行調用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);
        }
    }
    總結4:依次遍歷攔截器鏈的每一個元素,而後調用其實現,將真正調用工做委託給各個加強器

 

    

    總結:

    縱觀以上過程可知:實際就是爲bean建立一個proxy,JDKproxy或者CGLIBproxy,而後在調用bean的方法時,會經過proxy來調用bean方法

    重點過程可分爲:

    1)經過AspectJAutoProxyBeanDefinitionParser類將AnnotationAwareAspectJAutoProxyCreator註冊到Spring容器中

    2)AnnotationAwareAspectJAutoProxyCreator類的postProcessAfterInitialization()方法將全部有advice的bean從新包裝成proxy

    3)調用bean方法時經過proxy來調用,proxy依次調用加強器的相關方法,來實現方法切入

相關文章
相關標籤/搜索