Skip to content

Commit 263244f

Browse files
committed
Avoid expensive isReadable() check during classpath scan
Closes gh-27541 See gh-21372
1 parent 3a166ea commit 263244f

File tree

4 files changed

+43
-35
lines changed

4 files changed

+43
-35
lines changed

spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,12 @@
1616

1717
package org.springframework.context.annotation;
1818

19+
import java.io.FileNotFoundException;
1920
import java.io.IOException;
2021
import java.lang.annotation.Annotation;
22+
import java.util.ArrayList;
2123
import java.util.HashSet;
2224
import java.util.LinkedHashSet;
23-
import java.util.LinkedList;
2425
import java.util.List;
2526
import java.util.Set;
2627

@@ -93,9 +94,9 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
9394

9495
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
9596

96-
private final List<TypeFilter> includeFilters = new LinkedList<>();
97+
private final List<TypeFilter> includeFilters = new ArrayList<>();
9798

98-
private final List<TypeFilter> excludeFilters = new LinkedList<>();
99+
private final List<TypeFilter> excludeFilters = new ArrayList<>();
99100

100101
@Nullable
101102
private Environment environment;
@@ -424,40 +425,38 @@ private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
424425
if (traceEnabled) {
425426
logger.trace("Scanning " + resource);
426427
}
427-
if (resource.isReadable()) {
428-
try {
429-
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
430-
if (isCandidateComponent(metadataReader)) {
431-
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
432-
sbd.setSource(resource);
433-
if (isCandidateComponent(sbd)) {
434-
if (debugEnabled) {
435-
logger.debug("Identified candidate component class: " + resource);
436-
}
437-
candidates.add(sbd);
438-
}
439-
else {
440-
if (debugEnabled) {
441-
logger.debug("Ignored because not a concrete top-level class: " + resource);
442-
}
428+
try {
429+
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
430+
if (isCandidateComponent(metadataReader)) {
431+
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
432+
sbd.setSource(resource);
433+
if (isCandidateComponent(sbd)) {
434+
if (debugEnabled) {
435+
logger.debug("Identified candidate component class: " + resource);
443436
}
437+
candidates.add(sbd);
444438
}
445439
else {
446-
if (traceEnabled) {
447-
logger.trace("Ignored because not matching any filter: " + resource);
440+
if (debugEnabled) {
441+
logger.debug("Ignored because not a concrete top-level class: " + resource);
448442
}
449443
}
450444
}
451-
catch (Throwable ex) {
452-
throw new BeanDefinitionStoreException(
453-
"Failed to read candidate component class: " + resource, ex);
445+
else {
446+
if (traceEnabled) {
447+
logger.trace("Ignored because not matching any filter: " + resource);
448+
}
454449
}
455450
}
456-
else {
451+
catch (FileNotFoundException ex) {
457452
if (traceEnabled) {
458-
logger.trace("Ignored because not readable: " + resource);
453+
logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
459454
}
460455
}
456+
catch (Throwable ex) {
457+
throw new BeanDefinitionStoreException(
458+
"Failed to read candidate component class: " + resource, ex);
459+
}
461460
}
462461
}
463462
catch (IOException ex) {

spring-core/src/main/java/org/springframework/core/io/InputStreamSource.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -48,8 +48,9 @@ public interface InputStreamSource {
4848
* creating mail attachments. For such a use case, it is <i>required</i>
4949
* that each {@code getInputStream()} call returns a fresh stream.
5050
* @return the input stream for the underlying resource (must not be {@code null})
51-
* @throws java.io.FileNotFoundException if the underlying resource doesn't exist
51+
* @throws java.io.FileNotFoundException if the underlying resource does not exist
5252
* @throws IOException if the content stream could not be opened
53+
* @see Resource#isReadable()
5354
*/
5455
InputStream getInputStream() throws IOException;
5556

spring-orm/src/main/java/org/springframework/orm/hibernate5/LocalSessionFactoryBuilder.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.orm.hibernate5;
1818

19+
import java.io.FileNotFoundException;
1920
import java.io.IOException;
2021
import java.lang.reflect.InvocationHandler;
2122
import java.lang.reflect.InvocationTargetException;
@@ -349,7 +350,7 @@ public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws
349350
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
350351
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
351352
for (Resource resource : resources) {
352-
if (resource.isReadable()) {
353+
try {
353354
MetadataReader reader = readerFactory.getMetadataReader(resource);
354355
String className = reader.getClassMetadata().getClassName();
355356
if (matchesEntityTypeFilter(reader, readerFactory)) {
@@ -362,6 +363,9 @@ else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
362363
packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
363364
}
364365
}
366+
catch (FileNotFoundException ex) {
367+
// Ignore non-readable resource
368+
}
365369
}
366370
}
367371
}

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,12 +16,13 @@
1616

1717
package org.springframework.orm.jpa.persistenceunit;
1818

19+
import java.io.FileNotFoundException;
1920
import java.io.IOException;
2021
import java.net.URL;
22+
import java.util.ArrayList;
2123
import java.util.HashMap;
2224
import java.util.HashSet;
2325
import java.util.LinkedHashSet;
24-
import java.util.LinkedList;
2526
import java.util.List;
2627
import java.util.Map;
2728
import java.util.Set;
@@ -498,7 +499,7 @@ public void preparePersistenceUnitInfos() {
498499
* as defined in the JPA specification.
499500
*/
500501
private List<SpringPersistenceUnitInfo> readPersistenceUnitInfos() {
501-
List<SpringPersistenceUnitInfo> infos = new LinkedList<>();
502+
List<SpringPersistenceUnitInfo> infos = new ArrayList<>(1);
502503
String defaultName = this.defaultPersistenceUnitName;
503504
boolean buildDefaultUnit = (this.packagesToScan != null || this.mappingResources != null);
504505
boolean foundDefaultUnit = false;
@@ -585,7 +586,7 @@ private void scanPackage(SpringPersistenceUnitInfo scannedUnit, String pkg) {
585586
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
586587
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
587588
for (Resource resource : resources) {
588-
if (resource.isReadable()) {
589+
try {
589590
MetadataReader reader = readerFactory.getMetadataReader(resource);
590591
String className = reader.getClassMetadata().getClassName();
591592
if (matchesFilter(reader, readerFactory)) {
@@ -602,6 +603,9 @@ else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
602603
className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
603604
}
604605
}
606+
catch (FileNotFoundException ex) {
607+
// Ignore non-readable resource
608+
}
605609
}
606610
}
607611
catch (IOException ex) {

0 commit comments

Comments
 (0)