/* | |
* 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.alibaba.dubbo.config.spring; | |
import com.alibaba.dubbo.config.ApplicationConfig; | |
import com.alibaba.dubbo.config.ModuleConfig; | |
import com.alibaba.dubbo.config.MonitorConfig; | |
import com.alibaba.dubbo.config.ProtocolConfig; | |
import com.alibaba.dubbo.config.ProviderConfig; | |
import com.alibaba.dubbo.config.RegistryConfig; | |
import com.alibaba.dubbo.config.ServiceConfig; | |
import com.alibaba.dubbo.config.annotation.Service; | |
import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory; | |
import org.springframework.aop.support.AopUtils; | |
import org.springframework.beans.factory.BeanFactoryUtils; | |
import org.springframework.beans.factory.BeanNameAware; | |
import org.springframework.beans.factory.DisposableBean; | |
import org.springframework.beans.factory.InitializingBean; | |
import org.springframework.context.ApplicationContext; | |
import org.springframework.context.ApplicationContextAware; | |
import org.springframework.context.ApplicationListener; | |
import org.springframework.context.event.ContextRefreshedEvent; | |
import org.springframework.context.support.AbstractApplicationContext; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* ServiceFactoryBean | |
* | |
* @export | |
*/ | |
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware { | |
private static final long serialVersionUID = 213195494150089726L; | |
private static transient ApplicationContext SPRING_CONTEXT; | |
private final transient Service service; | |
private transient ApplicationContext applicationContext; | |
private transient String beanName; | |
private transient boolean supportedApplicationListener; | |
public ServiceBean() { | |
super(); | |
this.service = null; | |
} | |
public ServiceBean(Service service) { | |
super(service); | |
this.service = service; | |
} | |
public static ApplicationContext getSpringContext() { | |
return SPRING_CONTEXT; | |
} | |
@Override | |
public void setApplicationContext(ApplicationContext applicationContext) { | |
this.applicationContext = applicationContext; | |
SpringExtensionFactory.addApplicationContext(applicationContext); | |
if (applicationContext != null) { | |
SPRING_CONTEXT = applicationContext; | |
try { | |
Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); // backward compatibility to spring 2.0.1 | |
method.invoke(applicationContext, new Object[]{this}); | |
supportedApplicationListener = true; | |
} catch (Throwable t) { | |
if (applicationContext instanceof AbstractApplicationContext) { | |
try { | |
Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); // backward compatibility to spring 2.0.1 | |
if (!method.isAccessible()) { | |
method.setAccessible(true); | |
} | |
method.invoke(applicationContext, new Object[]{this}); | |
supportedApplicationListener = true; | |
} catch (Throwable t2) { | |
} | |
} | |
} | |
} | |
} | |
@Override | |
public void setBeanName(String name) { | |
this.beanName = name; | |
} | |
/** | |
* Gets associated {@link Service} | |
* | |
* @return associated {@link Service} | |
*/ | |
public Service getService() { | |
return service; | |
} | |
@Override | |
public void onApplicationEvent(ContextRefreshedEvent event) { | |
if (isDelay() && !isExported() && !isUnexported()) { | |
if (logger.isInfoEnabled()) { | |
logger.info("The service ready on spring started. service: " + getInterface()); | |
} | |
export(); | |
} | |
} | |
private boolean isDelay() { | |
Integer delay = getDelay(); | |
ProviderConfig provider = getProvider(); | |
if (delay == null && provider != null) { | |
delay = provider.getDelay(); | |
} | |
return supportedApplicationListener && (delay == null || delay == -1); | |
} | |
@Override | |
@SuppressWarnings({"unchecked", "deprecation"}) | |
public void afterPropertiesSet() throws Exception { | |
if (getProvider() == null) { | |
Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false); | |
if (providerConfigMap != null && providerConfigMap.size() > 0) { | |
Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); | |
if ((protocolConfigMap == null || protocolConfigMap.size() == 0) | |
&& providerConfigMap.size() > 1) { // backward compatibility | |
List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>(); | |
for (ProviderConfig config : providerConfigMap.values()) { | |
if (config.isDefault() != null && config.isDefault().booleanValue()) { | |
providerConfigs.add(config); | |
} | |
} | |
if (!providerConfigs.isEmpty()) { | |
setProviders(providerConfigs); | |
} | |
} else { | |
ProviderConfig providerConfig = null; | |
for (ProviderConfig config : providerConfigMap.values()) { | |
if (config.isDefault() == null || config.isDefault().booleanValue()) { | |
if (providerConfig != null) { | |
throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config); | |
} | |
providerConfig = config; | |
} | |
} | |
if (providerConfig != null) { | |
setProvider(providerConfig); | |
} | |
} | |
} | |
} | |
if (getApplication() == null | |
&& (getProvider() == null || getProvider().getApplication() == null)) { | |
Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false); | |
if (applicationConfigMap != null && applicationConfigMap.size() > 0) { | |
ApplicationConfig applicationConfig = null; | |
for (ApplicationConfig config : applicationConfigMap.values()) { | |
if (config.isDefault() == null || config.isDefault().booleanValue()) { | |
if (applicationConfig != null) { | |
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); | |
} | |
applicationConfig = config; | |
} | |
} | |
if (applicationConfig != null) { | |
setApplication(applicationConfig); | |
} | |
} | |
} | |
if (getModule() == null | |
&& (getProvider() == null || getProvider().getModule() == null)) { | |
Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false); | |
if (moduleConfigMap != null && moduleConfigMap.size() > 0) { | |
ModuleConfig moduleConfig = null; | |
for (ModuleConfig config : moduleConfigMap.values()) { | |
if (config.isDefault() == null || config.isDefault().booleanValue()) { | |
if (moduleConfig != null) { | |
throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config); | |
} | |
moduleConfig = config; | |
} | |
} | |
if (moduleConfig != null) { | |
setModule(moduleConfig); | |
} | |
} | |
} | |
if ((getRegistries() == null || getRegistries().isEmpty()) | |
&& (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty()) | |
&& (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) { | |
Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); | |
if (registryConfigMap != null && registryConfigMap.size() > 0) { | |
List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>(); | |
for (RegistryConfig config : registryConfigMap.values()) { | |
if (config.isDefault() == null || config.isDefault().booleanValue()) { | |
registryConfigs.add(config); | |
} | |
} | |
if (registryConfigs != null && !registryConfigs.isEmpty()) { | |
super.setRegistries(registryConfigs); | |
} | |
} | |
} | |
if (getMonitor() == null | |
&& (getProvider() == null || getProvider().getMonitor() == null) | |
&& (getApplication() == null || getApplication().getMonitor() == null)) { | |
Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false); | |
if (monitorConfigMap != null && monitorConfigMap.size() > 0) { | |
MonitorConfig monitorConfig = null; | |
for (MonitorConfig config : monitorConfigMap.values()) { | |
if (config.isDefault() == null || config.isDefault().booleanValue()) { | |
if (monitorConfig != null) { | |
throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config); | |
} | |
monitorConfig = config; | |
} | |
} | |
if (monitorConfig != null) { | |
setMonitor(monitorConfig); | |
} | |
} | |
} | |
if ((getProtocols() == null || getProtocols().isEmpty()) | |
&& (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) { | |
Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); | |
if (protocolConfigMap != null && protocolConfigMap.size() > 0) { | |
List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>(); | |
for (ProtocolConfig config : protocolConfigMap.values()) { | |
if (config.isDefault() == null || config.isDefault().booleanValue()) { | |
protocolConfigs.add(config); | |
} | |
} | |
if (protocolConfigs != null && !protocolConfigs.isEmpty()) { | |
super.setProtocols(protocolConfigs); | |
} | |
} | |
} | |
if (getPath() == null || getPath().length() == 0) { | |
if (beanName != null && beanName.length() > 0 | |
&& getInterface() != null && getInterface().length() > 0 | |
&& beanName.startsWith(getInterface())) { | |
setPath(beanName); | |
} | |
} | |
if (!isDelay()) { | |
export(); | |
} | |
} | |
@Override | |
public void destroy() throws Exception { | |
// This will only be called for singleton scope bean, and expected to be called by spring shutdown hook when BeanFactory/ApplicationContext destroys. | |
// We will guarantee dubbo related resources being released with dubbo shutdown hook. | |
//unexport(); | |
} | |
// merged from dubbox | |
@Override | |
protected Class getServiceClass(T ref) { | |
if (AopUtils.isAopProxy(ref)) { | |
return AopUtils.getTargetClass(ref); | |
} | |
return super.getServiceClass(ref); | |
} | |
} |