001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.support; 018 019import org.aopalliance.intercept.MethodInvocation; 020 021import org.springframework.aop.DynamicIntroductionAdvice; 022import org.springframework.aop.IntroductionInterceptor; 023import org.springframework.aop.ProxyMethodInvocation; 024import org.springframework.lang.Nullable; 025import org.springframework.util.Assert; 026 027/** 028 * Convenient implementation of the 029 * {@link org.springframework.aop.IntroductionInterceptor} interface. 030 * 031 * <p>Subclasses merely need to extend this class and implement the interfaces 032 * to be introduced themselves. In this case the delegate is the subclass 033 * instance itself. Alternatively a separate delegate may implement the 034 * interface, and be set via the delegate bean property. 035 * 036 * <p>Delegates or subclasses may implement any number of interfaces. 037 * All interfaces except IntroductionInterceptor are picked up from 038 * the subclass or delegate by default. 039 * 040 * <p>The {@code suppressInterface} method can be used to suppress interfaces 041 * implemented by the delegate but which should not be introduced to the owning 042 * AOP proxy. 043 * 044 * <p>An instance of this class is serializable if the delegate is. 045 * 046 * @author Rod Johnson 047 * @author Juergen Hoeller 048 * @since 16.11.2003 049 * @see #suppressInterface 050 * @see DelegatePerTargetObjectIntroductionInterceptor 051 */ 052@SuppressWarnings("serial") 053public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport 054 implements IntroductionInterceptor { 055 056 /** 057 * Object that actually implements the interfaces. 058 * May be "this" if a subclass implements the introduced interfaces. 059 */ 060 @Nullable 061 private Object delegate; 062 063 064 /** 065 * Construct a new DelegatingIntroductionInterceptor, providing 066 * a delegate that implements the interfaces to be introduced. 067 * @param delegate the delegate that implements the introduced interfaces 068 */ 069 public DelegatingIntroductionInterceptor(Object delegate) { 070 init(delegate); 071 } 072 073 /** 074 * Construct a new DelegatingIntroductionInterceptor. 075 * The delegate will be the subclass, which must implement 076 * additional interfaces. 077 */ 078 protected DelegatingIntroductionInterceptor() { 079 init(this); 080 } 081 082 083 /** 084 * Both constructors use this init method, as it is impossible to pass 085 * a "this" reference from one constructor to another. 086 * @param delegate the delegate object 087 */ 088 private void init(Object delegate) { 089 Assert.notNull(delegate, "Delegate must not be null"); 090 this.delegate = delegate; 091 implementInterfacesOnObject(delegate); 092 093 // We don't want to expose the control interface 094 suppressInterface(IntroductionInterceptor.class); 095 suppressInterface(DynamicIntroductionAdvice.class); 096 } 097 098 099 /** 100 * Subclasses may need to override this if they want to perform custom 101 * behaviour in around advice. However, subclasses should invoke this 102 * method, which handles introduced interfaces and forwarding to the target. 103 */ 104 @Override 105 @Nullable 106 public Object invoke(MethodInvocation mi) throws Throwable { 107 if (isMethodOnIntroducedInterface(mi)) { 108 // Using the following method rather than direct reflection, we 109 // get correct handling of InvocationTargetException 110 // if the introduced method throws an exception. 111 Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments()); 112 113 // Massage return value if possible: if the delegate returned itself, 114 // we really want to return the proxy. 115 if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) { 116 Object proxy = ((ProxyMethodInvocation) mi).getProxy(); 117 if (mi.getMethod().getReturnType().isInstance(proxy)) { 118 retVal = proxy; 119 } 120 } 121 return retVal; 122 } 123 124 return doProceed(mi); 125 } 126 127 /** 128 * Proceed with the supplied {@link org.aopalliance.intercept.MethodInterceptor}. 129 * Subclasses can override this method to intercept method invocations on the 130 * target object which is useful when an introduction needs to monitor the object 131 * that it is introduced into. This method is <strong>never</strong> called for 132 * {@link MethodInvocation MethodInvocations} on the introduced interfaces. 133 */ 134 protected Object doProceed(MethodInvocation mi) throws Throwable { 135 // If we get here, just pass the invocation on. 136 return mi.proceed(); 137 } 138 139}