- 后端:临时解决 Dubbo 内嵌在 Spring Boot 时,对本地的 Dubbo Service 引用报错的问题。

- 前端:完善商品推荐
- 前端:完善优惠劵
This commit is contained in:
YunaiV
2019-05-07 19:33:16 +08:00
parent ab5d051f75
commit d39a416080
69 changed files with 743 additions and 202 deletions

View File

@@ -0,0 +1,268 @@
/*
* 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 org.apache.dubbo.config.spring.beans.factory.annotation;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
import org.apache.dubbo.config.spring.util.AnnotationUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
* that Consumer service {@link Reference} annotated fields
*
* @since 2.5.7
*/
public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor<Reference>
implements ApplicationContextAware, ApplicationListener {
/**
* The bean name of {@link ReferenceAnnotationBeanPostProcessor}
*/
public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";
/**
* Cache size
*/
private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);
private final ConcurrentMap<String, ReferenceBean<?>> referenceBeanCache =
new ConcurrentHashMap<String, ReferenceBean<?>>(CACHE_SIZE);
private final ConcurrentHashMap<String, ReferenceBeanInvocationHandler> localReferenceBeanInvocationHandlerCache =
new ConcurrentHashMap<String, ReferenceBeanInvocationHandler>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedFieldReferenceBeanCache =
new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedMethodReferenceBeanCache =
new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE);
private ApplicationContext applicationContext;
/**
* Gets all beans of {@link ReferenceBean}
*
* @return non-null read-only {@link Collection}
* @since 2.5.9
*/
public Collection<ReferenceBean<?>> getReferenceBeans() {
return referenceBeanCache.values();
}
/**
* Get {@link ReferenceBean} {@link Map} in injected field.
*
* @return non-null {@link Map}
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {
return Collections.unmodifiableMap(injectedFieldReferenceBeanCache);
}
/**
* Get {@link ReferenceBean} {@link Map} in injected method.
*
* @return non-null {@link Map}
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {
return Collections.unmodifiableMap(injectedMethodReferenceBeanCache);
}
@Override
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
String referencedBeanName = buildReferencedBeanName(reference, injectedType);
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
cacheInjectedReferenceBean(referenceBean, injectedElement);
Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);
return proxy;
}
private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class<?> injectedType) {
InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean);
Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler);
return proxy;
}
private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) {
ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName);
if (handler == null) {
handler = new ReferenceBeanInvocationHandler(referenceBean);
}
if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ?
// ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported.
localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler);
} else if (!applicationContext.getBeansOfType(referenceBean.getInterfaceClass()).isEmpty()) { // TODO 芋艿,临时添加,等待官方修复方案
localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler);
} else {
// Remote Reference Bean should initialize immediately
handler.init();
}
return handler;
}
private static class ReferenceBeanInvocationHandler implements InvocationHandler {
private final ReferenceBean referenceBean;
private Object bean;
private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) {
this.referenceBean = referenceBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
if (bean == null) { // If the bean is not initialized, invoke init()
// issue: https://github.com/apache/incubator-dubbo/issues/3429
init();
}
result = method.invoke(bean, args);
} catch (InvocationTargetException e) {
// re-throws the actual Exception.
throw e.getTargetException();
}
return result;
}
private void init() {
this.bean = referenceBean.get();
}
}
@Override
protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName,
Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) {
String key = buildReferencedBeanName(reference, injectedType) +
"#source=" + (injectedElement.getMember()) +
"#attributes=" + AnnotationUtils.getAttributes(reference,getEnvironment(),true);
return key;
}
private String buildReferencedBeanName(Reference reference, Class<?> injectedType) {
AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, injectedType);
builder.environment(getEnvironment());
return getEnvironment().resolvePlaceholders(builder.build());
}
private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference,
Class<?> referencedType, ClassLoader classLoader)
throws Exception {
ReferenceBean<?> referenceBean = referenceBeanCache.get(referencedBeanName);
if (referenceBean == null) {
ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
.create(reference, classLoader, applicationContext)
.interfaceClass(referencedType);
referenceBean = beanBuilder.build();
referenceBeanCache.put(referencedBeanName, referenceBean);
}
return referenceBean;
}
private void cacheInjectedReferenceBean(ReferenceBean referenceBean,
InjectionMetadata.InjectedElement injectedElement) {
if (injectedElement.getMember() instanceof Field) {
injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);
} else if (injectedElement.getMember() instanceof Method) {
injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ServiceBeanExportedEvent) {
onServiceBeanExportEvent((ServiceBeanExportedEvent) event);
} else if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
}
}
private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) {
ServiceBean serviceBean = event.getServiceBean();
initReferenceBeanInvocationHandler(serviceBean);
}
private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) {
String serviceBeanName = serviceBean.getBeanName();
// Remove ServiceBean when it's exported
ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName);
// Initialize
if (handler != null) {
handler.init();
}
}
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
}
@Override
public void destroy() throws Exception {
super.destroy();
this.referenceBeanCache.clear();
this.localReferenceBeanInvocationHandlerCache.clear();
this.injectedFieldReferenceBeanCache.clear();
this.injectedMethodReferenceBeanCache.clear();
}
}