Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize startup time: make validation initialization lazy #7579

Closed
dsyer opened this issue Dec 6, 2016 · 21 comments
Closed

Optimize startup time: make validation initialization lazy #7579

dsyer opened this issue Dec 6, 2016 · 21 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@dsyer
Copy link
Member

dsyer commented Dec 6, 2016

If I'm not really using validation except in the web tier it's wasteful to initialize it on startup, and it's expensive: 200-300ms out of 3s to start a Pet Clinic.

@philwebb philwebb added the type: enhancement A general enhancement label Dec 6, 2016
@philwebb philwebb added this to the 1.5.0 milestone Dec 6, 2016
@philwebb
Copy link
Member

philwebb commented Dec 6, 2016

Will target to 1.5 to see what are options are. It might slip.

@wilkinsona
Copy link
Member

I think this should be DevTools-specific or opt-in. In production, I'd prefer to pay the cost of validation initialisation at startup and be safe in the knowledge that it's initialised successfully rather than deferring the cost and potential failure until a request is routed to the app.

@dsyer
Copy link
Member Author

dsyer commented Dec 6, 2016

It's also used in @ConfigurationProperties processing, at least optionally, so I'd want that to be on if I'm not in dev mode. It's a tricky one. It does seem inordinately expensive to bootstrap a local validator, compared to the value it provides. I guess maybe we should stick to explicit Spring validators for our own config properties, or something cheaper than Hibernate if it exists.

@snicoll
Copy link
Member

snicoll commented Dec 12, 2016

for our own config properties

We can't do that. Validation is an advertized feature so users are free to use it as advertized (read in their config properties). I don't think that changing something for our own code is something we should ever do if the related feature is public.

@snicoll snicoll modified the milestone: 1.5.0 Jan 16, 2017
@philwebb
Copy link
Member

I did a bit of digging with this, it seems like the majority of the time is spent trying to work out of a @ConfigurationProperties instance has any validator constraints. The logic is quite complicated, scanning all method and parameters for annotations and working up the type hierarchy.

95% of our properties classes don't use JSR-330 constraints, I think if we switch validation off for our classes, but leave it on for user defined configuration classes, we should be able to improve startup time.

@snicoll
Copy link
Member

snicoll commented Jan 17, 2017

I think it would be easier to require @Validated on the class to enable validation. That way we can have a quick check to figure out if we need to enable it or not.

@philwebb
Copy link
Member

Experimental branch https://github.com/philwebb/spring-boot/tree/gh-7579

@philwebb
Copy link
Member

@snicoll I like that idea, but is it a sensible change for 1.5? My approach so far has been to add a vaidate attribute to @ConfigurationProperties and set that to false for all our own instances.

@philwebb
Copy link
Member

Change isn't noticeable in SampleTomcatApplication:

before

2017-01-16 23:31:40.055  INFO 91149 --- [           main] sample.tomcat.SampleTomcatApplication    : Started SampleTomcatApplication in 1.494 seconds (JVM running for 1.744)
2017-01-16 23:32:05.928  INFO 91185 --- [           main] sample.tomcat.SampleTomcatApplication    : Started SampleTomcatApplication in 1.494 seconds (JVM running for 1.743)
2017-01-16 23:32:21.487  INFO 91207 --- [           main] sample.tomcat.SampleTomcatApplication    : Started SampleTomcatApplication in 1.493 seconds (JVM running for 1.746)

after


2017-01-16 23:27:27.669  INFO 90702 --- [           main] sample.tomcat.SampleTomcatApplication    : Started SampleTomcatApplication in 1.764 seconds (JVM running for 2.23)
2017-01-16 23:27:44.806  INFO 90731 --- [           main] sample.tomcat.SampleTomcatApplication    : Started SampleTomcatApplication in 1.498 seconds (JVM running for 1.744)
2017-01-16 23:27:55.165  INFO 90746 --- [           main] sample.tomcat.SampleTomcatApplication    : Started SampleTomcatApplication in 1.518 seconds (JVM running for 1.771)

But it is for Pet Clinic:

before

2017-01-16 23:30:28.164  INFO 91031 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 8.411 seconds (JVM running for 8.841)
2017-01-16 23:30:52.690  INFO 91068 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 7.988 seconds (JVM running for 8.424)
2017-01-16 23:31:14.828  INFO 91101 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 7.928 seconds (JVM running for 8.359)

after


2017-01-16 23:28:31.642  INFO 90792 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 7.654 seconds (JVM running for 8.143)
2017-01-16 23:28:48.329  INFO 90815 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 7.437 seconds (JVM running for 7.863)
2017-01-16 23:29:04.505  INFO 90841 --- [  restartedMain] o.s.s.petclinic.PetClinicApplication     : Started PetClinicApplication in 7.624 seconds (JVM running for 8.106)

@snicoll
Copy link
Member

snicoll commented Jan 17, 2017

That flag is better if you want this to be made 100% transparent but it's a bit weird. Someone might wonder why you wouldn't want validation in the first place. Our reasoning here is performance so making it that opt-in (i.e. you need the relevant annotation now) makes more sense to me.

Surely the current state is awesome because nobody has to change anything but I fear we'll regret that design pretty soon.

@wilkinsona
Copy link
Member

wilkinsona commented Jan 17, 2017

I like the idea of requiring @Validated and that feels like where we want to get to. I'm not sure how to get there from where we are today, but adding a validate attribute to @ConfigurationProperties doesn't feel like the right way to me. I'm not keen on adding an attribute in 1.5 that we'd then, presumably, want to remove in 2.0 in favour of requiring @Validated.

I think we either need to jump straight into @Validated in 1.5 or we should wait for 2.0 where requiring @Validated will be less of a shock.

@dsyer
Copy link
Member Author

dsyer commented Jan 17, 2017

+1 for @Validated (in 1.5 if possible).

@philwebb
Copy link
Member

Seems like @Validated is the winner. Will try for 1.5.

@philwebb philwebb self-assigned this Jan 19, 2017
@philwebb philwebb added this to the 1.5.0 milestone Jan 19, 2017
philwebb added a commit that referenced this issue Jan 19, 2017
Update use of `@ConfigurationProperties` to prefer the more explicit
`prefix` attribute, rather than `value`.

See gh-7579
philwebb added a commit that referenced this issue Jan 19, 2017
Replace JSR-330 validation annotations from all internal
`@ConfigurationProperties` classes with standard Asserts.

Prior to this commit validation of our own configuration properties
would only occur when the user happens to have compliant JSR-330
implementation on their classpath.

See gh-7579
philwebb added a commit that referenced this issue Jan 19, 2017
@philwebb
Copy link
Member

For 1.5 we'll still validate all configuration classes (with the exception of Spring Boot's own) even if there's not a @Validated annotation. We'll log a warning telling people what to do. We can flip the default in 2.0.

@kazuki43zoo
Copy link
Contributor

kazuki43zoo commented Jan 20, 2017

Hi @philwebb ,

I tried this feature using latest snapshot version of 1.5.
But same warning log are output twice if not specify the @Validated on configuration properties class as follow:

2017-01-21 01:44:59.434  WARN 15563 --- [           main] figurationPropertiesBindingPostProcessor : The @ConfigurationProperties bean class com.example.AppProperties contains validation constraints but had not been annotated with @Validated.
2017-01-21 01:45:00.201  WARN 15563 --- [           main] figurationPropertiesBindingPostProcessor : The @ConfigurationProperties bean class com.example.AppProperties contains validation constraints but had not been annotated with @Validated.

Is this behavior work as design ?
I think better that it output only just once. What do you think ?

@philwebb philwebb reopened this Jan 21, 2017
@philwebb
Copy link
Member

@kazuki43zoo Once only would be better

@bclozel
Copy link
Member

bclozel commented Jan 25, 2017

@philwebb quick question regarding the use of @PostConstruct annotated methods to validate properties.

Is this how it should be done on all properties classes from now on?
Is it strictly limited to validation code (or general initialization code is accepted)?
Why are setters not considered for this?

@philwebb
Copy link
Member

@bclozel I think setters might actually be better. I tried them at one point but hit some issues (I can't remember why). I'd say try setters first.

@philwebb
Copy link
Member

I'll try to fix the ones I changed.

@snicoll
Copy link
Member

snicoll commented Jan 26, 2017

@philwebb the only use case I have in mind is if you set the value to null for some reason and later (before the bean is initalized) you provide a valid value. If we put the validation in the setter it will fail hard as soon as we attempt to set null. Not sure if that's a legit use case but I wish we wouldn't use @PostConstruct to replace the validation.

@wilkinsona
Copy link
Member

We're going to live with the double log message. I've replaced the @PostConstruct-based validation with setter-based validation in f823599.

snicoll added a commit that referenced this issue Jan 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

6 participants