1. 程式人生 > >Spring AOP --JDK動態代理方式

Spring AOP --JDK動態代理方式

我們知道Spring是通過JDK或者CGLib實現動態代理的,今天我們討論一下JDK實現動態代理的原理。

一、簡述

Spring在解析Bean的定義之後會將Bean的定義生成一個BeanDefinition物件並且由BeanDefinitionHolder物件持有。在這個過程中,如果Bean需要被通知切入,BeanDefinition會被重新轉換成一個proxyDefinition(其實也是一個BeanDefinition物件,只不過描述的是一個ProxyFactoryBean)。ProxyFactoryBean是一個實現了FactoryBean的介面,用來生成被被切入的物件。Spring AOP的實現基本上是通過ProxyFactoryBean實現的。我們今天討論的重點也是這個類。

在討論ProxyFactoryBean之前,我們先看一下一個BeanDefinition轉換成proxyDefintion的過程。

public final BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definitionHolder, ParserContext parserContext) {

BeanDefinitionRegistry registry = parserContext.getRegistry();

// get the root bean name - will be the name of the generated proxy factory bean

String existingBeanName = definitionHolder.getBeanName();

BeanDefinition targetDefinition = definitionHolder.getBeanDefinition();

BeanDefinitionHolder targetHolder = new BeanDefinitionHolder(targetDefinition, existingBeanName + ".TARGET");

// delegate to subclass for interceptor definition

BeanDefinition interceptorDefinition = createInterceptorDefinition(node);

// generate name and register the interceptor

String interceptorName = existingBeanName + "." + getInterceptorNameSuffix(interceptorDefinition);

BeanDefinitionReaderUtils.registerBeanDefinition(

new BeanDefinitionHolder(interceptorDefinition, interceptorName), registry);

BeanDefinitionHolder result = definitionHolder;

if (!isProxyFactoryBeanDefinition(targetDefinition)) {

// create the proxy definition 這裡建立proxyDefinition物件,並且從原來的BeanDefinition物件中複製屬性

RootBeanDefinition proxyDefinition = new RootBeanDefinition();

// create proxy factory bean definition

proxyDefinition.setBeanClass(ProxyFactoryBean.class);

proxyDefinition.setScope(targetDefinition.getScope());

proxyDefinition.setLazyInit(targetDefinition.isLazyInit());

// set the target

proxyDefinition.setDecoratedDefinition(targetHolder);

proxyDefinition.getPropertyValues().add("target", targetHolder);

// create the interceptor names list

proxyDefinition.getPropertyValues().add("interceptorNames", new ManagedList<String>());

// copy autowire settings from original bean definition.

proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());

proxyDefinition.setPrimary(targetDefinition.isPrimary());

if (targetDefinition instanceof AbstractBeanDefinition) {

proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);

}

// wrap it in a BeanDefinitionHolder with bean name

result = new BeanDefinitionHolder(proxyDefinition, existingBeanName);

}

addInterceptorNameToList(interceptorName, result.getBeanDefinition());

return result;

}

Java

二、ProxyFactoryBean的原理

我們先來看一下ProxyFactoryBean的繼承關係:

ProxyFactoryBean類圖

ProxyFactoryBean實現了FactoryBean、BeanClassLoaderAware、BeanFactoryAware介面,這裡就不多說了。ProxyCreatorSupport這個類則是建立代理物件的關鍵所在。  我們先來看看產生代理物件的方法:

public Object getObject() throws BeansException {

initializeAdvisorChain();

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();

}

}

initializeAdvisorChain() 方法是將通知鏈例項化。然後判斷物件是否要生成單例而選擇呼叫不同的方法,這裡我們只看生成單例物件的方法。

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

}

//獲取目標類實現的所有介面,並註冊給父類的interfaces屬性,為jdk動態代理做準備

setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));

}

// Initialize the shared singleton instance.

super.setFrozen(this.freezeProxy);

//這裡產生代理物件

this.singletonInstance = getProxy(createAopProxy());

}

return this.singletonInstance;

}

我們可以看到,產生代理物件是通過getProxy()方法實現的,這個方法我們看一下:

protected Object getProxy(AopProxy aopProxy) {

return aopProxy.getProxy(this.proxyClassLoader);

}

AopProxy物件的getProxy()方法產生我們需要的代理物件,究竟AopProxy這個類是什麼,我們接下來先看一下產生這個物件的方法createAopProxy():

protected final synchronized AopProxy createAopProxy() {

if (!this.active) {

activate();

}

return getAopProxyFactory().createAopProxy(this);

}

createAopProxy方法:

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()) {

return new JdkDynamicAopProxy(config);

}

return new ObjenesisCglibAopProxy(config);

}

else {

return new JdkDynamicAopProxy(config);

}

}

Java

在這裡我們只看JdkDynamicAopProxy這個類的實現,我們前面提到,真正代理物件的生成是由AopProxy的getProxy方法完成的,這裡我們看一下JdkDynamicAopProxy的getProxy方法,這也是本文討論的重點:

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

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

}

