All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alipay.sofa.serverless.common.service.SpringServiceInvoker Maven / Gradle / Ivy

There is a newer version: 0.5.6
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alipay.sofa.serverless.common.service;

import com.alipay.sofa.ark.api.ArkClient;
import com.alipay.sofa.ark.spi.model.Biz;
import com.alipay.sofa.ark.spi.model.BizState;
import com.alipay.sofa.serverless.common.exception.BizRuntimeException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static com.alipay.sofa.serverless.common.exception.ErrorCodes.SpringContextManager.E100003;
import static com.alipay.sofa.serverless.common.exception.ErrorCodes.SpringContextManager.E100004;
import static com.alipay.sofa.serverless.common.util.SerializeUtils.serializeTransform;

/**
 * @author: yuanyuan
 * @date: 2023/9/21 9:57 下午
 */
public class SpringServiceInvoker implements MethodInterceptor {

    private static final Logger LOGGER          = LoggerFactory
                                                    .getLogger(SpringServiceInvoker.class);

    private static final String TOSTRING_METHOD = "toString";
    private static final String EQUALS_METHOD   = "equals";
    private static final String HASHCODE_METHOD = "hashCode";

    private Object              target;                                                    // target 跨上下文寻址

    private String              bizName;

    private String              bizVersion;

    private String              bizIdentity;

    private ClassLoader         clientClassLoader;

    private ClassLoader         serviceClassLoader;

    public SpringServiceInvoker() {
    }

    public SpringServiceInvoker(Object target, String bizName, String bizVersion,
                                String bizIdentity, ClassLoader clientClassLoader,
                                ClassLoader serviceClassLoader) {
        this.target = target;
        this.bizName = bizName;
        this.bizVersion = bizVersion;
        this.bizIdentity = bizIdentity;
        this.clientClassLoader = clientClassLoader;
        this.serviceClassLoader = serviceClassLoader;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Biz biz = ArkClient.getBizManagerService().getBiz(bizName, bizVersion);
        if (biz == null) {
            throw new BizRuntimeException(E100003, "biz does not exist when called");
        }
        if (BizState.ACTIVATED != biz.getBizState() && BizState.DEACTIVATED != biz.getBizState()) {
            throw new BizRuntimeException(E100004, "biz state is not valid");
        }

        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
        long startTime = System.currentTimeMillis();
        try {
            Thread.currentThread().setContextClassLoader(serviceClassLoader);
            return doInvoke(invocation);
        } catch (Throwable e) {
            doCatch(invocation, e, startTime);
            throw e;
        } finally {
            doFinally(invocation, startTime);
            Thread.currentThread().setContextClassLoader(oldClassLoader);
        }
    }

    protected Object doInvoke(MethodInvocation invocation) throws InvocationTargetException,
                                                          IllegalAccessException {
        if (isCrossClassLoader(invocation)) {
            return invokeServiceCrossClassLoader(invocation);
        }
        return invokeService(invocation);
    }

    protected void doCatch(MethodInvocation invocation, Throwable e, long startTime) {
        // log
    }

    protected void doFinally(MethodInvocation invocation, long startTime) {
        // log、metrics
    }

    private boolean isCrossClassLoader(MethodInvocation invocation) {
        return target.getClass().getClassLoader() != invocation.getMethod().getDeclaringClass()
            .getClassLoader();
    }

    private Object invokeServiceCrossClassLoader(MethodInvocation invocation)
                                                                             throws InvocationTargetException,
                                                                             IllegalAccessException {
        Method clientMethod = invocation.getMethod();
        Object[] clientMethodArguments = invocation.getArguments();
        Class[] clientMethodArgumentTypes = clientMethod.getParameterTypes();

        if (TOSTRING_METHOD.equalsIgnoreCase(clientMethod.getName())
            && clientMethodArgumentTypes.length == 0) {
            return target.toString();
        } else if (EQUALS_METHOD.equalsIgnoreCase(clientMethod.getName())
                   && clientMethodArgumentTypes.length == 1) {
            return target.equals(clientMethodArguments[0]);
        } else if (HASHCODE_METHOD.equalsIgnoreCase(clientMethod.getName())
                   && clientMethodArgumentTypes.length == 0) {
            return target.hashCode();
        }

        Object[] serviceMethodArguments = (Object[]) serializeTransform(clientMethodArguments,
            serviceClassLoader);
        Class[] serviceMethodArgumentTypes = (Class[]) serializeTransform(
            clientMethodArgumentTypes, serviceClassLoader);
        Method serviceMethod = getTargetMethod(clientMethod, serviceMethodArgumentTypes);
        Object retVal = serviceMethod.invoke(target, serviceMethodArguments);
        return serializeTransform(retVal, clientClassLoader);
    }

    private Object invokeService(MethodInvocation invocation) throws InvocationTargetException,
                                                             IllegalAccessException {
        return invocation.getMethod().invoke(target, invocation.getArguments());
    }

    private Method getTargetMethod(Method method, Class[] argumentTypes) {
        try {
            return target.getClass().getMethod(method.getName(), argumentTypes);
        } catch (NoSuchMethodException ex) {
            throw new IllegalStateException(target + " in " + bizIdentity
                                            + " don't have the method " + method);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy