I have a some small experience with spring-boot. I consider if I correctly understand its way of working, on example rabbitmq which I am using now.
So look at my way of thinking and correct me if I am wrong, please.
I added to my pom.xml dependencies for spring-rabbit. Thanks to this dependency, I can use automatic configuration what does mean that during starting application spring engine read application.properties, find settings for rabbitmq (as host, port, queuename) and creates (register) needed beans for servicing rabbitmq (is this sequence of step is correct ?).
Now, I should be able to use #Autowired to get some beans (=objects form spring container).
Where is difference between spring and spring-boot in this case ?
To my eye, using spring I have must add all necessary beans in java code (or xml) and mark them as #Bean or #Autowired. However, in this case I must use new operator and be responsible for creating instance of queues and something like that.
Can you tell me if I correctly understand it ? Each additional explanation is welcome!
Related
My target is to build a GraphQL server on Spring with (1) GraphiQL IDE (2) dynamic GraphQL schema at run-time. My GraphQL engine is GraphQL-Java.
In my first try, I use graphql-java-spring-boot-starter-webmvc and graphiql-spring-boot-starter.
Both the GraphQL server and the GraphiQL work well.
However, under the graphql-java-spring-boot-starter-webmvc framework, a #Bean of GraphQL class is needed. In this bean, the schema is loaded when the server starts so it could not been updated.
In my second try, I don't use graphql-java-spring-boot-starter-webmvc. Instead, I choose spring-boot-starter-web to start the web server and define my own RestController. This is easy to update the GraphQL instance. But I don't find a way to integrate with GraphiQL. I googled GraphiQL+Spring but all solutions are with graphql-java-spring-boot-starter.
Appreciate if anyone could provide me an idea on either approach.
It can be enabled in properties:
graphql.graphiql.enabled=true
It is accessible via the root url +/graphiql example http://localhost:8080/graphiql
You can find a good detailed example here : https://github.com/NoorKrichen/GraphQL-Spring-Boot-Example
Do you have a sample of your setup in git?
It sounds like some configuration problem. But naturally using graphql-java-spring-boot-starter-webmvc all your *.graphql schemas should be picked up in the configured schema resource path. check if you have the path set in your application.yml or if your schema is in the configured path if its already set or by default.
On your second point: "I googled GraphiQL+Spring but all solutions are with graphql-java-spring-boot-starter."
This makes sense for quick guides and demos as using Springboot the plumbing is somehow hidden away from you so that you can focus on the technology at hand being demo'd in this case GraphQl.
On GraphiQL:
Sounds like you are intending to have this embedded with your application, you may not want to do so in production. Depending on your use case there are many other alternatives that are standalone and gives you all the functionality of GraphiQL plus more e.g Altair Graphql Client and Insomnia to name a few.
I am trying to disable Redis when I am testing with spring boot. I have disabled my configuration but the auto config created a default connection and fails because it can't connect to a non-existent service. For testing I am content to just use a basic in-memory cache or a no-op cache. That doesn't work either. Here is what I have tried:
per this issue I added said configuration to my test app properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
But. That gets me a bit further. But ultimately I get a NoSuchBeanDefinitionException redisTemplate - this is because redisReferenceResolver is trying to look that up.
Looking at my debugger right now, the bean it's trying to hydrate is:
org.springframework.data.redis.core.convert.ReferenceResolverImpl which is coming from spring-data-redis:1.8.0.RELEASE which is coming from this dependency: compile('org.springframework.boot:spring-boot-starter-data-redis') . I admit, the bean name is a bit misleading. The type it actually resolves to is not
The only other reference to redis is in our hibernate support.
Can someone explain how to turn this off for testing?
Try excluding this two auto-configuration classes in your test properties file:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
or
exclude
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
and set: spring.data.redis.repositories.enabled=false
With YAML syntax (& Spring Boot):
spring.autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
- org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
If you have SystemEnvironmentPropertySource in you app context you can use environment variable SPRING_AUTOCONFIGURE_EXCLUDE separating items with comma:
SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
Also try #EnableAutoConfiguration(exclude = {...}) on a #TestConfiguration annotated class.
If you dont want to change any files/code, you can also do this with an environment variable:
SPRING_AUTOCONFIGURE_EXCLUDE=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
It is needed to define Spring scope which will provide a proxy to the beans and reload/recreate target beans when say an event occurs. The behavior is similar to session beans, except there is no http session.
Does Spring provide a way for such bean proxing and scope manipulation?
UPDATED
Say that it is need to change externalUrl which is used to send http requests. So the application has to switch to new bean with new http connection pool created.
When bean autowired directly it is imposible to recreate it, especially when it is used in many places. So I search some way to inject a proxy instead of it and recreate target instace without altering caller code.
It is possible. I can't tell you exactly how to do it, but if you're able to, something like Spring Cloud Config would be exactly what you want. If you can't adopt that, I would start digging into the source code. The class you'd want to start with is the RefreshScope - from there, you should be able to figure out how it works and how it re-creates beans. I'm sorry that I can't provide more direction.
I am trying to figure out how can I dynamically update/reload externalized configuration in a Spring Boot application without restarting the whole application.
Most of the advice involves reloading ApplicationContext after changing the externalized configuration, but that is equivalent to restarting the entire application, so this is not really all that useful.
Reading through SpringBoot reference documentation, I found a chapter 23.7 Typesafe Configuration Properties.
If I understand it correctly, this allows to define simple POJO classes that will hold your application (externalized) configuration values as attributes.
In theory at least, this scheme could be used to bind beans only once to the required configuration POJO and upon configuration change just update the values in the POJO. Components could easily pick up the changes next time they access getters on the POJO...
However, I have yet not managed to figure out how to enable this type of behavior. Is there some glaringly obvious way to dynamically update components annotated with #ConfigurationProperties when relevant configuration has changed?
It sounds like you're looking for #RefreshScope which is provided by Spring Cloud. From the Spring Cloud documentation:
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
I'd like to run one spring boot application but have it listen on multiple ports.
The aim is to be able to let an Apache forward multiple (sub-) domains to the spring boot application (Tomcat) on different ports. Example:
example.com/** -> PORT 8080
client.example.com/** -> PORT 8090
employee.example.com/** -> PORT 8100
As far as I understood from several threads on SO, I'm best off launching multiple #SpringBootApplication Annotated classes from one main class, right? (https://stackoverflow.com/a/25870132/1510659)
What I didn't grasp yet, is how to configure each one of those applications separately.
Let's say I have launched these three Applications as shown in the linked post above:
MainExampleApplication
ClientExampleApplication
EmployeeExampleApplication
Now, for example, I want to have separate Spring Security #Configuration classes for each of these Applications, as well as #RequestMappings which might have the same value (e.g. "/").
How do I tell the #Configuration or #Controller classes which Application they are assigned to?
Or are there properties that can to be passed to the applications on startup to specify which resources are responsible for the context?
I hope I'm not going in a totally wrong direction here. I do have experience with Spring MVC and have configured some rather simplistic Spring applications - but not with multiple contexts. I'd be really glad if someone could lead me in the right direction. Thank you in advance.
UPDATE
As mentioned in iamiddy's answer and xeon's comment, I used Spring Profiles for that. I provided the SpringApplicationBuilder with a profile for each of my application contexts on startup and used the #Profile("some_profile") on the #Components that should only be available to some of the contexts.
Use Profiles it's a great spring feature, loads only beans associted with the profile.
Once that's done start your applications N times with different port and profile arguments
Ex: Here is how you would start the first one, do it for the rest to your N
java -jar -Dspring.profiles.active=production1 -Dserver.port=9000 app.jar