Spring之AOP原理、代码、使用详解(XML配置方式)

  Spring 的两大核心,一是IOC,另一个是AOP,本博客从原理、AOP代码以及AOP使用三个方向来讲AOP。先给出一张AOP相关的结构图,可以放大查看。

一、Spring AOP 接口设计

  1、PointCut (连接点,定义匹配哪些方法)

  首先打开 Spring 的源码,查看 PointCut 接口设计:

public interface Pointcut {
    ClassFilter getClassFilter();
    MethodMatcher getMethodMatcher();
    Pointcut TRUE = TruePointcut.INSTANCE;
}

  该接口定义了2 个方法,一个成员变量。我们先看第一个方法:ClassFilter getClassFilter() ,该方法返回一个类过滤器,由于一个类可能会被多个代理类代理,于是Spring引入了责任链模式,另一个方法则是 MethodMatcher getMethodMatcher() ,表示返回一个方法匹配器,我们知道,AOP 的作用是代理方法,那么,Spirng 怎么知道代理哪些方法呢?必须通过某种方式来匹配方法的名称来决定是否对该方法进行增强,这就是 MethodMatcher 的作用。还有要给默认的 Pointcut 实例,该实例对于任何方法的匹配结果都是返回 true。

  我们关注一下 MethodMatcher 接口:

public interface MethodMatcher {
    boolean matches(Method method, @Nullable Class<?> targetClass);
    boolean isRuntime();
    boolean matches(Method method, @Nullable Class<?> targetClass, Object... args);
    MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}

  该接口定义了静态方法匹配器和动态方法匹配器。所谓静态方法匹配器,它仅对方法名签名(包括方法名和入参类型及顺序)进行匹配;而动态方法匹配器,会在运行期检查方法入参的值。静态匹配仅会判别一次,而动态匹配因为每次调用方法的入参都可能不一样,所以每次都必须判断。一般情况下,动态匹配不常用。方法匹配器的类型由isRuntime()返回值决定,返回false表示是静态方法匹配器,返回true表示是动态方法匹配器。

  总的来说, PointCut 和 MethodMatcher 是依赖关系,定义了AOP应该匹配什么方法以及如何匹配。

  2、Advice (通知,定义在链接点做什么)

  注意,Advice 接口只是一个标识,什么也没有定义,但是我们常用的几个接口,比如 BeforeAdvice,AfterAdvice,都是继承自它。我们关注一下 AfterAdvice 的子接口 AfterReturningAdvice :

public interface AfterReturningAdvice extends AfterAdvice {
    void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
  该接口定义了一个方法,afterReturning,参数分别是返回值,目标方法,参数,目标方法类,在目标方法执行之后会回调该方法。那么我们就可以在该方法中执行我们的切面逻辑,BeforeAdvice 也是一样的道理。

  3、Advisor (通知器,将 Advice 和 PointCut 结合起来)

  有了对目标方法的增强接口 Advice 和 如何匹配目标方法接口 PointCut 接口后,那么我们就需要用一个对象将他们结合起来,发挥AOP 的作用,所以Spring 设计了 Advisor(通知器),经过我们刚刚的描述,我们应该知道了,这个 Advisor 肯定依赖了 Advice 和 PointCut,我们看看接口设计:

public interface Advisor {
    Advice EMPTY_ADVICE = new Advice() {};
    Advice getAdvice();
    boolean isPerInstance();
}

  及其子接口:

public interface PointcutAdvisor extends Advisor {
    Pointcut getPointcut();
}

  以上三个接口关系如图所示:

        

 二、手写AOP示例

  我们直接定义以上三个接口的实现类,实现AOP(此方式是为了理解AOP原理的AOP写作方式,非日常用的AOP的XML实现方式)。

  1、Pointcut 接口实现

package test;

import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;

public class TestPointcut implements Pointcut {

    @Override
    public ClassFilter getClassFilter() {
        return ClassFilter.TRUE;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return new MethodMatcher() {

            public boolean matches(Method method, Class<?> targetClass, Object[] args) {
                if (method.getName().equals("test")) {
                    return true;
                }
                return false;
            }

            public boolean matches(Method method, Class<?> targetClass) {
                if (method.getName().equals("test")) {
                    return true;
                }
                return false;
            }

            public boolean isRuntime() {
                return true;
            }
        };
    }
}

  只要方法名称是test则对该方法进行增强或者说拦截。

  2、AfterAdvice 实现

package test;

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

public class TestAfterAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
        System.out.println(
                "after " + target.getClass().getSimpleName() + "." + method.getName() + "()");
    }
}

  3、Advisor 通知器的实现

package test;

import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;

// 通知器
public class TestAdvisor implements PointcutAdvisor {
    // 获取通知处理逻辑
    @Override
    public Advice getAdvice() {
        return new TestAfterAdvice();
    }
    @Override
    public boolean isPerInstance() {
        return false;
    }
    // 获取切入点
    @Override
    public Pointcut getPointcut() {
        return new TestPointcut();
    }
}

  我们实现了 PointcutAdvisor 接口,返回我们刚才定义的两个类。完成了他们的组合。

  4、定义目标类 Targe

package test;

public class TestTarget {

    public void test() {
        System.out.println("target.test()");
    }

    public void test2() {
        System.out.println("target.test2()");
    }
}

  该目标的实现是2个方法,分别打印自己的方法名。

  5、定义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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="testAdvisor" class="test.TestAdvisor"></bean>
    <bean id="testTarget" class="test.TestTarget"></bean>
    <bean id="testAOP" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="targetName">
            <value>testTarget</value>
        </property>
        <property name="interceptorNames">
            <list>
                <value>testAdvisor</value>
            </list>
        </property>
    </bean>
</beans>
  我们定义了3个bean,上面两个testAdvisor、testTarget是我们刚刚定义的,下面一个ProxyFactoryBean 是什么呢?首先他是一个 FactoryBean,我们在学习 IOC 的时候知道, FactoryBean 是Spring 留给我们扩展用的,实现该接口的类可以自定类的各种功能。ProxyFactoryBean 当然也实现了自己的很多自定义功能。ProxyFactoryBean 也是Spring IOC 环境中创建AOP 应用的底层方法,Spring 正是通过它来实现对AOP的封装。这样我们更加接近Spring的底层设计。而该类需要注入两个属性一个目标类,一个拦截类,ProxyFactoryBean 会生成一个动态代理类来完成对目标方法的拦截。

  6、定义测试类

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TestAOP {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext(
                "spring-context/src/test/java/test/beans.xml");
        TestTarget target = (TestTarget) applicationContext.getBean("testAOP");
        target.test();
        System.out.println("----------------");
        target.test2();
    }
}

  查看输出结果:

target.test()
after TestTarget.test()
----------------
target.test2()

  可以看到因为我们只配置了在test名称的方法之后打印该方法的名称和该目标类的名称,而test2 则没有配置,因此也就没有打印。

三、深入 AOP 源码实现

  我本地配置对service配置了AOP,代码如下:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = 
                new ClassPathXmlApplicationContext("classpath:aop/args/applicationContext.xml");
        TestService service = context.getBean("service", TestService.class);
        System.out.println(service.getClass().getName());
        service.test("test execution");
    }
}

  在调用时,可以通过debug看到service返回的是一个JDK生成的代理对象:JdkDynamicAopProxy,而不是我们自己定义的一个TestServiceImpl的实例,也就是说, FactoryBean 确实能够在IOC容器中做一些定制化。

      

  配置了AOP的实例类在IOC阶段就已经注册了一个带有AOP功能的代理类,那么这个代理对象是如何生成的呢?

  首先进入抽象类 AbstractApplicationContext 的getBean 方法,从容器或获取 Bean,再调用 doGetBean 方法,看看该方法实现:

