Browse Source

@Resource injection points support @Lazy as well

Issue: SPR-12654
pull/703/merge
Juergen Hoeller 10 years ago
parent
commit
e3d1a1dda2
  1. 49
      spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java
  2. 85
      spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java

49
spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -44,6 +44,8 @@ import javax.xml.ws.Service; @@ -44,6 +44,8 @@ import javax.xml.ws.Service;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceRef;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
@ -414,6 +416,44 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean @@ -414,6 +416,44 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
return new InjectionMetadata(clazz, elements);
}
/**
* Obtain a lazily resolving resource proxy for the given name and type,
* delegating to {@link #getResource} on demand once a method call comes in.
* @param element the descriptor for the annotated field/method
* @param requestingBeanName the name of the requesting bean
* @return the resource object (never {@code null})
* @since 4.2
* @see #getResource
* @see Lazy
*/
protected Object buildLazyResourceProxy(final LookupElement element, final String requestingBeanName) {
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return element.lookupType;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public Object getTarget() {
return getResource(element, requestingBeanName);
}
@Override
public void releaseTarget(Object target) {
}
};
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
if (element.lookupType.isInterface()) {
pf.addInterface(element.lookupType);
}
ClassLoader classLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : null);
return pf.getProxy(classLoader);
}
/**
* Obtain the resource object for the given name and type.
* @param element the descriptor for the annotated field/method
@ -527,6 +567,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean @@ -527,6 +567,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
*/
private class ResourceElement extends LookupElement {
private final boolean lazyLookup;
public ResourceElement(Member member, AnnotatedElement ae, PropertyDescriptor pd) {
super(member, pd);
Resource resource = ae.getAnnotation(Resource.class);
@ -552,11 +594,14 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean @@ -552,11 +594,14 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
this.name = resourceName;
this.lookupType = resourceType;
this.mappedName = resource.mappedName();
Lazy lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
@Override
protected Object getResourceToInject(Object target, String requestingBeanName) {
return getResource(this, requestingBeanName);
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
}

85
spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -437,6 +437,60 @@ public class CommonAnnotationBeanPostProcessorTests { @@ -437,6 +437,60 @@ public class CommonAnnotationBeanPostProcessorTests {
assertTrue(bean.destroy2Called);
}
@Test
public void testLazyResolutionWithResourceField() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(LazyResourceFieldInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
LazyResourceFieldInjectionBean bean = (LazyResourceFieldInjectionBean) bf.getBean("annotatedBean");
assertFalse(bf.containsSingleton("testBean"));
bean.testBean.setName("notLazyAnymore");
assertTrue(bf.containsSingleton("testBean"));
TestBean tb = (TestBean) bf.getBean("testBean");
assertEquals("notLazyAnymore", tb.getName());
}
@Test
public void testLazyResolutionWithResourceMethod() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(LazyResourceMethodInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
LazyResourceMethodInjectionBean bean = (LazyResourceMethodInjectionBean) bf.getBean("annotatedBean");
assertFalse(bf.containsSingleton("testBean"));
bean.testBean.setName("notLazyAnymore");
assertTrue(bf.containsSingleton("testBean"));
TestBean tb = (TestBean) bf.getBean("testBean");
assertEquals("notLazyAnymore", tb.getName());
}
@Test
public void testLazyResolutionWithCglibProxy() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
CommonAnnotationBeanPostProcessor bpp = new CommonAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(LazyResourceCglibInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
LazyResourceCglibInjectionBean bean = (LazyResourceCglibInjectionBean) bf.getBean("annotatedBean");
assertFalse(bf.containsSingleton("testBean"));
bean.testBean.setName("notLazyAnymore");
assertTrue(bf.containsSingleton("testBean"));
TestBean tb = (TestBean) bf.getBean("testBean");
assertEquals("notLazyAnymore", tb.getName());
}
public static class AnnotatedInitDestroyBean {
@ -716,6 +770,35 @@ public class CommonAnnotationBeanPostProcessorTests { @@ -716,6 +770,35 @@ public class CommonAnnotationBeanPostProcessorTests {
}
private static class LazyResourceFieldInjectionBean {
@Resource @Lazy
private ITestBean testBean;
}
private static class LazyResourceMethodInjectionBean {
private ITestBean testBean;
@Resource @Lazy
public void setTestBean(ITestBean testBean) {
this.testBean = testBean;
}
}
private static class LazyResourceCglibInjectionBean {
private TestBean testBean;
@Resource @Lazy
public void setTestBean(TestBean testBean) {
this.testBean = testBean;
}
}
@SuppressWarnings("unused")
private static class NullFactory {

Loading…
Cancel
Save