AOP就是面向切面編程,主要做用就是抽取公共代碼,無侵入的加強現有類的功能。從一個簡單的spring AOP配置開始:html
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> <!-- 定義target --> <bean id="human" class="org.lep.springtest.aop.Human"> </bean> <!-- 定義advice --> <bean id="sleepHlper" class="org.lep.springtest.aop.SleepHelper"> </bean> <!-- 定義切點 --> <bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value=".*sleep"></property> </bean> <!-- 定義advisor --> <bean id="sleepAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="sleepHlper"></property> <property name="pointcut" ref="sleepPointcut"></property> </bean> <!-- 定義代理 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="human"></property> <property name="interceptorNames" value="sleepAdvisor"></property> </bean> </beans>
上面的配置涉及到AOP幾個重要的概念:java
從上面能夠看出是proxy把這些東西結合起來,那麼proxy是怎麼實現的呢,好比:spring
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml"); Sleep sleeper =(Sleep) context.getBean("proxy"); sleeper.sleep();
上面有兩個問題:編程
針對第一個問題咱們分析getBean的過程,也就是ProxyFactoryBean的初始化spring-mvc
在spring IoC容器初始化以後咱們分析了bean的初始化,最後提到了FactoryBean和BeanFactory的區別,可是沒有詳細分析涉及到的factoryBean的初始化過程,具體以下:mvc
ProxyFactoryBean的初始化就是先當作普通的bean初始化,以後再獲取具有factory能力的bean,這裏分爲代理對象的生成和得到真正的代理ui
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); // createAopProxy裏面會調用DefaultAopProxyFactory的createAopProxy方法來獲取AopProxy // getProxy會利用上面生成的AopProxy來生成具體的代理對象 this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; }
DefaultAopProxyFactory的createAopProxy以下:this
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."); } // 若是目標類實現了接口則使用jdk生成proxy if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } if (!cglibAvailable) { throw new AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " + "Add CGLIB to the class path or specify proxy interfaces."); } // 若是沒有實現接口,則使用cglib來生成proxy,由於jdk的生成方法只支持實現了接口的類的proxy生成 return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } }
在ProxyFactoryBean的getProxy方法中會調用上面得到到的AopProxy來生成proxy,生成的proxy返回,也就是最後getBean得到到對象,這個對象是實現了Sleep接口的類,只不過這個類存在內存裏面,由JdkDynamicProxy動態生成的(也就是動態代理),因此能夠向上轉型爲Sleep
將動態代理類保存在本地,反編譯獲得:debug
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import org.lep.springtest.aop.Sleep; public final class $Proxy0 extends Proxy implements Sleep { private static Method m1; private static Method m0; private static Method m3; private static Method m2; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void sleep() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("org.lep.springtest.aop.Sleep").getMethod("sleep", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
上面已經說到了,由於是在內存中存在的動態代理,這個代理實現了Sleep接口,也就是說調試的時候應該跳轉到的是這個代理對象的sleep方法,在sleep方法中調用了InvocationHandler的invoke方法,而JdkDynamicProxy實現了InvocationHandler接口,在JdkDynamicProxy的getProxy方法中3d
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); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 把JdkDynamicProxy自身傳入,在proxy中調用的就是JdkDynamicProxy的invoke方法 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
可是IDE不知道內存中的代理類類,因此就直接跳轉到了JdkDynamicProxy的invoke方法