我們看可以很清楚的看到,代理物件的生成直接使用了jdk動態代理:Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);而代理邏輯是通過實現了InvocationHandler介面的invoke方法實現的。而這裡用到的實現了InvocationHandler介面的類就是JdkDynamicAopProxy自身。JdkDynamicAopProxy自身實現了InvocationHandler介面,完成了Spring AOP攔截器鏈攔截等一系列邏輯,我們看一下JdkDynamicAopProxy的invoke方法的具體實現:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

MethodInvocation invocation;

Object oldProxy = null;

boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource;

Class<?> targetClass = null;

Object target = null;

try {

//沒有重寫equals方法

if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {

// The target does not implement the equals(Object) method itself.

return equals(args[0]);

}

//沒有重寫hashCode方法

if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {

// The target does not implement the hashCode() method itself.

return hashCode();

}

//代理的類是Advised,這裡直接執行,不做任何代理

if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&

method.getDeclaringClass().isAssignableFrom(Advised.class)) {

// Service invocations on ProxyConfig with the proxy config...

return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);

}

Object retVal;

if (this.advised.exposeProxy) {

// Make invocation available if necessary.

oldProxy = AopContext.setCurrentProxy(proxy);

setProxyContext = true;

}

// May be null. Get as late as possible to minimize the time we "own" the target,

// in case it comes from a pool.

//獲得代理物件

target = targetSource.getTarget();

if (target != null) {

targetClass = target.getClass();

}

// Get the interception chain for this method.

//獲得已經定義的攔截器鏈

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

// Check whether we have any advice. If we don't, we can fallback on direct

// reflective invocation of the target, and avoid creating a MethodInvocation.

if (chain.isEmpty()) {

// We can skip creating a MethodInvocation: just invoke the target directly

// Note that the final invoker must be an InvokerInterceptor so we know it does

// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.

//攔截器鏈是空的,直接執行需要代理的方法

retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);

}

else {

// We need to create a method invocation...

//這裡是呼叫攔截器鏈的地方,先建立一個MethodInvocation物件,然後呼叫該物件的proceed方法完成攔截器鏈呼叫

Java

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

// Proceed to the joinpoint through the interceptor chain.

retVal = invocation.proceed();

}

// Massage return value if necessary.

Class<?> returnType = method.getReturnType();

//這裡處理返回值,判斷返回值和方法需要的返回是否一致

if (retVal != null && retVal == target && returnType.isInstance(proxy) &&

!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {

// Special case: it returned "this" and the return type of the method

// is type-compatible. Note that we can't help if the target sets

// a reference to itself in another returned object.

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

}

return retVal;

}

finally {

if (target != null && !targetSource.isStatic()) {

// Must have come from TargetSource.

targetSource.releaseTarget(target);

}

if (setProxyContext) {

// Restore old proxy.

AopContext.setCurrentProxy(oldProxy);

}

}

}

攔截器鏈的呼叫

從上面的程式碼和註釋中我們可以看到spring實現aop的主要流程,具體如何呼叫攔截器鏈,我們來看一下MethodInvocation的proceed方法

