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;
}
二、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);
}
}
在這裡我們只看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方法完成攔截器鏈呼叫
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,不匹配則此攔截器不生效
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:Spring中jdk動態代理
方式 方法 案例 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)-aop之jdk動態代理深入解析
續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動態代理作為宣告式事務
Spring之AOP的實現(JDK動態代理:只能代理介面,不能代理類)
通過動態代理物件,我們可以在動態代理類中加自己想要加的邏輯,而不需要在真實物件的類中新增自己想要的邏輯,提高了程式碼的擴充套件性,降低了耦合性。 java的動態代理機制,缺點:只能代理介面不能代理類。 在學習Spring的時候,我們知道Spring主要有兩大思想,一個
Spring—AOP兩種代理機制對比(JDK和CGLib動態代理)
Sprign 動態代理機制 Spirng的AOP的動態代理實現機制有兩種,分別是: 1)JDK動態代理: 具體實現原理: 1、通過實現InvocationHandlet介面建立自己的呼叫處理器 2、