//获取IoC容器中指定名称的Bean  
public Object getBean(String name) throws BeansException {  
   //doGetBean才是真正向IoC容器获取被管理Bean的过程  
   return doGetBean(name, null, null, false);  
}  
//获取IoC容器中指定名称和类型的Bean  
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {  
   //doGetBean才是真正向IoC容器获取被管理Bean的过程  
   return doGetBean(name, requiredType, null, false);  
}  
//获取IoC容器中指定名称和参数的Bean  
public Object getBean(String name, Object... args) throws BeansException {  
   //doGetBean才是真正向IoC容器获取被管理Bean的过程  
   return doGetBean(name, null, args, false);  
}  
//获取IoC容器中指定名称、类型和参数的Bean  
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {  
//doGetBean才是真正向IoC容器获取被管理Bean的过程  
   return doGetBean(name, requiredType, args, false);  
}  
//真正实现向IoC容器获取Bean的功能,也是触发依赖注入功能的地方  
@SuppressWarnings("unchecked")  
protected <T> T doGetBean(  
       final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)  
       throws BeansException {  
   //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖,如果指定的是别名,将别名转换为规范的Bean名称  
   final String beanName = transformedBeanName(name);  
   Object bean;  
   //先从缓存中取是否已经有被创建过的单态类型的Bean,对于单态模式的Bean整个IoC容器中只创建一次,不需要重复创建  
   Object sharedInstance = getSingleton(beanName);  
   //IOC容器创建单态模式Bean实例对象  
   if (sharedInstance != null && args == null) {  
       if (logger.isDebugEnabled()) {  
           //如果指定名称的Bean在容器中已有单态模式的Bean被创建,直接返回已经创建的Bean  
           if (isSingletonCurrentlyInCreation(beanName)) {  
               logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +  
                       "' that is not fully initialized yet - a consequence of a circular reference");  
           }  
           else {  
               logger.debug("Returning cached instance of singleton bean '" + beanName + "'");  
           }  
       }  
       //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理  
       //注意:BeanFactory是管理容器中Bean的工厂,而FactoryBean是创建创建对象的工厂Bean,两者之间有区别  
       bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  
   }  
   else {
    //缓存没有正在创建的单态模式Bean  
       //缓存中已经有已经创建的原型模式Bean,但是由于循环引用的问题导致实例化对象失败  
       if (isPrototypeCurrentlyInCreation(beanName)) {  
           throw new BeanCurrentlyInCreationException(beanName);  
       }  
       //对IoC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否能在当前的BeanFactory中获取的所需要的Bean
    //如果不能则委托当前容器的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找  
       BeanFactory parentBeanFactory = getParentBeanFactory();  
       //当前容器的父级容器存在,且当前容器中不存在指定名称的Bean  
       if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {  
           //解析指定Bean名称的原始名称  
           String nameToLookup = originalBeanName(name);  
           if (args != null) {  
               //委派父级容器根据指定名称和显式的参数查找  
               return (T) parentBeanFactory.getBean(nameToLookup, args);  
           }  
           else {  
               //委派父级容器根据指定名称和类型查找  
               return parentBeanFactory.getBean(nameToLookup, requiredType);  
           }  
       }  
       //创建的Bean是否需要进行类型验证,一般不需要  
       if (!typeCheckOnly) {  
           //向容器标记指定的Bean已经被创建  
           markBeanAsCreated(beanName);  
       }  
        //根据指定Bean名称获取其父级的Bean定义,主要解决Bean继承时子类合并父类公共属性问题  
       final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
       checkMergedBeanDefinition(mbd, beanName, args);  
       //获取当前Bean所有依赖Bean的名称  
       String[] dependsOn = mbd.getDependsOn();  
       //如果当前Bean有依赖Bean  
       if (dependsOn != null) {  
           for (String dependsOnBean : dependsOn) {  
               //递归调用getBean方法,获取当前Bean的依赖Bean  
               getBean(dependsOnBean);  
               //把被依赖Bean注册给当前依赖的Bean  
               registerDependentBean(dependsOnBean, beanName);  
           }  
       }  
       //创建单态模式Bean的实例对象  
       if (mbd.isSingleton()) {  
       //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象  
           sharedInstance = getSingleton(beanName, new ObjectFactory() {  
               public Object getObject() throws BeansException {  
                   try {  
                       //创建一个指定Bean实例对象,如果有父级继承,则合并子//类和父类的定义  
                       return createBean(beanName, mbd, args);  
                   }  
                   catch (BeansException ex) {  
                       //显式地从容器单态模式Bean缓存中清除实例对象  
                       destroySingleton(beanName);  
                       throw ex;  
                   }  
               }  
           });  
           //获取给定Bean的实例对象  
           bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
       }  
       //IoC容器创建原型模式Bean实例对象  
       else if (mbd.isPrototype()) {  
           //原型模式(Prototype)是每次都会创建一个新的对象  
           Object prototypeInstance = null;  
           try {  
               //回调beforePrototypeCreation方法,默认的功能是注册当前创//建的原型对象  
               beforePrototypeCreation(beanName);  
               //创建指定Bean对象实例  
               prototypeInstance = createBean(beanName, mbd, args);  
           }  
           finally {  
               //回调afterPrototypeCreation方法,默认的功能告诉IoC容器指//定Bean的原型对象不再创建了  
               afterPrototypeCreation(beanName);  
           }  
           //获取给定Bean的实例对象  
           bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);  
       }  
       //要创建的Bean既不是单态模式,也不是原型模式,则根据Bean定义资源中配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中比较常用
       //如:request、session、application等生命周期  
       else {  
           String scopeName = mbd.getScope();  
           final Scope scope = this.scopes.get(scopeName);  
           //Bean定义资源中没有配置生命周期范围,则Bean定义不合法  
           if (scope == null) {  
               throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");  
           }  
           try {  
               //这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例  
               Object scopedInstance = scope.get(beanName, new ObjectFactory() {  
                   public Object getObject() throws BeansException {  
                       beforePrototypeCreation(beanName);  
                       try {  
                           return createBean(beanName, mbd, args);  
                       }  
                       finally {  
                           afterPrototypeCreation(beanName);  
                       }  
                   }  
               });  
               //获取给定Bean的实例对象  
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);  
           }  
           catch (IllegalStateException ex) {  
               throw new BeanCreationException(beanName,  
                       "Scope '" + scopeName + "' is not active for the current thread; " +  
                       "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",  
                       ex);  
           }  
       }  
   }  
   //对创建的Bean实例对象进行类型检查  
   if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {  
       throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());  
   }  
   return (T) bean;  
}
  该方法会进入到第一个if块中的 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null) 方法中,而 getObjectForBeanInstance 方法则会先判断缓存是否存在,如果不存在,则进入父类的 getObjectForBeanInstance 方法,我们看看该方法实现:
