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方法