日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring AOP源码解析——AOP动态代理原理和实现方式

發(fā)布時間:2023/12/9 javascript 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring AOP源码解析——AOP动态代理原理和实现方式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

Spring介紹

Spring(http://spring.io/)是一個輕量級的Java 開發(fā)框架,同時也是輕量級的IoC和AOP的容器框架,主要是針對JavaBean的生命周期進(jìn)行管理的輕量級容器,可以單獨使用,也可以和Struts框架,MyBatis框架等組合使用。

?

AOP介紹

AOP是什么

AOP技術(shù)利用一種稱為“橫切”的技術(shù),剖解開封裝的對象內(nèi)部,并將那些影響了多個類的公共行為封裝到一個可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護(hù)性。AOP代表的是一個橫向的關(guān)系,如果說“對象”是一個空心的圓柱體,其中封裝的是對象的屬性和行為;那么面向方面編程的方法,就仿佛一把利刃,將這些空心圓柱體剖開,以獲得其內(nèi)部的消息。而剖開的切面,也就是所謂的“方面”了。然后它又以巧奪天功的妙手將這些剖開的切面復(fù)原,不留痕跡。

?

AOP相關(guān)概念

方面(Aspect):一個關(guān)注點的模塊化,這個關(guān)注點實現(xiàn)可能另外橫切多個對象。事務(wù)管理是一個很好的橫切關(guān)注點例子。方面用Spring的Advisor或攔截器實現(xiàn)。

連接點(Joinpoint): 程序執(zhí)行過程中明確的點,如方法的調(diào)用或特定的異常被拋出。

通知(Advice): 在特定的連接點,AOP框架執(zhí)行的動作。各種類型的通知包括“around”、“before”和“throws”通知。通知類型將在下面討論。許多AOP框架包括Spring都是以攔截器做通知模型,維護(hù)一個“圍繞”連接點的攔截器鏈。Spring中定義了四個advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice

切入點(Pointcut): 指定一個通知將被引發(fā)的一系列連接點的集合。AOP框架必須允許開發(fā)者指定切入點:例如,使用正則表達(dá)式。 Spring定義了Pointcut接口,用來組合MethodMatcher和ClassFilter,可以通過名字很清楚的理解, MethodMatcher是用來檢查目標(biāo)類的方法是否可以被應(yīng)用此通知,而ClassFilter是用來檢查Pointcut是否應(yīng)該應(yīng)用到目標(biāo)類上

目標(biāo)對象(Target Object): 包含連接點的對象。也被稱作被通知或被代理對象。

AOP代理(AOP Proxy): AOP框架創(chuàng)建的對象,包含通知。 在Spring中,AOP代理可以是JDK動態(tài)代理或者CGLIB代理。

?

AOP原理

AOP 實現(xiàn)的關(guān)鍵就在于 AOP 框架自動創(chuàng)建的 AOP 代理,AOP 代理則可分為靜態(tài)代理和動態(tài)代理兩大類,其中靜態(tài)代理是指使用 AOP 框架提供的命令進(jìn)行編譯,從而在編譯階段就可生成 AOP 代理類,因此也稱為編譯時增強(qiáng);而動態(tài)代理則在運(yùn)行時借助于 JDK 動態(tài)代理、CGLIB 等在內(nèi)存中“臨時”生成 AOP 動態(tài)代理類,因此也被稱為運(yùn)行時增強(qiáng)。Spring AOP則采用的是動態(tài)代理來實現(xiàn)。

在本節(jié)中,我們只分中JDK動態(tài)代理的實現(xiàn)方式。

?

源碼解析

準(zhǔn)備工作

首先定義一個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動態(tài)代理的實現(xiàn)方式,所以需要定義一個接口。

public interface ITest{public void doSomething(); }

目標(biāo)對象實現(xiàn)上面定義的接口。

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");} }

編寫程序入口代碼,可以直接打斷點進(jìn)行調(diào)試。

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); Test bean = context.getBean("test", Test.class); bean.doSomething();

開始解析

根據(jù)上節(jié)對bean創(chuàng)建和初始化過程的分析,我們來到AbstractAutowireCapableBeanFactory.java類的initializeBean方法。在這個方法里Spring會對創(chuàng)建完成的Bean進(jìn)行初始化,我們重點關(guān)注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;}

進(jìn)入applyBeanPostProcessorsAfterInitializaton方法,繼續(xù)往下。

@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;}

接著進(jìn)入AbstractAutoProxyCreator.java類的postProcessAfterInitialization方法中,繼續(xù)往下。

/*** 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信息,然后調(diào)用createProxy方法為目標(biāo)對象創(chuàng)建了代理,接著將創(chuàng)建的代理對象返回。

/*** 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;}

進(jìn)入createProxy方法,Spring根據(jù)傳入的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());}

接著進(jìn)入ProxyFactory.java類的getProxy方法,只有一行代碼。我們分為兩個部分來分析:

第一部分,調(diào)用createAopProxy方法初始化AopProxy。

第二部分,調(diào)用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

先進(jìn)入ProxyCreatorSupport.java類的createAopProxy方法。這就是生成代理的入口,你會發(fā)現(xiàn)傳入的參數(shù)是是this,其實傳入的就是this的父類AdvisedSupport.java中的advisor等生成代理的核心參數(shù)。

/*** 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根據(jù)代理的目標(biāo)對象是否實現(xiàn)了接口,來返回JdkDynamicAopProxy的動態(tài)代理或者CGLIB的代理,并且傳入advisor核心參數(shù)(JdkDynamicAopProxy這個實現(xiàn)了InvocationHandler,要實現(xiàn)invoke的關(guān)鍵就是傳入的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);}}

接著進(jìn)入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是如何獲取代理對象的。

獲取代理對象

先進(jìn)入getProxy方法,這里我們重點關(guān)注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);}

接著進(jìn)入Proxy.java類的newProxyInstance方法,這是java reflect包提供的原生創(chuàng)建代理類的方法。就是在這里,目標(biāo)對象的代理對象完成了創(chuàng)建并返回。

/*** 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);}}

以上就完成了創(chuàng)建并獲取代理對象的整個過程。

?

總結(jié)

通過這次源碼分析,我們應(yīng)該知道AOP動態(tài)代理的原理是什么,也知道Spring是如何根據(jù)目標(biāo)對象去創(chuàng)建并獲取代理對象的。其實,整個過程的本質(zhì)就是Spring根據(jù)配置文件,利用反射和目標(biāo)對象實現(xiàn)所的接口創(chuàng)建了代理對象。然后將代理對象返回,與原對象進(jìn)行替換,從而實現(xiàn)了動態(tài)代理。如果還有不明白的地方,可以對照著Spring的源碼自己動手理解一下,希望能對大家有所幫助。

轉(zhuǎn)載于:https://my.oschina.net/zhaojia/blog/778455

總結(jié)

以上是生活随笔為你收集整理的Spring AOP源码解析——AOP动态代理原理和实现方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。