Skip to content

Commit

Permalink
Fixed incubator-dubbo-spring-boot-project#243
Browse files Browse the repository at this point in the history
  • Loading branch information
taogu.mxx committed Aug 13, 2018
1 parent 185545e commit 3f99fe1
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

Expand All @@ -48,33 +50,35 @@ public class ReferenceAnnotationBeanPostProcessor extends CustomizedAnnotationBe
*/
public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";

private ApplicationContext applicationContext;
/**
* Cache size
*/
private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);

private final List<ReferenceBean<?>> referenceBeans = new LinkedList<ReferenceBean<?>>();
private final ConcurrentMap<String, ReferenceBean<?>> referenceBeanCache =
new ConcurrentHashMap<String, ReferenceBean<?>>(CACHE_SIZE);

private final List<ReferenceBeanInvocationHandler> referenceBeanInvocationHandlers =
new LinkedList<ReferenceBeanInvocationHandler>();
private final ConcurrentHashMap<String, Object> proxyCache = new ConcurrentHashMap<String, Object>(CACHE_SIZE);

private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedFieldReferenceBeanMap =
new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>();
private final ConcurrentHashMap<String, ReferenceBeanInvocationHandler> referenceBeanInvocationHandlerCache =
new ConcurrentHashMap<String, ReferenceBeanInvocationHandler>(CACHE_SIZE);

private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedMethodReferenceBeanMap =
new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>();
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);

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private ApplicationContext applicationContext;

/**
* Gets all beans of {@link ReferenceBean}
*
* @return non-null {@link Collection}
* @return non-null read-only {@link Collection}
* @since 2.5.9
*/
public Collection<ReferenceBean<?>> getReferenceBeans() {
return Collections.unmodifiableCollection(referenceBeans);
return referenceBeanCache.values();
}

private static String resolveInterfaceName(Reference reference, Class<?> beanClass)
Expand Down Expand Up @@ -105,7 +109,7 @@ private static String resolveInterfaceName(Reference reference, Class<?> beanCla
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedFieldReferenceBeanMap() {
return Collections.unmodifiableMap(injectedFieldReferenceBeanMap);
return Collections.unmodifiableMap(injectedFieldReferenceBeanCache);
}

/**
Expand All @@ -115,87 +119,146 @@ public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedField
* @since 2.5.11
*/
public Map<InjectionMetadata.InjectedElement, ReferenceBean<?>> getInjectedMethodReferenceBeanMap() {
return Collections.unmodifiableMap(injectedMethodReferenceBeanMap);
return Collections.unmodifiableMap(injectedMethodReferenceBeanCache);
}

@Override
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {

ReferenceBean referenceBean = buildReferenceBean(reference, injectedType, getClassLoader(), injectedElement);
String referenceBeanCacheKey = buildReferenceBeanCacheKey(reference, injectedType);

ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanCacheKey, reference, injectedType, getClassLoader());

InvocationHandler handler = buildReferenceBeanInvocationHandler(referenceBean);
cacheInjectedReferenceBean(referenceBean, injectedElement);

Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler);
Object proxy = buildProxyIfAbsent(referenceBeanCacheKey, referenceBean, injectedType);

return proxy;
}

private InvocationHandler buildReferenceBeanInvocationHandler(ReferenceBean referenceBean) {
ReferenceBeanInvocationHandler handler = new ReferenceBeanInvocationHandler(referenceBean);
referenceBeanInvocationHandlers.add(handler);
private Object buildProxyIfAbsent(String referenceBeanCacheKey, ReferenceBean referenceBean, Class<?> injectedType) {

Object proxy = proxyCache.get(referenceBeanCacheKey);

if (proxy == null) {
InvocationHandler handler = buildInvocationHandlerIfAbsent(referenceBeanCacheKey, referenceBean);
proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler);
proxyCache.put(referenceBeanCacheKey, proxy);
}

return proxy;
}

private InvocationHandler buildInvocationHandlerIfAbsent(String referenceBeanCacheKey, ReferenceBean referenceBean) {

ReferenceBeanInvocationHandler handler = referenceBeanInvocationHandlerCache.get(referenceBeanCacheKey);

if (handler == null) {
handler = new ReferenceBeanInvocationHandler(referenceBean);
referenceBeanInvocationHandlerCache.put(referenceBeanCacheKey, handler);
}

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 bean = referenceBean.get();
return method.invoke(bean, args);
}

private void init() {
this.bean = referenceBean.get();
}
}

@Override
protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, Class<?> injectedType) {
protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName,
Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) {

String key = buildReferenceBeanCacheKey(reference, injectedType) +
"?source=" + (injectedElement.getMember());

return key;
}

private String buildReferenceBeanCacheKey(Reference reference, Class<?> injectedType) {

String interfaceName = resolveInterfaceName(reference, injectedType);

String key = reference.url() + "/" + interfaceName +
String key = reference.url() +
"/" + interfaceName +
"/" + reference.version() +
"/" + reference.group();

key = getEnvironment().resolvePlaceholders(key);

return key;
return getEnvironment().resolvePlaceholders(key);
}

private ReferenceBean buildReferenceBean(Reference reference, Class<?> referencedType,
ClassLoader classLoader, InjectionMetadata.InjectedElement injectedElement) throws Exception {
private ReferenceBean buildReferenceBeanIfAbsent(String referenceBeanCacheKey, Reference reference,
Class<?> referencedType, ClassLoader classLoader)
throws Exception {

ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
.create(reference, classLoader, applicationContext)
.interfaceClass(referencedType);
ReferenceBean<?> referenceBean = referenceBeanCache.get(referenceBeanCacheKey);

ReferenceBean<?> referenceBean = beanBuilder.build();
if (referenceBean == null) {
ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
.create(reference, classLoader, applicationContext)
.interfaceClass(referencedType);
referenceBean = beanBuilder.build();
referenceBeanCache.put(referenceBeanCacheKey, referenceBean);
}

referenceBeans.add(referenceBean);
return referenceBean;
}

private void cacheInjectedReferenceBean(ReferenceBean referenceBean,
InjectionMetadata.InjectedElement injectedElement) {
if (injectedElement.getMember() instanceof Field) {
injectedFieldReferenceBeanMap.put(injectedElement, referenceBean);
injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);
} else if (injectedElement.getMember() instanceof Method) {
injectedMethodReferenceBeanMap.put(injectedElement, referenceBean);
injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);
}

return referenceBean;

}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {

if (referenceBeanInvocationHandlers.isEmpty()) {
if (proxyCache.isEmpty() || referenceBeanCache.isEmpty() || referenceBeanInvocationHandlerCache.isEmpty()) {
return;
}

// clear all
referenceBeanInvocationHandlers.clear();
// initialize all
for (ReferenceBeanInvocationHandler handler : referenceBeanInvocationHandlerCache.values()) {
handler.init();
}

// clear Proxies and Handlers
this.proxyCache.clear();
this.referenceBeanInvocationHandlerCache.clear();
}

@Override
public void destroy() throws Exception {
super.destroy();
this.proxyCache.clear();
this.referenceBeanCache.clear();
this.referenceBeanInvocationHandlerCache.clear();
this.injectedFieldReferenceBeanCache.clear();
this.injectedMethodReferenceBeanCache.clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@
*/
package com.alibaba.dubbo.config.spring.beans.factory.annotation;

import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.config.spring.api.DemoService;
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.context.ApplicationContext;
Expand All @@ -37,9 +32,7 @@
import java.util.Map;

import static com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.BEAN_NAME;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;

/**
Expand All @@ -57,7 +50,7 @@ public static void prepare() {
System.setProperty("package1", "com.alibaba.dubbo.config.spring.annotation.provider");
System.setProperty("packagesToScan", "${package1}");
System.setProperty("consumer.version", "1.2");
System.setProperty("consumer.url", "dubbo://" + NetUtils.getLocalHost() + ":12345");
System.setProperty("consumer.url", "dubbo://127.0.0.1:12345");
}

@Before
Expand All @@ -79,15 +72,14 @@ public void test() throws Exception {

TestBean testBean = context.getBean(TestBean.class);

DemoService demoService = testBean.getDemoService();

Assert.assertEquals("annotation:Mercy", demoService.sayName("Mercy"));

Assert.assertNotNull(testBean.getDemoServiceFromAncestor());
Assert.assertNotNull(testBean.getDemoServiceFromParent());
Assert.assertNotNull(testBean.getDemoService());

Assert.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent());
Assert.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent());

DemoService demoService = testBean.getDemoService();

Assert.assertEquals("annotation:Mercy", demoService.sayName("Mercy"));

context.close();
Expand All @@ -113,9 +105,7 @@ public void testGetReferenceBeans() {

TestBean testBean = context.getBean(TestBean.class);

Assert.assertEquals(referenceBean.get(), testBean.getDemoServiceFromAncestor());
Assert.assertEquals(referenceBean.get(), testBean.getDemoServiceFromParent());
Assert.assertEquals(referenceBean.get(), testBean.getDemoService());
Assert.assertNotNull(referenceBean.get());

}

Expand Down Expand Up @@ -143,7 +133,7 @@ public void testGetInjectedFieldReferenceBeanMap() {
ReferenceBean<?> referenceBean = entry.getValue();

Assert.assertEquals("1.2", referenceBean.getVersion());
Assert.assertEquals("dubbo://" + NetUtils.getLocalHost() + ":12345", referenceBean.getUrl());
Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl());

}

Expand All @@ -167,7 +157,7 @@ public void testGetInjectedMethodReferenceBeanMap() {

InjectionMetadata.InjectedElement injectedElement = entry.getKey();

Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor$AnnotatedMethodlement",
Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.CustomizedAnnotationBeanPostProcessor$AnnotatedMethodElement",
injectedElement.getClass().getName());

ReferenceBean<?> referenceBean = entry.getValue();
Expand Down

0 comments on commit 3f99fe1

Please sign in to comment.