//获取给定Bean的实例对象,主要是完成FactoryBean的相关处理 
protected Object getObjectForBeanInstance(  
       Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {  
   //容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,也可能是一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象
   //如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象  
   //如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),且Bean实例也不是创建Bean实例对象的工厂Bean  
   if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {  
       throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());  
   }  
   //如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,调用者向获取对容器的引用,则直接返回当前的Bean实例  
   if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {  
       return beanInstance;  
   }  
   //处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean,使用工厂Bean创建一个Bean的实例对象  
   Object object = null;  
   if (mbd == null) {  
       //从Bean工厂缓存中获取给定名称的Bean实例对象  
       object = getCachedObjectForFactoryBean(beanName);  
   }  
   //让Bean工厂生产给定名称的Bean对象实例  
   if (object == null) {  
       FactoryBean factory = (FactoryBean) beanInstance;  
       //如果从Bean工厂生产的Bean是单态模式的,则缓存  
       if (mbd == null && containsBeanDefinition(beanName)) {  
           //从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性  
           mbd = getMergedLocalBeanDefinition(beanName);  
       }  
       //如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,则让工厂Bean生产Bean实例对象  
       boolean synthetic = (mbd != null && mbd.isSynthetic());  
       //调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,实现工厂Bean生产Bean对象实例的过程  
       object = getObjectFromFactoryBean(factory, beanName, !synthetic);  
   }  
   return object;  
}
  首先判断是否是 Bean 引用类型并且是否是 Factory 类型,很明显不是Bean 引用类型(Bean引用类型指的是IOC在解析XML文件 的时候,会有 ref 属性,而这个ref 对象还没有实例化,则暂时创建一个Bean引用类型的实例,用于在依赖注入的时候判断是否是Bean的属性类型,如果是,则从容器中取出,如果不是,则是基本类型,就直接赋值),然后进入下面的if判断,很明显会直接跳过。进入下面的 getCachedObjectForFactoryBean(beanName) 方法,从缓存中取出,很明显,第一次肯定返回null,继续向下,进入if块,重点在 object = getObjectFromFactoryBean(factory, beanName, !synthetic) 方法,我们进入该方法查看:
//Bean工厂生产Bean实例对象  
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {  
   //Bean工厂是单态模式,并且Bean工厂缓存中存在指定名称的Bean实例对象  
   if (factory.isSingleton() && containsSingleton(beanName)) {  
       //多线程同步,以防止数据不一致  
       synchronized (getSingletonMutex()) {  
           //直接从Bean工厂缓存中获取指定名称的Bean实例对象  
           Object object = this.factoryBeanObjectCache.get(beanName);  
           //Bean工厂缓存中没有指定名称的实例对象,则生产该实例对象  
           if (object == null) {  
               //调用Bean工厂的getObject方法生产指定Bean的实例对象  
               object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);  
               //将生产的实例对象添加到Bean工厂缓存中  
               this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));  
           }  
           return (object != NULL_OBJECT ? object : null);  
       }  
   }  
   //调用Bean工厂的getObject方法生产指定Bean的实例对象  
   else {  
       return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);  
   }  
}  

  该方法还是先重缓存中取出,然后进入 doGetObjectFromFactoryBean(factory, beanName) 方法,我们看看该方法:

//调用Bean工厂的getObject方法生产指定Bean的实例对象  
private Object doGetObjectFromFactoryBean(  
       final FactoryBean factory, final String beanName, final boolean shouldPostProcess)  
       throws BeanCreationException {  
   Object object;  
   try {  
       if (System.getSecurityManager() != null) {  
           AccessControlContext acc = getAccessControlContext();  
           try {  
               //实现PrivilegedExceptionAction接口的匿名内置类,根据JVM检查权限,然后决定BeanFactory创建实例对象  
               object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {  
                   public Object run() throws Exception {  
                           //调用BeanFactory接口实现类的创建对象方法  
                           return factory.getObject();  
                       }  
                   }, acc);  
           }  
           catch (PrivilegedActionException pae) {  
               throw pae.getException();  
           }  
       }  
       else {  
           //调用BeanFactory接口实现类的创建对象方法  
           object = factory.getObject();  
       }  
   }  
   catch (FactoryBeanNotInitializedException ex) {  
       throw new BeanCurrentlyInCreationException(beanName, ex.toString());  
   }  
   catch (Throwable ex) {  
       throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);  
   }  
   //创建出来的实例对象为null,或者因为单态对象正在创建而返回null  
   if (object == null && isSingletonCurrentlyInCreation(beanName)) {  
       throw new BeanCurrentlyInCreationException(  
               beanName, "FactoryBean which is currently in creation returned null from getObject");  
   }  
   //为创建出来的Bean实例对象添加BeanPostProcessor后置处理器  
   if (object != null && shouldPostProcess) {  
       try {  
           object = postProcessObjectFromFactoryBean(object, beanName);  
       }  
       catch (Throwable ex) {  
           throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);  
       }  
   }  
   return object;  
}
  该方法会直接进入 object = factory.getObject() 行,也就是 ProxyFactoryBean 的 getObject 方法,Spring 允许我们从写 getObject 方法来实现特定逻辑,继续看看该方法实现:
public Object getObject() throws BeansException {
    initializeAdvisorChain();// 为代理对象配置Advisor链
    if (isSingleton()) {// 单例
        return getSingletonInstance();
    }
    else {
        if (this.targetName == null) {
            logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                    "Enable prototype proxies by setting the 'targetName' property.");
        }// 非单例
        return newPrototypeInstance();
    }
}
  该方法很重要,首先初始化通知器链,然后获取单例,这里返回的就是我们最初看到的JDK动态代理。这里的初始化过滤器链的重要作用就是将通知连接起来,基本实现就是循环我们在配置文件中配置的通知器,按照链表的方式连接起来。然后判断是否是单例,然后我们着重关注下面的方法 getSingletonInstance();
private synchronized Object getSingletonInstance() {
    if (this.singletonInstance == null) {
        this.targetSource = freshTargetSource();
        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
            // Rely on AOP infrastructure to tell us what interfaces to proxy.
            Class<?> targetClass = getTargetClass();
            if (targetClass == null) {
                throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
            }
            setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
        }
        // Initialize the shared singleton instance.
        super.setFrozen(this.freezeProxy);
        this.singletonInstance = getProxy(createAopProxy());
    }
    return this.singletonInstance;
}
  该方法是同步方法,防止并发错误,因为有共享变量。首先返回一个包装过的目标对象,然后是否含有接口,我们的目标类实现了接口,因此截图也有展示interfaces,进入if块,从目标类中取出所有接口并设置接口。接下来重要的一行是 getProxy(createAopProxy()),先创建AOP,再获取代理。我们先看 crateAopProxy。
protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

  该方法返回一个AopProxy 类型的实例,我们看看该接口:

public interface AopProxy {
    Object getProxy();
    Object getProxy(@Nullable ClassLoader classLoader);
}

  该接口定义了两个重载方法,我们看看它有哪些实现:

        

  这是该接口的继承图,分别是 JdkDynamicAopProxy 动态代理和 CglibAopProxy 代理。而 JdkDynamicAopProxy 实现了 InvocationHandler 接口,如果熟悉Java 动态代理,应该熟悉该接口,实现了该接口的类并实现invoke方法,再代理类调用的时候,会回调该方法。实现动态代理。

  我们继续看 createAopProxy 方法,该方法主要逻辑是创建一个AOP 工厂,默认工厂是 DefaultAopProxyFactory,该类的 createAopProxy 方法则根据 ProxyFactoryBean 的一些属性来决定创建哪种代理:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    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.");
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

  看到只要实现类接口,则创建JDK代理,否则则是Cglib代理。最终创建了一个 JdkDynamicAopProxy代理。

  我们回到 ProxyFactoryBean 类的 getProxy 方法,当 createAopProxy 返回一个JDK 代理的后,则调用 getProxy 方法获取一个代理对象,我们看看该方法的JdkDynamicAopProxy实现:

