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; }
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>
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; }
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工厂生产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; }
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(); } }
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; }
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代理类调用流程
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依次调用增强器的相关方法,来实现方法切入。
参考资料: