2019独角兽企业重金招聘Python工程师标准>>>
Spring介绍
Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,MyBatis框架等组合使用。
AOP介绍
AOP是什么
AOP技术利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
AOP相关概念
方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice
切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上
目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。
AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
AOP原理
AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。Spring AOP则采用的是动态代理来实现。
在本节中,我们只分中JDK动态代理的实现方式。
源码解析
准备工作
首先定义一个Spring AOP的配置文件spring-aop.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.xsd"><aop:config><aop:aspect id="TestAspect" ref="aspect"><aop:pointcut id="pointcut" expression="execution(* org.study.spring.aop.*.*(..))"/><aop:before method="doBefore" pointcut-ref="pointcut"/></aop:aspect></aop:config><bean id="aspect" class="org.study.spring.aop.Aspect"/><bean id="test" class="org.study.spring.aop.Test"/></beans>
由于我们只分析JDK动态代理的实现方式,所以需要定义一个接口。
public interface ITest{public void doSomething();
}
目标对象实现上面定义的接口。
public class Test implements ITest {public void doSomething() {System.out.println("do something");}
}
定义Aspect,这里我们以前置通知为例。
public class Aspect {public void doBefore(JoinPoint jp) {System.out.println("do before");}
}
编写程序入口代码,可以直接打断点进行调试。
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Test bean = context.getBean("test", Test.class);
bean.doSomething();
开始解析
根据上节对bean创建和初始化过程的分析,我们来到AbstractAutowireCapableBeanFactory.java类的initializeBean方法。在这个方法里Spring会对创建完成的Bean进行初始化,我们重点关注applyBeanPostProcessorsAfterInitializaton这个方法。
/*** Initialize the given bean instance, applying factory callbacks* as well as init methods and bean post processors.* <p>Called from {@link #createBean} for traditionally defined beans,* and from {@link #initializeBean} for existing bean instances.* @param beanName the bean name in the factory (for debugging purposes)* @param bean the new bean instance we may need to initialize* @param mbd the bean definition that the bean was created with* (can also be {@code null}, if given an existing bean instance)* @return the initialized bean instance (potentially wrapped)* @see BeanNameAware* @see BeanClassLoaderAware* @see BeanFactoryAware* @see #applyBeanPostProcessorsBeforeInitialization* @see #invokeInitMethods* @see #applyBeanPostProcessorsAfterInitialization*/protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {invokeAwareMethods(beanName, bean);return null;}}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
进入applyBeanPostProcessorsAfterInitializaton方法,继续往下。
@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {result = beanProcessor.postProcessAfterInitialization(result, beanName);if (result == null) {return result;}}return result;}
接着进入AbstractAutoProxyCreator.java类的postProcessAfterInitialization方法中,继续往下。
/*** Create a proxy with the configured interceptors if the bean is* identified as one to proxy by the subclass.* @see #getAdvicesAndAdvisorsForBean*/@Overridepublic 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方法,我们可以看到,Spring在这里先获取配置好的Advisor信息,然后调用createProxy方法为目标对象创建了代理,接着将创建的代理对象返回。
/*** Wrap the given bean if necessary, i.e. if it is eligible for being proxied.* @param bean the raw bean instance* @param beanName the name of the bean* @param cacheKey the cache key for metadata access* @return a proxy wrapping the bean, or the raw bean instance as-is*/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.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}
进入createProxy方法,Spring根据传入的advisor配置信息,初始化ProxyFactory然后获取并返回代理对象,我们直接看最后一行proxyFactory.getProxy(getProxyClassLoader())。
/*** Create an AOP proxy for the given bean.* @param beanClass the class of the bean* @param beanName the name of the bean* @param specificInterceptors the set of interceptors that is* specific to this bean (may be empty, but not null)* @param targetSource the TargetSource for the proxy,* already pre-configured to access the bean* @return the AOP proxy for the bean* @see #buildAdvisors*/protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);if (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, 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);}return proxyFactory.getProxy(getProxyClassLoader());}
接着进入ProxyFactory.java类的getProxy方法,只有一行代码。我们分为两个部分来分析:
第一部分,调用createAopProxy方法初始化AopProxy。
第二部分,调用getProxy方法获取代理对象。
/*** Create a new proxy according to the settings in this factory.* <p>Can be called repeatedly. Effect will vary if we've added* or removed interfaces. Can add and remove interceptors.* <p>Uses the given class loader (if necessary for proxy creation).* @param classLoader the class loader to create the proxy with* (or {@code null} for the low-level proxy facility's default)* @return the proxy object*/public Object getProxy(ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}
我们先来看看AopProxy是如何被初始化的。
初始化AopProxy
先进入ProxyCreatorSupport.java类的createAopProxy方法。这就是生成代理的入口,你会发现传入的参数是是this,其实传入的就是this的父类AdvisedSupport.java中的advisor等生成代理的核心参数。
/*** Subclasses should call this to get a new AOP proxy. They should <b>not</b>* create an AOP proxy with {@code this} as an argument.*/protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);}
打开DefaultAopProxyFactory.java类中的createAopProxy方法。Spring根据代理的目标对象是否实现了接口,来返回JdkDynamicAopProxy的动态代理或者CGLIB的代理,并且传入advisor核心参数(JdkDynamicAopProxy这个实现了InvocationHandler,要实现invoke的关键就是传入的advisor)。
@Overridepublic 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);}}
接着进入JdkDynamicAopProxy.java类中的JdkDynamicAopProxy方法,将传入的AdvisedSupport赋值到advised里。
/*** Construct a new JdkDynamicAopProxy for the given AOP configuration.* @param config the AOP configuration as AdvisedSupport object* @throws AopConfigException if the config is invalid. We try to throw an informative* exception in this case, rather than let a mysterious failure happen later.*/public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {Assert.notNull(config, "AdvisedSupport must not be null");if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {throw new AopConfigException("No advisors and no TargetSource specified");}this.advised = config;}
到这里,AopProxy已初始化完成。接下来我们来看,Spring是如何获取代理对象的。
获取代理对象
先进入getProxy方法,这里我们重点关注newProxyInstance这个方法。
@Overridepublic 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);return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}
接着进入Proxy.java类的newProxyInstance方法,这是java reflect包提供的原生创建代理类的方法。就是在这里,目标对象的代理对象完成了创建并返回。
/*** Returns an instance of a proxy class for the specified interfaces* that dispatches method invocations to the specified invocation* handler.** <p>{@code Proxy.newProxyInstance} throws* {@code IllegalArgumentException} for the same reasons that* {@code Proxy.getProxyClass} does.** @param loader the class loader to define the proxy class* @param interfaces the list of interfaces for the proxy class* to implement* @param h the invocation handler to dispatch method invocations to* @return a proxy instance with the specified invocation handler of a* proxy class that is defined by the specified class loader* and that implements the specified interfaces* @throws IllegalArgumentException if any of the restrictions on the* parameters that may be passed to {@code getProxyClass}* are violated* @throws SecurityException if a security manager, <em>s</em>, is present* and any of the following conditions is met:* <ul>* <li> the given {@code loader} is {@code null} and* the caller's class loader is not {@code null} and the* invocation of {@link SecurityManager#checkPermission* s.checkPermission} with* {@code RuntimePermission("getClassLoader")} permission* denies access;</li>* <li> for each proxy interface, {@code intf},* the caller's class loader is not the same as or an* ancestor of the class loader for {@code intf} and* invocation of {@link SecurityManager#checkPackageAccess* s.checkPackageAccess()} denies access to {@code intf};</li>* <li> any of the given proxy interfaces is non-public and the* caller class is not in the same {@linkplain Package runtime package}* as the non-public interface and the invocation of* {@link SecurityManager#checkPermission s.checkPermission} with* {@code ReflectPermission("newProxyInPackage.{package name}")}* permission denies access.</li>* </ul>* @throws NullPointerException if the {@code interfaces} array* argument or any of its elements are {@code null}, or* if the invocation handler, {@code h}, is* {@code null}*/@CallerSensitivepublic static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{Objects.requireNonNull(h);final Class<?>[] intfs = interfaces.clone();final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** Look up or generate the designated proxy class.*/Class<?> cl = getProxyClass0(loader, intfs);/** Invoke its constructor with the designated invocation handler.*/try {if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}}
以上就完成了创建并获取代理对象的整个过程。
总结
通过这次源码分析,我们应该知道AOP动态代理的原理是什么,也知道Spring是如何根据目标对象去创建并获取代理对象的。其实,整个过程的本质就是Spring根据配置文件,利用反射和目标对象实现所的接口创建了代理对象。然后将代理对象返回,与原对象进行替换,从而实现了动态代理。如果还有不明白的地方,可以对照着Spring的源码自己动手理解一下,希望能对大家有所帮助。