Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
3ffc5f2a
Commit
3ffc5f2a
authored
Sep 27, 2019
by
Phillip Webb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Polish 'Support programmatic lazy-int exclusion'
See gh-16615
parent
0f26f4d6
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
171 additions
and
59 deletions
+171
-59
LazyInitializationBeanFactoryPostProcessor.java
...work/boot/LazyInitializationBeanFactoryPostProcessor.java
+38
-49
LazyInitializationExcludeFilter.java
...springframework/boot/LazyInitializationExcludeFilter.java
+76
-0
LazyInitializationExcludeFilterTests.java
...gframework/boot/LazyInitializationExcludeFilterTests.java
+47
-0
SpringApplicationTests.java
...java/org/springframework/boot/SpringApplicationTests.java
+10
-10
No files found.
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/LazyInitializationBeanFactoryPostProcessor.java
View file @
3ffc5f2a
...
...
@@ -16,11 +16,10 @@
package
org
.
springframework
.
boot
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Collection
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.NoSuchBeanDefinitionException
;
import
org.springframework.beans.factory.config.BeanDefinition
;
import
org.springframework.beans.factory.config.BeanFactoryPostProcessor
;
import
org.springframework.beans.factory.config.ConfigurableListableBeanFactory
;
...
...
@@ -28,71 +27,61 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import
org.springframework.core.Ordered
;
/**
* {@link BeanFactoryPostProcessor} to set the lazy attribute on bean definition.
*
* <P>
* This processor will not touch a bean definition that has already had its "lazy" flag
* explicitly set to "false".
*
* <P>
* There are edge cases in which it is not easy to explicitly set the "lazy" flag to
* "false" (such as in DSLs that dynamically create additional beans) and therefore this
* class uses a customizer strategy that allows downstream projects to contribute
* predicates which impact if a class is considered for lazy-loading.
*
* <P>
* Because this is a BeanFactoryPostProcessor, this class does not use dependency
* injection to collect the customizers. The post processor actually makes two passes
* through the bean definitions; the first is used to find and instantiate any
* {@link org.springframework.boot.EagerLoadingBeanDefinitionPredicate} and the second
* pass is where bean definitions are marked as lazy.
* {@link BeanFactoryPostProcessor} to set lazy-init on bean definitions that not
* {@link LazyInitializationExcludeFilter excluded} and have not already had a value
* explicitly set.
*
* @author Andy Wilkinson
* @author Madhura Bhave
* @author Tyler Van Gorder
* @author Phillip Webb
* @since 2.2.0
* @see LazyInitializationExcludeFilter
*/
public
final
class
LazyInitializationBeanFactoryPostProcessor
implements
BeanFactoryPostProcessor
,
Ordered
{
@Override
public
void
postProcessBeanFactory
(
ConfigurableListableBeanFactory
beanFactory
)
throws
BeansException
{
List
<
EagerLoadingBeanDefinitionPredicate
>
eagerPredicateList
=
getEagerLoadingPredicatesFromContext
(
beanFactory
);
// Take care not to force the eager init of factory beans when getting filters
Collection
<
LazyInitializationExcludeFilter
>
filters
=
beanFactory
.
getBeansOfType
(
LazyInitializationExcludeFilter
.
class
,
false
,
false
).
values
();
for
(
String
beanName
:
beanFactory
.
getBeanDefinitionNames
())
{
BeanDefinition
beanDefinition
=
beanFactory
.
getBeanDefinition
(
beanName
);
if
(
eagerPredicateList
.
stream
()
.
anyMatch
((
predicate
)
->
predicate
.
test
(
beanFactory
.
getType
(
beanName
,
false
))))
{
continue
;
}
if
(
beanDefinition
instanceof
AbstractBeanDefinition
)
{
Boolean
lazyInit
=
((
AbstractBeanDefinition
)
beanDefinition
).
getLazyInit
();
if
(
lazyInit
!=
null
&&
!
lazyInit
)
{
continue
;
}
postProcess
(
beanFactory
,
filters
,
beanName
,
(
AbstractBeanDefinition
)
beanDefinition
);
}
beanDefinition
.
setLazyInit
(
true
);
}
}
/**
* This method extracts the list of
* {@link org.springframework.boot.EagerLoadingBeanDefinitionPredicate} beans from the
* bean factory. Because this method is called early in the factory life cycle, we
* take care not to force the eager initialization of factory beans.
* @param beanFactory bean factory passed into the post-processor.
* @return a list of {@link EagerLoadingBeanDefinitionPredicate} that can be used to
* customize the behavior of this processor.
*/
private
List
<
EagerLoadingBeanDefinitionPredicate
>
getEagerLoadingPredicatesFromContext
(
ConfigurableListableBeanFactory
beanFactory
)
{
Map
<
String
,
EagerLoadingBeanDefinitionPredicate
>
eagerPredicates
=
beanFactory
.
getBeansOfType
(
EagerLoadingBeanDefinitionPredicate
.
class
,
false
,
false
);
private
void
postProcess
(
ConfigurableListableBeanFactory
beanFactory
,
Collection
<
LazyInitializationExcludeFilter
>
filters
,
String
beanName
,
AbstractBeanDefinition
beanDefinition
)
{
Boolean
lazyInit
=
beanDefinition
.
getLazyInit
();
Class
<?>
beanType
=
getBeanType
(
beanFactory
,
beanName
);
if
(
lazyInit
==
null
&&
!
isExcluded
(
filters
,
beanName
,
beanDefinition
,
beanType
))
{
beanDefinition
.
setLazyInit
(
true
);
}
}
return
new
ArrayList
<>(
eagerPredicates
.
values
());
private
Class
<?>
getBeanType
(
ConfigurableListableBeanFactory
beanFactory
,
String
beanName
)
{
try
{
return
beanFactory
.
getType
(
beanName
,
false
);
}
catch
(
NoSuchBeanDefinitionException
ex
)
{
return
null
;
}
}
private
boolean
isExcluded
(
Collection
<
LazyInitializationExcludeFilter
>
filters
,
String
beanName
,
AbstractBeanDefinition
beanDefinition
,
Class
<?>
beanType
)
{
if
(
beanType
!=
null
)
{
for
(
LazyInitializationExcludeFilter
filter
:
filters
)
{
if
(
filter
.
isExcluded
(
beanName
,
beanDefinition
,
beanType
))
{
return
true
;
}
}
}
return
false
;
}
@Override
...
...
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/LazyInitializationExcludeFilter.java
0 → 100644
View file @
3ffc5f2a
/*
* Copyright 2012-2018 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
*
* https://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
.
springframework
.
boot
;
import
org.springframework.beans.factory.config.BeanDefinition
;
import
org.springframework.beans.factory.support.AbstractBeanDefinition
;
/**
* Filter that can be used to exclude beans definitions from having their
* {@link AbstractBeanDefinition#setLazyInit(boolean) lazy-int} set by the
* {@link LazyInitializationBeanFactoryPostProcessor}.
* <P>
* Primarily intended to allow downstream projects to deal with edge-cases in which it is
* not easy to support lazy-loading (such as in DSLs that dynamically create additional
* beans). Adding an instance of this filter to the application context can be used for
* these edge cases.
* <P>
* A typical example would be something like this:
* <P>
* <pre><code>
* @Bean
* public static LazyInitializationExcludeFilter integrationLazyInitializationExcludeFilter() {
* return LazyInitializationExcludeFilter.forBeanTypes(IntegrationFlow.class);
* }</code></pre>
* <p>
* NOTE: Beans of this type will be instantiated very early in the spring application
* lifecycle so should generally be declared static and not have any dependencies.
*
* @author Tyler Van Gorder
* @author Philip Webb
* @since 2.2.0
*/
@FunctionalInterface
public
interface
LazyInitializationExcludeFilter
{
/**
* Returns {@code true} if the specified bean definition should be excluded from
* having {@code lazy-int} automatically set.
* @param beanName the bean name
* @param beanDefinition the bean definition
* @param beanType the bean type
* @return {@code true} if {@code lazy-int} should not be automatically set
*/
boolean
isExcluded
(
String
beanName
,
BeanDefinition
beanDefinition
,
Class
<?>
beanType
);
/**
* Factory method that creates a filter for the given bean types.
* @param types the filtered types
* @return a new filter instance
*/
static
LazyInitializationExcludeFilter
forBeanTypes
(
Class
<?>...
types
)
{
return
(
beanName
,
beanDefinition
,
beanType
)
->
{
for
(
Class
<?>
type
:
types
)
{
if
(
type
.
isAssignableFrom
(
beanType
))
{
return
true
;
}
}
return
false
;
};
}
}
spring-boot-project/spring-boot/src/
main/java/org/springframework/boot/EagerLoadingBeanDefinitionPredicate
.java
→
spring-boot-project/spring-boot/src/
test/java/org/springframework/boot/LazyInitializationExcludeFilterTests
.java
View file @
3ffc5f2a
/*
* Copyright 2012-201
8
the original author or authors.
* Copyright 2012-201
9
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,38 +16,32 @@
package
org
.
springframework
.
boot
;
import
java.util.function.Predicate
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.config.BeanDefinition
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
Mockito
.
mock
;
/**
* This predicate can be implemented by downstream projects to customize the behavior of
* the {@link LazyInitializationBeanFactoryPostProcessor}.
*
* <P>
* There are edge cases (such as in DSLs that dynamically create additional beans) in
* which it is not easy to explicitly exclude a class from the lazy-loading behavior.
* Adding an instance of this predicate to the application context can be used for these
* edge cases.
* <P>
* Returning "true" from this predicate will exclude a class from the lazy-loading
* process.
*
* <P>
* Example:
* <P>
* <pre>
* {@code
* Tests for {@link LazyInitializationExcludeFilter}.
*
* @Bean
* public static EagerLoadingBeanDefinitionPredicate eagerLoadingBeanDefinitionPredicate() {
* return IntegrationFlow.class::isAssignableFrom;
* }}</pre>
*
* WARNING: Beans of this type will be instantiated very early in the spring application
* life cycle.
*
* @author Tyler Van Gorder
* @since 2.2.0
* @author Phillip Webb
*/
public
interface
EagerLoadingBeanDefinitionPredicate
extends
Predicate
<
Class
<?>>
{
class
LazyInitializationExcludeFilterTests
{
@Test
void
forBeanTypesMatchesTypes
()
{
LazyInitializationExcludeFilter
filter
=
LazyInitializationExcludeFilter
.
forBeanTypes
(
CharSequence
.
class
,
Number
.
class
);
String
beanName
=
"test"
;
BeanDefinition
beanDefinition
=
mock
(
BeanDefinition
.
class
);
assertThat
(
filter
.
isExcluded
(
beanName
,
beanDefinition
,
CharSequence
.
class
)).
isTrue
();
assertThat
(
filter
.
isExcluded
(
beanName
,
beanDefinition
,
String
.
class
)).
isTrue
();
assertThat
(
filter
.
isExcluded
(
beanName
,
beanDefinition
,
StringBuilder
.
class
)).
isTrue
();
assertThat
(
filter
.
isExcluded
(
beanName
,
beanDefinition
,
Number
.
class
)).
isTrue
();
assertThat
(
filter
.
isExcluded
(
beanName
,
beanDefinition
,
Long
.
class
)).
isTrue
();
assertThat
(
filter
.
isExcluded
(
beanName
,
beanDefinition
,
Boolean
.
class
)).
isFalse
();
}
}
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java
View file @
3ffc5f2a
...
...
@@ -1107,15 +1107,15 @@ class SpringApplicationTests {
}
@Test
void
lazyInitialization
ShouldNotApplyTo
BeansThatAreExplicitlyNotLazy
()
{
void
lazyInitialization
Ignores
BeansThatAreExplicitlyNotLazy
()
{
assertThat
(
new
SpringApplication
(
NotLazyInitializationConfig
.
class
)
.
run
(
"--spring.main.web-application-type=none"
,
"--spring.main.lazy-initialization=true"
)
.
getBean
(
AtomicInteger
.
class
)).
hasValue
(
1
);
}
@Test
void
lazyInitialization
ShouldNotApplyToBeansThatMatchPredicate
()
{
assertThat
(
new
SpringApplication
(
NotLazyInitializationPredicate
Config
.
class
)
void
lazyInitialization
IgnoresLazyInitializationExcludeFilteredBeans
()
{
assertThat
(
new
SpringApplication
(
LazyInitializationExcludeFilter
Config
.
class
)
.
run
(
"--spring.main.web-application-type=none"
,
"--spring.main.lazy-initialization=true"
)
.
getBean
(
AtomicInteger
.
class
)).
hasValue
(
1
);
}
...
...
@@ -1430,7 +1430,7 @@ class SpringApplicationTests {
}
@Configuration
(
proxyBeanMethods
=
false
)
static
class
NotLazyInitializationPredicate
Config
{
static
class
LazyInitializationExcludeFilter
Config
{
@Bean
AtomicInteger
counter
()
{
...
...
@@ -1443,16 +1443,16 @@ class SpringApplicationTests {
}
@Bean
static
EagerLoadingBeanDefinitionPredicate
eagerLoadingBeanDefinitionPredicate
()
{
return
NotLazyBean
.
class
::
isAssignableFrom
;
static
LazyInitializationExcludeFilter
lazyInitializationExcludeFilter
()
{
return
LazyInitializationExcludeFilter
.
forBeanTypes
(
NotLazyBean
.
class
)
;
}
static
class
NotLazyBean
{
}
NotLazyBean
(
AtomicInteger
counter
)
{
counter
.
getAndIncrement
();
}
static
class
NotLazyBean
{
NotLazyBean
(
AtomicInteger
counter
)
{
counter
.
getAndIncrement
();
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment