From 7d3fcaa934ad0fefd4a7097e659caa60a9bac856 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 23 Jan 2017 17:28:18 +0100 Subject: [PATCH] Consider abstract classes with @Lookup methods as candidate components Issue: SPR-14550 --- ...athScanningCandidateComponentProvider.java | 123 ++++++++++-------- .../example/profilescan/DevComponent.java | 4 +- .../ProfileAnnotatedComponent.java | 17 +++ .../ProfileMetaAnnotatedComponent.java | 5 +- .../profilescan/SomeAbstractClass.java | 24 ++++ .../example/scannable/FooServiceImpl.java | 15 ++- .../ClassPathBeanDefinitionScannerTests.java | 47 +++++-- .../EnableAspectJAutoProxyTests.java | 9 +- 8 files changed, 164 insertions(+), 80 deletions(-) create mode 100644 spring-context/src/test/java/example/profilescan/SomeAbstractClass.java diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java index 55171cb90f1..f6aa75deff6 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -30,6 +30,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; +import org.springframework.beans.factory.annotation.Lookup; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ResourceLoaderAware; @@ -43,6 +44,7 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; @@ -294,7 +296,62 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC } } - protected Set addCandidateComponentsFromIndex(String basePackage) { + /** + * Determine if the index can be used by this instance. + * @return {@code true} if the index is available and the configuration of this + * instance is supported by it, {@code false} otherwise + * @since 5.0 + */ + protected boolean isIndexSupported() { + if (this.componentsIndex == null) { + return false; + } + for (TypeFilter includeFilter : this.includeFilters) { + if (!isIndexSupportsIncludeFilter(includeFilter)) { + return false; + } + } + return true; + } + + /** + * Determine if the specified include {@link TypeFilter} is supported by the index. + * @param filter the filter to check + * @return whether the index supports this include filter + * @since 5.0 + * @see #extractStereotype(TypeFilter) + */ + protected boolean isIndexSupportsIncludeFilter(TypeFilter filter) { + if (filter instanceof AnnotationTypeFilter) { + Class annotation = ((AnnotationTypeFilter) filter).getAnnotationType(); + return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) || + annotation.getName().startsWith("javax.")); + } + if (filter instanceof AssignableTypeFilter) { + Class target = ((AssignableTypeFilter) filter).getTargetType(); + return AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, target); + } + return false; + } + + /** + * Extract the stereotype to use for the specified compatible filter. + * @param filter the filter to handle + * @return the stereotype in the index matching this filter + * @since 5.0 + * @see #isIndexSupportsIncludeFilter(TypeFilter) + */ + protected String extractStereotype(TypeFilter filter) { + if (filter instanceof AnnotationTypeFilter) { + return ((AnnotationTypeFilter) filter).getAnnotationType().getName(); + } + if (filter instanceof AssignableTypeFilter) { + return ((AssignableTypeFilter) filter).getTargetType().getName(); + } + return null; + } + + private Set addCandidateComponentsFromIndex(String basePackage) { Set candidates = new LinkedHashSet<>(); try { Set types = new HashSet<>(); @@ -337,7 +394,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC return candidates; } - protected Set scanCandidateComponents(String basePackage) { + private Set scanCandidateComponents(String basePackage) { Set candidates = new LinkedHashSet<>(); try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + @@ -440,66 +497,18 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC /** * Determine whether the given bean definition qualifies as candidate. - *

The default implementation checks whether the class is concrete - * (i.e. not abstract and not an interface). Can be overridden in subclasses. + *

The default implementation checks whether the class is not an interface + * and not dependent on an enclosing class. + *

Can be overridden in subclasses. * @param beanDefinition the bean definition to check * @return whether the bean definition qualifies as a candidate component */ protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { - return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent()); + AnnotationMetadata metadata = beanDefinition.getMetadata(); + return (metadata.isIndependent() && (metadata.isConcrete() || + (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName())))); } - /** - * Determine if the index can be used by this instance. - * @return {@code true} if the index is available and the configuration of this - * instance is supported by it, {@code false otherwise}. - */ - protected boolean isIndexSupported() { - if (this.componentsIndex == null) { - return false; - } - for (TypeFilter includeFilter : this.includeFilters) { - if (!isIndexSupportsIncludeFilter(includeFilter)) { - return false; - } - } - return true; - } - - /** - * Determine if the specified include {@link TypeFilter} is supported by the index. - * @param filter the filter to check - * @return whether the index supports this include filter - * @see #extractStereotype(TypeFilter) - */ - protected boolean isIndexSupportsIncludeFilter(TypeFilter filter) { - if (filter instanceof AnnotationTypeFilter) { - Class annotation = ((AnnotationTypeFilter) filter).getAnnotationType(); - return (AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, annotation) - || annotation.getName().startsWith("javax.")); - } - if (filter instanceof AssignableTypeFilter) { - Class target = ((AssignableTypeFilter) filter).getTargetType(); - return AnnotationUtils.isAnnotationDeclaredLocally(Indexed.class, target); - } - return false; - } - - /** - * Extract the stereotype to use for the specified compatible filter. - * @param filter the filter to handle - * @return the stereotype in the index matching this filter - * @see #isIndexSupportsIncludeFilter(TypeFilter) - */ - protected String extractStereotype(TypeFilter filter) { - if (filter instanceof AnnotationTypeFilter) { - return ((AnnotationTypeFilter) filter).getAnnotationType().getName(); - } - if (filter instanceof AssignableTypeFilter) { - return ((AssignableTypeFilter) filter).getTargetType().getName(); - } - return null; - } /** * Clear the local metadata cache, if any, removing all cached class metadata. diff --git a/spring-context/src/test/java/example/profilescan/DevComponent.java b/spring-context/src/test/java/example/profilescan/DevComponent.java index 5126e8dd6cf..ab92554e157 100644 --- a/spring-context/src/test/java/example/profilescan/DevComponent.java +++ b/spring-context/src/test/java/example/profilescan/DevComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2017 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. @@ -30,7 +30,7 @@ import org.springframework.stereotype.Component; @Component public @interface DevComponent { - public static final String PROFILE_NAME = "dev"; + String PROFILE_NAME = "dev"; String value() default ""; diff --git a/spring-context/src/test/java/example/profilescan/ProfileAnnotatedComponent.java b/spring-context/src/test/java/example/profilescan/ProfileAnnotatedComponent.java index 860c7581b78..422da4b4c38 100644 --- a/spring-context/src/test/java/example/profilescan/ProfileAnnotatedComponent.java +++ b/spring-context/src/test/java/example/profilescan/ProfileAnnotatedComponent.java @@ -1,3 +1,19 @@ +/* + * Copyright 2002-2017 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 + * + * 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 example.profilescan; import org.springframework.context.annotation.Profile; @@ -8,6 +24,7 @@ import org.springframework.stereotype.Component; public class ProfileAnnotatedComponent { public static final String BEAN_NAME = "profileAnnotatedComponent"; + public static final String PROFILE_NAME = "test"; } diff --git a/spring-context/src/test/java/example/profilescan/ProfileMetaAnnotatedComponent.java b/spring-context/src/test/java/example/profilescan/ProfileMetaAnnotatedComponent.java index 68b9d2d639f..4784b98df3e 100644 --- a/spring-context/src/test/java/example/profilescan/ProfileMetaAnnotatedComponent.java +++ b/spring-context/src/test/java/example/profilescan/ProfileMetaAnnotatedComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2017 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. @@ -16,10 +16,9 @@ package example.profilescan; - @DevComponent(ProfileMetaAnnotatedComponent.BEAN_NAME) public class ProfileMetaAnnotatedComponent { public static final String BEAN_NAME = "profileMetaAnnotatedComponent"; -} \ No newline at end of file +} diff --git a/spring-context/src/test/java/example/profilescan/SomeAbstractClass.java b/spring-context/src/test/java/example/profilescan/SomeAbstractClass.java new file mode 100644 index 00000000000..96744e02ca0 --- /dev/null +++ b/spring-context/src/test/java/example/profilescan/SomeAbstractClass.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2017 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 + * + * 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 example.profilescan; + +import org.springframework.stereotype.Component; + +@Component +public abstract class SomeAbstractClass { + +} diff --git a/spring-context/src/test/java/example/scannable/FooServiceImpl.java b/spring-context/src/test/java/example/scannable/FooServiceImpl.java index cc15ecbdcd4..625006ee05d 100644 --- a/spring-context/src/test/java/example/scannable/FooServiceImpl.java +++ b/spring-context/src/test/java/example/scannable/FooServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -24,6 +24,7 @@ import javax.annotation.PostConstruct; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Lookup; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ConfigurableApplicationContext; @@ -42,7 +43,7 @@ import org.springframework.util.Assert; * @author Juergen Hoeller */ @Service @Lazy @DependsOn("myNamedComponent") -public class FooServiceImpl implements FooService { +public abstract class FooServiceImpl implements FooService { // Just to test ASM5's bytecode parsing of INVOKESPECIAL/STATIC on interfaces private static final Comparator COMPARATOR_BY_MESSAGE = Comparator.comparing(MessageBean::getMessage); @@ -84,11 +85,15 @@ public class FooServiceImpl implements FooService { return this.fooDao.findFoo(id); } + public String lookupFoo(int id) { + return fooDao().findFoo(id); + } + @Override public Future asyncFoo(int id) { System.out.println(Thread.currentThread().getName()); Assert.state(ServiceInvocationCounter.getThreadLocalCount() != null, "Thread-local counter not exposed"); - return new AsyncResult<>(this.fooDao.findFoo(id)); + return new AsyncResult<>(fooDao().findFoo(id)); } @Override @@ -96,4 +101,8 @@ public class FooServiceImpl implements FooService { return this.initCalled; } + + @Lookup + protected abstract FooDao fooDao(); + } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java index 62cb02d7f72..d11e2551c0d 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 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. @@ -24,6 +24,7 @@ import example.scannable.StubFooDao; import org.aspectj.lang.annotation.Aspect; import org.junit.Test; +import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; @@ -69,9 +70,11 @@ public class ClassPathBeanDefinitionScannerTests { assertTrue(context.containsBean(AnnotationConfigUtils.EVENT_LISTENER_PROCESSOR_BEAN_NAME)); assertTrue(context.containsBean(AnnotationConfigUtils.EVENT_LISTENER_FACTORY_BEAN_NAME)); context.refresh(); - FooServiceImpl service = context.getBean("fooServiceImpl", FooServiceImpl.class); + + FooServiceImpl fooService = context.getBean("fooServiceImpl", FooServiceImpl.class); assertTrue(context.getDefaultListableBeanFactory().containsSingleton("myNamedComponent")); - assertEquals("bar", service.foo(1)); + assertEquals("bar", fooService.foo(123)); + assertEquals("bar", fooService.lookupFoo(123)); assertTrue(context.isPrototype("thoreau")); } @@ -88,11 +91,13 @@ public class ClassPathBeanDefinitionScannerTests { assertTrue(context.containsBean("myNamedDao")); assertTrue(context.containsBean("otherFooDao")); context.refresh(); + assertFalse(context.getBeanFactory().containsSingleton("otherFooDao")); assertFalse(context.getBeanFactory().containsSingleton("fooServiceImpl")); - FooServiceImpl service = context.getBean("fooServiceImpl", FooServiceImpl.class); + FooServiceImpl fooService = context.getBean("fooServiceImpl", FooServiceImpl.class); assertTrue(context.getBeanFactory().containsSingleton("otherFooDao")); - assertEquals("other", service.foo(1)); + assertEquals("other", fooService.foo(123)); + assertEquals("other", fooService.lookupFoo(123)); } @Test @@ -102,6 +107,7 @@ public class ClassPathBeanDefinitionScannerTests { int beanCount = scanner.scan(BASE_PACKAGE); assertEquals(12, beanCount); scanner.scan(BASE_PACKAGE); + assertTrue(context.containsBean("serviceInvocationCounter")); assertTrue(context.containsBean("fooServiceImpl")); assertTrue(context.containsBean("stubFooDao")); @@ -117,6 +123,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.setIncludeAnnotationConfig(false); int beanCount = scanner.scan(BASE_PACKAGE); assertEquals(6, beanCount); + assertTrue(context.containsBean("serviceInvocationCounter")); assertTrue(context.containsBean("fooServiceImpl")); assertTrue(context.containsBean("stubFooDao")); @@ -159,6 +166,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setIncludeAnnotationConfig(false); int scannedBeanCount = scanner.scan(BASE_PACKAGE); + assertEquals(5, scannedBeanCount); assertEquals(initialBeanCount + scannedBeanCount, context.getBeanDefinitionCount()); assertTrue(context.containsBean("serviceInvocationCounter")); @@ -178,6 +186,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setIncludeAnnotationConfig(false); int scannedBeanCount = scanner.scan(BASE_PACKAGE); + assertEquals(5, scannedBeanCount); assertEquals(initialBeanCount + scannedBeanCount, context.getBeanDefinitionCount()); assertTrue(context.containsBean("serviceInvocationCounter")); @@ -220,6 +229,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, false); scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(7, beanCount); assertTrue(context.containsBean("messageBean")); assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)); @@ -235,6 +245,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, false); scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(7, beanCount); assertTrue(context.containsBean("messageBean")); assertFalse(context.containsBean("serviceInvocationCounter")); @@ -255,6 +266,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); scanner.addIncludeFilter(new AnnotationTypeFilter(CustomComponent.class)); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(13, beanCount); assertTrue(context.containsBean("messageBean")); assertTrue(context.containsBean("serviceInvocationCounter")); @@ -275,6 +287,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); scanner.addExcludeFilter(new AnnotationTypeFilter(Aspect.class)); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(11, beanCount); assertFalse(context.containsBean("serviceInvocationCounter")); assertTrue(context.containsBean("fooServiceImpl")); @@ -293,6 +306,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, true); scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(11, beanCount); assertFalse(context.containsBean("fooServiceImpl")); assertTrue(context.containsBean("serviceInvocationCounter")); @@ -313,6 +327,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.setIncludeAnnotationConfig(false); scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(5, beanCount); assertFalse(context.containsBean("fooServiceImpl")); assertTrue(context.containsBean("serviceInvocationCounter")); @@ -331,6 +346,7 @@ public class ClassPathBeanDefinitionScannerTests { scanner.addExcludeFilter(new AssignableTypeFilter(FooService.class)); scanner.addExcludeFilter(new AnnotationTypeFilter(Aspect.class)); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(10, beanCount); assertFalse(context.containsBean("fooServiceImpl")); assertFalse(context.containsBean("serviceInvocationCounter")); @@ -350,6 +366,7 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setBeanNameGenerator(new TestBeanNameGenerator()); int beanCount = scanner.scan(BASE_PACKAGE); + assertEquals(12, beanCount); assertFalse(context.containsBean("fooServiceImpl")); assertTrue(context.containsBean("fooService")); @@ -403,6 +420,7 @@ public class ClassPathBeanDefinitionScannerTests { MessageSource ms = (MessageSource) context.getBean("messageSource"); assertTrue(fooService.isInitCalled()); assertEquals("bar", fooService.foo(123)); + assertEquals("bar", fooService.lookupFoo(123)); assertSame(context.getDefaultListableBeanFactory(), fooService.beanFactory); assertEquals(2, fooService.listableBeanFactory.size()); assertSame(context.getDefaultListableBeanFactory(), fooService.listableBeanFactory.get(0)); @@ -426,13 +444,13 @@ public class ClassPathBeanDefinitionScannerTests { int beanCount = scanner.scan(BASE_PACKAGE); assertEquals(6, beanCount); context.refresh(); - FooService fooService = (FooService) context.getBean("fooService"); - assertFalse(fooService.isInitCalled()); + try { - fooService.foo(123); - fail("NullPointerException expected; fooDao must not have been set"); + context.getBean("fooService"); } - catch (NullPointerException expected) { + catch (BeanCreationException expected) { + assertTrue(expected.contains(BeanInstantiationException.class)); + // @Lookup method not substituted } } @@ -442,11 +460,13 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setIncludeAnnotationConfig(true); scanner.setBeanNameGenerator(new TestBeanNameGenerator()); - scanner.setAutowireCandidatePatterns(new String[] { "*FooDao" }); + scanner.setAutowireCandidatePatterns("*FooDao"); scanner.scan(BASE_PACKAGE); context.refresh(); - FooService fooService = (FooService) context.getBean("fooService"); + + FooServiceImpl fooService = (FooServiceImpl) context.getBean("fooService"); assertEquals("bar", fooService.foo(123)); + assertEquals("bar", fooService.lookupFoo(123)); } @Test @@ -455,8 +475,9 @@ public class ClassPathBeanDefinitionScannerTests { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); scanner.setIncludeAnnotationConfig(true); scanner.setBeanNameGenerator(new TestBeanNameGenerator()); - scanner.setAutowireCandidatePatterns(new String[] { "*NoSuchDao" }); + scanner.setAutowireCandidatePatterns("*NoSuchDao"); scanner.scan(BASE_PACKAGE); + try { context.refresh(); context.getBean("fooService"); diff --git a/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java b/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java index feeee8a8eea..81d4f9937c9 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -19,6 +19,7 @@ package org.springframework.context.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import example.scannable.FooDao; import example.scannable.FooService; import example.scannable.FooServiceImpl; import example.scannable.ServiceInvocationCounter; @@ -123,13 +124,17 @@ public class EnableAspectJAutoProxyTests { static class ConfigWithExposedProxy { @Bean - public FooService fooServiceImpl() { + public FooService fooServiceImpl(final ApplicationContext context) { return new FooServiceImpl() { @Override public String foo(int id) { assertNotNull(AopContext.currentProxy()); return super.foo(id); } + @Override + protected FooDao fooDao() { + return context.getBean(FooDao.class); + } }; } }