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

top.osjf.sdk.spring.proxy.AbstractSdkProxyBean Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright 2024-? the original author or authors.
 *
 * Licensed 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
 *
 *      https://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 top.osjf.sdk.spring.proxy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.NonNull;
import org.springframework.web.context.WebApplicationContext;
import top.osjf.sdk.core.client.ClientExecutors;
import top.osjf.sdk.core.process.*;
import top.osjf.sdk.core.util.StringUtils;
import top.osjf.sdk.http.HttpSdkSupport;
import top.osjf.sdk.spring.beans.DeterminantDisposableBean;
import top.osjf.sdk.spring.beans.DeterminantInitializingBean;
import top.osjf.sdk.spring.beans.HandlerPostProcessor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * Inheriting {@link HierarchicalProxySupport} implements handing over
 * the object of the jdk dynamic proxy to the spring container for management.
 *
 * 

When this object is called, the {@link #invoke(Object, Method, Object[])} * method will be executed and passed to this abstract class. * *

This class takes on the common parameter processing and converts * it into the parameters required for SDK execution. * *

The corresponding executor will be selected based on the full name * of a single {@link top.osjf.sdk.core.client.Client}, * as shown in {@link Request#getClientCls()}. * *

Simply obtain the host parameter from the corresponding proxy class * entity to complete the SDK request. * * @param The data type of the proxy class. * @author zhangpengfei * @since 1.0.0 */ public abstract class AbstractSdkProxyBean extends HierarchicalProxySupport implements RequestAttributes, ApplicationContextAware, InitializingBean, DisposableBean { /*** SLF4J logs.*/ private final Logger log = LoggerFactory.getLogger(getClass()); /*** Spring container context object.*/ private ApplicationContext applicationContext; /*** The host address when calling SDK.*/ private String host; /*** Customized modifiers for the results of proxy processing.*/ private final List postProcessors = new ArrayList<>(); /*** Custom specified current type in proxy class destruction logic..*/ private final List disposableBeans = new ArrayList<>(); /*** The return value {@link #toString()} needs to be formatted.*/ private static final String TO_STR_FORMAT = "Proxy info ( target type [%s] | proxy type [%s] | host [%s] | proxy model [%s] )"; /** * When defining a special scope bean, such as {@link WebApplicationContext#SCOPE_REQUEST} * {@link WebApplicationContext#SCOPE_APPLICATION} {@link WebApplicationContext#SCOPE_SESSION}, * call this constructor to pass the type in advance. * * @param type When injecting beans, the type of teammates is required. * {@link FactoryBean#getObjectType()}. */ public AbstractSdkProxyBean(Class type) { super(type); } @Override public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void setHost(String host) { if (StringUtils.isBlank(host)) { throw new IllegalArgumentException("SDK access host address cannot be empty!"); } this.host = host; } @Override public String getHost() { return host; } @Override public void afterPropertiesSet() throws Exception { //Collect request post processors. getBeansOfType(HandlerPostProcessor.class, h -> h.appointTarget() != null && getType().isAssignableFrom(h.appointTarget()), postProcessors::add); //Collect the destruction logic collection of proxy beans of the specified type. getBeansOfType(DeterminantDisposableBean.class, d -> getType().isAssignableFrom(d.getType()), disposableBeans::add); //Collect the initialization logic collection of proxy beans of the specified type and execute it. for (DeterminantInitializingBean initializingBean : getBeansOfType(DeterminantInitializingBean.class, d -> getType().isAssignableFrom(d.getType()), null)) { initializingBean.afterPropertiesSet(); } } /** * Retrieve the bean collection from the Spring container according to the * specified type and determine if it meets the criteria. After sorting, * it can be executed concurrently. * * @param requiredType Find the type of bean. * @param assignableCondition Filter conditions. * @param exec Execute the consumption function. * @param Generic types. * @return The filtered collection of type entities. */ List getBeansOfType(Class requiredType, Predicate assignableCondition, Consumer exec) { List beans = new ArrayList<>(); try { for (R bean : applicationContext.getBeansOfType(requiredType).values()) { if (assignableCondition.test(bean)) { beans.add(bean); } } } catch (BeansException ignored) { if (log.isWarnEnabled()) { log.warn("No bean collection of type {} was found from the Spring container.", requiredType.getName()); } // ...Ignoring undefined issues } AnnotationAwareOrderComparator.sort(beans); if (exec != null) beans.forEach(exec); return beans; } @Override public Object handle(Object proxy, Method method, Object[] args) { return handle0(proxy, method, args); } @Override public void destroy() throws Exception { for (DeterminantDisposableBean disposableBean : disposableBeans) { disposableBean.destroy(); } } /** * The parameter processing logic for Jdk dynamic proxy callbacks can be * rewritten by subclasses, defined according to their own situation. *

Here, a default processing posture that conforms to SDK is provided. * *

Support for {@link RequestParameter} and {@link RequestParam} and * {@link ResponseData} has been added. * * @param proxy Proxy object. * @param method The method object executed by the proxy class. * @param args The real parameters executed by the proxy method. * @return The result returned by the proxy execution method. */ private Object handle0(@SuppressWarnings("unused") Object proxy, Method method, Object[] args) { //Supports toString and returns proxy metadata. if ("toString".equals(method.getName())) return toString(); /* * if (!checkMethodCoverRanger(proxy, getType(), method, args)) * throw new UnsupportedSDKCallBackMethodException(method.getName()); */ //Get target type. Class targetType = getType(); //Create a request class based on the extension. Request request = HttpSdkSupport.invokeCreateRequest(method, args); //Dynamically customize request parameters. for (HandlerPostProcessor postProcessor : postProcessors) { request = postProcessor.postProcessRequestBeforeHandle(request, targetType, method, args); } //Execute the request. Object result = HttpSdkSupport.getResponse(method, doRequest(request)); //Dynamic customization of request response results. for (HandlerPostProcessor postProcessor : postProcessors) { result = postProcessor.postProcessResultAfterHandle(result, targetType, method, args); } return result; } /** * Return relevant information about this agent. * * @return relevant information about this agent. * @see #TO_STR_FORMAT */ @Override public String toString() { return String.format(TO_STR_FORMAT, getType().getName(), getClass().getName(), getHost(), getProxyModel().name()); } /** * Use {@link top.osjf.sdk.core.client.Client} for the * next name routing operation. * * @param request Think of {@link Request#getClientCls()}. * @return The result set of this request is encapsulated in {@link Response}. */ private Response doRequest(@NonNull Request request) { //private perm //change protected //son class can use return ClientExecutors.executeRequestClient(this::getHost, request); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy