Profile-based sets of beans

Many cloud-based platforms use proxies wrapped around applications. This enables the platform to support many features, including caching, content delivery networks (CDN), load balancing, and SSL termination. After all, why put such common infrastructure requirements on developers?

However, the side effect can break security protocols designed to protect us in the web. For example, our application may be running on a private IP address, while original requests come in on a public-facing URL. When our application sees a forwarded web request, how are we to distinguish it between a proper request versus some nefarious cross site scripting attack leveraging our service?

The first place this can affect our application is the chat service's WebSocket handling. It requires explicit configuration to handle such a hop. However, we only want such an adjustment in our code to apply when we are in production, not when running things in development on our workstation.

The solution is profile-based beans. Spring lets us configure beans to only be created if certain profiles are enabled.

In the previous chapter, we had our entire WebSocket configuration in a top-level class. We need to change that configuration class and turn it into a container class with different options based on whether or not we are in production.

The first step is to move the existing bean definitions into a new, static inner class as shown here:

    @Configuration 
    public class WebSocketConfig { 
      ... 
      @Profile("!cloud") 
      @Configuration 
      static class LocalWebSocketConfig { 
        ... 
      } 
    } 

So far, we haven't changed a lot. What we have, can be described as follows:

  • The outer class, WebSocketConfig, looks the same
  • This new inner class, LocalWebSocketConfig, is annotated @Profile("!cloud"), meaning it only runs if there is no cloud profile
  • The new class is called LocalWebSocketConfig to clarify that it only operates when we run things locally
What is a cloud profile? Spring allows settings various profiles through the spring.profiles.active application property. We can create all the profiles we want, even overlapping ones. However, any application deployed to Cloud Foundry automatically has an extra profile, that is, cloud, applied.

Since we plan to have both a local as well as a cloud-based configuration, it's important to distinguish what is the same and what is different. Something that will be the same are the WebSocket route mappings.

To support this, we need a single configureUrlMappings() method to configure this SimpleUrlHandlerMapping:

    private static SimpleUrlHandlerMapping configureUrlMappings( 
      CommentService commentService, 
      InboundChatService inboundChatService, 
      OutboundChatService outboundChatService) { 
        Map<String, WebSocketHandler> urlMap = new HashMap<>(); 
        urlMap.put("/topic/comments.new", commentService); 
        urlMap.put("/app/chatMessage.new", inboundChatService); 
        urlMap.put("/topic/chatMessage.new", outboundChatService); 
 
        SimpleUrlHandlerMapping mapping = new 
SimpleUrlHandlerMapping(); mapping.setOrder(10); mapping.setUrlMap(urlMap); return mapping; }

This is the same code we saw in the last chapter, just moved around a little:

  • The three endpoints are tied to their respective services in Map of routes-to-WebSocketHandlers
  • A SimpleUrlHandlerMapping is defined with this map of handlers
  • The order is set to 10
  • The method is static since it will be placed outside our new LocalWebSocketConfig (but inside WebSocketConfig)

To tap this, we simply need to write a bean definition inside LocalWebSocketConfig like this:

    @Bean HandlerMapping webSocketMapping(CommentService
commentService, InboundChatService inboundChatService, OutboundChatService outboundChatService) { return configureUrlMappings(commentService, InboundChatService, outboundChatService); }

This method does nothing more than invoke our WebSocket configuring method.

With the local configuration set up, we can now turn our attention towards configuring the WebSocket broker to work in the cloud. To do so, we need another inner static class inside WebSocketConfig, as follows:

    @Profile("cloud") 
    @Configuration 
    @EnableConfigurationProperties(ChatConfigProperties.class) 
    static class CloudBasedWebSocketConfig { 

It can be explained as follows:

  • It's marked as @Profile("cloud"), meaning this only applies if the cloud profile is in force, the opposite of LocalWebSocketConfig
  • It contains @EnableConfigurationProperties(ChatConfigProperties.class), used to provide an extra set of properties
  • It's named CloudBasedWebSocketConfig to point out its role

If you're wondering what @EnableConfigurationProperties means, it leads us into the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.239.41