public Object proceed() throws Throwable {

// We start with an index of -1 and increment early.

// currentInterceptorIndex是從-1開始的,所以攔截器鏈呼叫結束的時候index是 this.interceptorsAndDynamicMethodMatchers.size() - 1

// 呼叫鏈結束後執行目標方法

if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {

return invokeJoinpoint();

}

// 獲得當前處理到的攔截器

Object interceptorOrInterceptionAdvice =

this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

// 這裡判斷是否是InterceptorAndDynamicMethodMatcher,如果是,這要判斷是否匹配methodMatcher,不匹配則此攔截器不生效

Java

if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

// Evaluate dynamic method matcher here: static part will already have

// been evaluated and found to match.

InterceptorAndDynamicMethodMatcher dm =

(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;

if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {

return dm.interceptor.invoke(this);

}

else {

// Dynamic matching failed.

// Skip this interceptor and invoke the next in the chain.

return proceed();

}

}

else {

相關推薦

Spring AOP --JDK動態代理方式

我們知道Spring是通過JDK或者CGLib實現動態代理的,今天我們討論一下JDK實現動態代理的原理。 一、簡述 Spring在解析Bean的定義之後會將Bean的定義生成一個BeanDefinition物件並且由BeanDefinitionHolder物件持有。在

Spring AOP動態代理實例

delete 日誌 實現類 imp exc print cati user ins 1.項目結構圖如下3.3.3.1: 圖3.3.3.1 2.IUserServ接口代碼與UserServImpl實現類代碼和上述代碼相同 3.LogHandler類代碼

SSM-Spring-09:Springjdk動態代理

方式 方法 案例 reflect jdk BE nbsp size 調用 ------------吾亦無他,唯手熟爾,謙卑若愚,好學若饑------------- JDK動態代理:   為何叫JDK動態代理呢?     所謂JDK,jdk是java開發工具包

Spring AOP動態代理

Spring AOP有兩種動態代理的方式,一種是jdk的動態代理,一種是cglib實現的動態代理,看下兩種代理的實現方式。 1.jdk的動態代理 介面: public interface ISaler { public void buy(); } 實現類: public

javaEE Mybatis,Mybatis與Spring整合之動態代理方式(推薦),自動建立Dao層實現類

src/applicationContext.xml(Spring核心配置檔案): <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.or

spring aop切面動態代理xml配置實現

上次我已經寫過aop用註解實現的這次是用配置實現,個人感覺配置實現比較好,畢竟程式是給人看的嗎,配置裡寫的一清二楚,別人看來也好懂,而且配置修改起來也比較容易,便於後期維護及修改,而才用註解方式的修改,需要修改註解,或者重寫實現類,比較麻煩,建議採用配置方式實現,至於效能方

Spring AOP原始碼分析--代理方式的選擇

能堅持別人不能堅持的,才能擁有別人未曾擁有的。關注程式設計大道公眾號,讓我們一同堅持心中所想,一起成長!!   年前寫了一個面試突擊系列的文章,目前只有redis相關的。在這個系列裡,我整理了一些面試題與大家分享,幫助年後和我一樣想要在金三銀四準備跳槽的同學。我們一起鞏固、突擊面試官常問的一些面

Spring AOP 代理實現的兩種方式JDK動態代理 和 Cglib框架動態代理

1.JDK動態代理 JDK API 內建 ---- 通過 Proxy類,為目標物件建立代理 (必須面向介面代理 ),此文中介面為UserDao,實現類為UserDaoImpl. public class UserDaoImpl implements UserDao {

【轉載】Spring AOP詳解 、 JDK動態代理、CGLib動態代理

rto 工廠 第一個 lec 僅支持 sel clas sleep gpo 原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspect Oriented Programing的簡稱,面向切面

Spring的兩種代理方式JDK動態代理和CGLIB動態代理

轉自 :https://blog.csdn.net/cckevincyh/article/details/54962920   代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可譯為”代理“,所謂代理,就是一個人或者一個機構代表另一個人或者另一個機構採取行動。

Spring AOP 前篇(一):Java代理JDK靜態代理JDK動態代理、CGLIB動態代理

Spring AOP 前篇:Java代理之JDK靜態代理、JDK動態代理、CGLIB動態代理 該文章參考多篇文章的基礎上進行了簡化並做少許修改,方便理解。原文章地址如下: Java之代理(jdk靜態代理,jdk動態代理,cglib動態代理,aop,aspectj

spring原始碼閱讀(2)-aopjdk動態代理深入解析

續spring原始碼閱讀(2)-aop之j動態代理 我們從需求作為動態代理髮展的切入吧 現在有5個已經投產了的run100m的實現,我們新的需求需要監控不同實現的執行效能,如果我們針對這五個實現分別去新增效能監控的程式碼,如此就造成兩個問題: 一個是已經穩定的程式碼需要

Spring AOP中的JDK動態代理

一、關於靜態代理和動態代理的概念1 代理模式是常用的Java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物

Spring底層AOP的原理示例(JDK動態代理和cglib動態代理

1 JDK動態代理(必須要有介面) 介面 package com.itykd.dao; public interface UserDao { void save(); void update(); void find(); void delete(); } 實現

Spring AOP之---基於JDK動態代理和CGLib動態代理AOP實現

AOP(面向切面程式設計)是OOP的有益補充,它只適合那些具有橫切邏輯的應用場合,如效能監測,訪問控制,事物管理,日誌記錄等。至於怎麼理解橫切邏輯,敲完例項程式碼也就明白了。 為什麼要使用AOP,舉個栗子:需要監測一些方法的執行所消耗的時間,在每個方法開始

Spring AOP底層實現- JDK動態代理和CGLIB動態代理

Spring AOP是執行時織入的,那麼執行時織入到底是怎麼實現的呢?答案就是代理物件。 代理又可以分為靜態代理和動態代理。 靜態代理:由程式設計師建立或特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。

spring aop原理 JDK動態代理和CGLIB動態代理

lan ble -- 自定義 and ets spec gen ase Spring的兩大特性是IOC和AOPIOC負責將對象動態的註入到容器,從而達到一種需要誰就註入誰,什麽時候需要就什麽時候註入的效果。理解spring的ioc也很重要。但是今天主要來和大家講講aop。A

2.1 Spring宣告式事務的實現方式選擇(JDK動態代理與cglib)

1、簡介Spring宣告式事務的具體實現方式是動態決定的,與具體配置、以及事務代理物件是否實現介面等有關。2、使用JDK動態代理的情況在滿足下面兩個條件時,Spring會選擇JDK動態代理作為宣告式事務

SpringAOP的實現(JDK動態代理:只能代理介面,不能代理類)

通過動態代理物件,我們可以在動態代理類中加自己想要加的邏輯,而不需要在真實物件的類中新增自己想要的邏輯,提高了程式碼的擴充套件性,降低了耦合性。 java的動態代理機制,缺點:只能代理介面不能代理類。 在學習Spring的時候,我們知道Spring主要有兩大思想,一個

SpringAOP兩種代理機制對比(JDK和CGLib動態代理

Sprign 動態代理機制 Spirng的AOP的動態代理實現機制有兩種,分別是: 1)JDK動態代理: 具體實現原理: 1、通過實現InvocationHandlet介面建立自己的呼叫處理器 2、