潘志宝
2024-12-12 3374d19db03cce97572c3a294f137d1ea70b307f
提交 | 用户 | 时间
e7c126 1 /*
H 2  * Copyright 2002-2021 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.springframework.messaging.handler.invocation;
18
19 import com.iailab.framework.tenant.core.context.TenantContextHolder;
20 import com.iailab.framework.tenant.core.util.TenantUtils;
21 import org.springframework.core.DefaultParameterNameDiscoverer;
22 import org.springframework.core.MethodParameter;
23 import org.springframework.core.ParameterNameDiscoverer;
24 import org.springframework.core.ResolvableType;
25 import org.springframework.lang.Nullable;
26 import org.springframework.messaging.Message;
27 import org.springframework.messaging.handler.HandlerMethod;
28 import org.springframework.util.ObjectUtils;
29
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.lang.reflect.Type;
33 import java.util.Arrays;
34
35 import static com.iailab.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
36
37 /**
38  * Extension of {@link HandlerMethod} that invokes the underlying method with
39  * argument values resolved from the current HTTP request through a list of
40  * {@link HandlerMethodArgumentResolver}.
41  *
42  * 针对 rabbitmq-spring 和 kafka-spring,不存在合适的拓展点,可以实现 Consumer 消费前,读取 Header 中的 tenant-id 设置到 {@link TenantContextHolder} 中
43  * TODO iailab:持续跟进,看看有没新的拓展点
44  *
45  * @author Rossen Stoyanchev
46  * @author Juergen Hoeller
47  * @since 4.0
48  */
49 public class InvocableHandlerMethod extends HandlerMethod {
50
51     private static final Object[] EMPTY_ARGS = new Object[0];
52
53     private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
54
55     private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
56
57     /**
58      * Create an instance from a {@code HandlerMethod}.
59      */
60     public InvocableHandlerMethod(HandlerMethod handlerMethod) {
61         super(handlerMethod);
62     }
63
64     /**
65      * Create an instance from a bean instance and a method.
66      */
67     public InvocableHandlerMethod(Object bean, Method method) {
68         super(bean, method);
69     }
70
71     /**
72      * Construct a new handler method with the given bean instance, method name and parameters.
73      * @param bean the object bean
74      * @param methodName the method name
75      * @param parameterTypes the method parameter types
76      * @throws NoSuchMethodException when the method cannot be found
77      */
78     public InvocableHandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
79             throws NoSuchMethodException {
80
81         super(bean, methodName, parameterTypes);
82     }
83
84     /**
85      * Set {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} to use for resolving method argument values.
86      */
87     public void setMessageMethodArgumentResolvers(HandlerMethodArgumentResolverComposite argumentResolvers) {
88         this.resolvers = argumentResolvers;
89     }
90
91     /**
92      * Set the ParameterNameDiscoverer for resolving parameter names when needed
93      * (e.g. default request attribute name).
94      * <p>Default is a {@link DefaultParameterNameDiscoverer}.
95      */
96     public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
97         this.parameterNameDiscoverer = parameterNameDiscoverer;
98     }
99
100     /**
101      * Invoke the method after resolving its argument values in the context of the given message.
102      * <p>Argument values are commonly resolved through
103      * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
104      * The {@code providedArgs} parameter however may supply argument values to be used directly,
105      * i.e. without argument resolution.
106      * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the
107      * resolved arguments.
108      * @param message the current message being processed
109      * @param providedArgs "given" arguments matched by type, not resolved
110      * @return the raw value returned by the invoked method
111      * @throws Exception raised if no suitable argument resolver can be found,
112      * or if the method raised an exception
113      * @see #getMethodArgumentValues
114      * @see #doInvoke
115      */
116     @Nullable
117     public Object invoke(Message<?> message, Object... providedArgs) throws Exception {
118         Object[] args = getMethodArgumentValues(message, providedArgs);
119         if (logger.isTraceEnabled()) {
120             logger.trace("Arguments: " + Arrays.toString(args));
121         }
122         // 注意:如下是本类的改动点!!!
123         // 情况一:无租户编号的情况
124         Long tenantId= parseTenantId(message);
125         if (tenantId == null) {
126             return doInvoke(args);
127         }
128         // 情况二:有租户的情况下
129         return TenantUtils.execute(tenantId, () -> doInvoke(args));
130     }
131
132     private Long parseTenantId(Message<?> message) {
133         Object tenantId = message.getHeaders().get(HEADER_TENANT_ID);
134         if (tenantId == null) {
135             return null;
136         }
137         if (tenantId instanceof Long) {
138             return (Long) tenantId;
139         }
140         if (tenantId instanceof Number) {
141             return ((Number) tenantId).longValue();
142         }
143         if (tenantId instanceof String) {
144             return Long.parseLong((String) tenantId);
145         }
146         if (tenantId instanceof byte[]) {
147             return Long.parseLong(new String((byte[]) tenantId));
148         }
149         throw new IllegalArgumentException("未知的数据类型:" + tenantId);
150     }
151
152     /**
153      * Get the method argument values for the current message, checking the provided
154      * argument values and falling back to the configured argument resolvers.
155      * <p>The resulting array will be passed into {@link #doInvoke}.
156      * @since 5.1.2
157      */
158     protected Object[] getMethodArgumentValues(Message<?> message, Object... providedArgs) throws Exception {
159         MethodParameter[] parameters = getMethodParameters();
160         if (ObjectUtils.isEmpty(parameters)) {
161             return EMPTY_ARGS;
162         }
163
164         Object[] args = new Object[parameters.length];
165         for (int i = 0; i < parameters.length; i++) {
166             MethodParameter parameter = parameters[i];
167             parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
168             args[i] = findProvidedArgument(parameter, providedArgs);
169             if (args[i] != null) {
170                 continue;
171             }
172             if (!this.resolvers.supportsParameter(parameter)) {
173                 throw new MethodArgumentResolutionException(
174                         message, parameter, formatArgumentError(parameter, "No suitable resolver"));
175             }
176             try {
177                 args[i] = this.resolvers.resolveArgument(parameter, message);
178             }
179             catch (Exception ex) {
180                 // Leave stack trace for later, exception may actually be resolved and handled...
181                 if (logger.isDebugEnabled()) {
182                     String exMsg = ex.getMessage();
183                     if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
184                         logger.debug(formatArgumentError(parameter, exMsg));
185                     }
186                 }
187                 throw ex;
188             }
189         }
190         return args;
191     }
192
193     /**
194      * Invoke the handler method with the given argument values.
195      */
196     @Nullable
197     protected Object doInvoke(Object... args) throws Exception {
198         try {
199             return getBridgedMethod().invoke(getBean(), args);
200         }
201         catch (IllegalArgumentException ex) {
202             assertTargetBean(getBridgedMethod(), getBean(), args);
203             String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
204             throw new IllegalStateException(formatInvokeError(text, args), ex);
205         }
206         catch (InvocationTargetException ex) {
207             // Unwrap for HandlerExceptionResolvers ...
208             Throwable targetException = ex.getTargetException();
209             if (targetException instanceof RuntimeException) {
210                 throw (RuntimeException) targetException;
211             }
212             else if (targetException instanceof Error) {
213                 throw (Error) targetException;
214             }
215             else if (targetException instanceof Exception) {
216                 throw (Exception) targetException;
217             }
218             else {
219                 throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
220             }
221         }
222     }
223
224     MethodParameter getAsyncReturnValueType(@Nullable Object returnValue) {
225         return new AsyncResultMethodParameter(returnValue);
226     }
227
228     private class AsyncResultMethodParameter extends HandlerMethodParameter {
229
230         @Nullable
231         private final Object returnValue;
232
233         private final ResolvableType returnType;
234
235         public AsyncResultMethodParameter(@Nullable Object returnValue) {
236             super(-1);
237             this.returnValue = returnValue;
238             this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric();
239         }
240
241         protected AsyncResultMethodParameter(AsyncResultMethodParameter original) {
242             super(original);
243             this.returnValue = original.returnValue;
244             this.returnType = original.returnType;
245         }
246
247         @Override
248         public Class<?> getParameterType() {
249             if (this.returnValue != null) {
250                 return this.returnValue.getClass();
251             }
252             if (!ResolvableType.NONE.equals(this.returnType)) {
253                 return this.returnType.toClass();
254             }
255             return super.getParameterType();
256         }
257
258         @Override
259         public Type getGenericParameterType() {
260             return this.returnType.getType();
261         }
262
263         @Override
264         public AsyncResultMethodParameter clone() {
265             return new AsyncResultMethodParameter(this);
266         }
267     }
268
269 }