public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }

        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

  该方法就是用JDK自带的proxy返回一个proxy代理,接下来我们看看另一种Cglib的实现:

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
    }

    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // Validate the class, writing log messages as necessary.
        validateClassIfNecessary(proxySuperClass, classLoader);

        // Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        // fixedInterceptorMap only populated at this point, after getCallbacks call above
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // Generate the proxy class and create a proxy instance.
        return createProxyClassAndInstance(enhancer, callbacks);
    }
    catch (CodeGenerationException | IllegalArgumentException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of class [" +
                this.advised.getTargetClass() + "]: " +
                "Common causes of this problem include using a final class or a non-visible class",
                ex);
    }
    catch (Throwable ex) {
        // TargetSource.getTarget() failed
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

  该方法基本上就是使用了Cglib 的库的一些API最后通过字节码生成代理类,比如 Enhancer 增强器,。总之,我们已经知道了Spring 是如何生成代理对象的,主要的通过 ProxyFactoryBean 来实现。

  最后,返回代理类,执行代理类的方法。完成切面编程。

四、AOP代理类调用流程

  由3已经知道,AOP直接返回了一个代理类,那么这个代理类如何调用方法实现AOP的呢?
  以JdkDynamicAopProxy为例,通过debug可以知道在调用到具体的方法时,实际调用了JdkDynamicAopProxy类的invoke方法。

  1、JdkDynamicAopProxy.invoke()

@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    // 获取代理对象中的目标源对象。 相当于 Service 实现类。
    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    Integer var9;
    try {
        // 判断逻辑目的是避免代理对象执行出现RuntimeException
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            Boolean var19 = this.equals(args[0]);
            return var19;
        }

        if (this.hashCodeDefined || !AopUtils.isHashCodeMethod(method)) {
            if (method.getDeclaringClass() == DecoratingProxy.class) {
                Class var18 = AopProxyUtils.ultimateTargetClass(this.advised);
                return var18;
            }
            //returnvalue, 定义返回结果数据的引用。
            Object retVal;
            if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                return retVal;
            }

            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            //incaseitcomesfromapool. 目标对象获取。目标对象的类对象 
            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);
            if (chain.isEmpty()) {
                // 如果代理对象没有需要切入的拦截器,执行目标对象中的方法。
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            } else {
                // 创建一个执行器,加入拦截信息,并按照顺序执行拦截代码和目标对象中的方法。
                MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, 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())) {
                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);
            }

            Object var13 = retVal;
            return var13;
        }

        var9 = this.hashCode();
    } finally {
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }

        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }

    }
    return var9;
}

  2、AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    // 方法匹配信息, 获取 spring 容器中的缓存。
    AdvisedSupport.MethodCacheKey cacheKey = new AdvisedSupport.MethodCacheKey(method);
    // 从已知的缓存中获取方法缓存匹配信息。
    List<Object> cached = (List)this.methodCache.get(cacheKey);
    if (cached == null) {
        // 查询代理对象需要执行的拦截信息。 关注此方法
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
        // 保存缓存数据,为后续其他代码提供缓存内容。
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

  3、DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
    List<Object> interceptorList = new ArrayList(config.getAdvisors().length);
    Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    // 通知注册器。spring 容器会将配置好的所有通知使用注册器管理。
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] var8 = config.getAdvisors();
    int var9 = var8.length;

    // 从配置信息中获取通知对象。
    for(int var10 = 0; var10 < var9; ++var10) {
        Advisor advisor = var8[var10];
        MethodInterceptor[] interceptors;
        if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    if (mm.isRuntime()) {
                        MethodInterceptor[] var15 = interceptors;
                        int var16 = interceptors.length;

                        for(int var17 = 0; var17 < var16; ++var17) {
                            MethodInterceptor interceptor = var15[var17];
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    } else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        } else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor)advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        } else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

  4、ReflectiveMethodInvocation.proceed()

public Object proceed() throws Throwable {
    // 开始执行代理方法。包含通知方法和目标对象中的真实方法。
    // 判断当前代理是否还有需要执行通知。如果没有通知,执行目标代码。
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return this.invokeJoinpoint();
    } else {
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
            return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
        } else {
            return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
        }
    }
} 

  综合以上给出JdkDynamicAopProxy的时序图:

五、AOP常见XML配置

  1、execution 表达式

  语法格式:execution(返回类型 包名.类名.方法名(参数表))

  如:execution(java.lang.String com.xxx.service.AService.test(java.lang.Integer))

  在类型 com.xxx.service.AService 中有方法 test,且参数为 Integer,返回类型为 String 时增加切面。

  如:execution(* com.xxx.AService.*(..)),代码:

<bean id="service" class="com.sxt.aop.TestServiceImpl"></bean>
<bean id="advice" class="com.sxt.aop.TestBeforeAdvice"></bean>
<aop:config>
    <!-- com.sxt.aop包中任意类型任意方法都作为连接点。 -->
    <aop:pointcut expression="execution(* com.sxt.aop.*.*(..))" id="pointcut"/>
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>

  com.xxx.AService 类型中的任意方法,任意类型返回结果,参数表不限定,都增加切面。 应用:最常用 。也是相对最通用。根据方法执行的标准,定义切点。如:事务处理,日志处理。

  2、target表达式

  以目标对象作为切点的表达式定义方式。

  语法: target(包名.接口名)

  如: target(com.xxx.IA) - 所有实现了 IA 接口的实现类,作为代理的目标对象,会自动增加通知的织入,实现切面。代码:

<bean id="service" class="com.sxt.aop.TestServiceImpl"></bean>
<bean id="advice" class="com.sxt.aop.TestBeforeAdvice"></bean>
<aop:config>
    <!-- 任意实现TestService接口的目标对象,都作为连接点 -->
    <aop:pointcut expression="target( com.sxt.aop.TestService )" id="pointcut"/>
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>

  应用:为某一个具体的接口实现提供的配置。如:登录 。登录的时候需要执行的附属逻辑是比较多的。在不同的业务流程中,附属逻辑也不同。如:电商中,可能在登录的时候,需要去执行购物车合并。

  3、this 表达式

  实现了某接口的代理对象,会作为切点。 和 target 很类似,但是更粗粒度,因为一个代理对象可能实现多个接口,意味着可以对应包含多个target。

  语法: this(包名.接口名),如代码:

<bean id="service" class="com.sxt.aop.TestServiceImpl"></bean>
<bean id="advice" class="com.sxt.aop.TestBeforeAdvice"></bean>
<aop:config>
    <!-- 实现接口TestService的任意代理对象都作为连接点 -->
    <aop:pointcut expression="this( com.sxt.aop.TestService )" id="pointcut"/>
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>

  如: this(com.xxx.IA) - 代理对象 Proxy 如果实现了 IA 接口,则作为连接点。 应用:针对某个具体的代理提供的配置。比 target 切点粒度细致。因为目标对象可以多实现。代理对象可以针对目标对象实现的多个接口的某一个接口,提供特定的切点 。如:银 行中的登录,银行中的帐户种类非常多。且有交叉。如:借记卡,贷记卡,借记还贷卡,贷 记还贷卡等。可以针对还贷接口提供一个切点,做还贷信息的记录等。

  4、within 表达式

  以包作为目标,定义切点。

  语法: within(包名.*)- 代表在包中的任意接口或类型都作为切点。如代码:

<bean id="service" class="com.sxt.aop.TestServiceImpl"></bean>
<bean id="advice" class="com.sxt.aop.TestBeforeAdvice"></bean>
<aop:config>
    <!-- com.sxt.aop包中的任意位置作为连接点 -->
    <aop:pointcut expression="within( com.sxt.aop.* )" id="pointcut"/>
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>

  应用: 针对某一个包提供的切点,粒度比 target 粗糙。如:某包中的所有接口都需要执行某附属逻辑。如:电商平台中的下订单。下订单服务中可能需 要特定的逻辑(时间戳校 验,库存检查等),这些逻辑,是其他业务线中不需要提供切面的。

  5、args 表达式

  以参数标准作为目标,定义切点。

  语法: args(类型,类型) - 代表方法的参数表符合要求的时候,作为切点。参数表是有顺序的。代码如:

<bean id="service" class="com.sxt.aop.TestServiceImpl"></bean>
<bean id="advice" class="com.sxt.aop.TestBeforeAdvice"></bean>
<aop:config>
    <!-- 任意只有唯一参数,且参数类型为字符串的,都作为连接点 -->
    <aop:pointcut expression="args( java.lang.String )" id="pointcut"/>
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>

  应用:主要应用在参数校验中。如:登录的时候必须传递两个字符 串参数(登录名和密 码)。可以使用 args 来限定。 配合这 execution 实现。 如: execution( * xxxx.*.login(..) ) args(string,string)。 是使用频率最低的表达式。

六、注解方式AOP概述

  而对于注解方式,通过分析源码我们知道注解方式和 XML 配置方式的底层实现都是一样的,都是通过继承 ProxyCreatorSupport 来实现的,不同的通过扩展不同的 Spring 提供的接口,XML 扩展的是FactoryBean 接口, 而注解方式扩展的是 BeanPostProcessor 接口,通过Spring 的扩展接口,能够对特定的Bean进行增强。而 AOP 正式通过这种方式实现的。

  大致流程为:

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

    重点过程可分为:

    1)通过AspectJAutoProxyBeanDefinitionParser类将AnnotationAwareAspectJAutoProxyCreator注册到Spring容器中;

    2)AnnotationAwareAspectJAutoProxyCreator类的postProcessAfterInitialization()方法将所有有advice的bean重新包装成proxy;

    3)调用bean方法时通过proxy来调用,proxy依次调用增强器的相关方法,来实现方法切入。

参考资料:

  SpringBoot2 | Spring AOP 原理深度源码分析

  深入理解Spring 之 源码剖析AOP(注解方式)

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

原文地址:https://www.cnblogs.com/jing99/p/11841159.html