2

I had to create a singleton bean manually in a @Configuration class in order to share it without exposing it into the context (which triggers conditionals/autoconfigures). I have been pointed to the awareness of certain risks to manage it by myself:

  • Thread Safeness: The Datasource object is not stateless
  • Resource leaking: The Datasource object is not explictly closed by the context

The code is the following:

    private DataSource nonExposedDatasource;

    public DataSource nonExposedSingletonDataSource() {
        if (Objects.isNull(this.nonExposedDatasource)) {
            this.nonExposedDatasource = this.myPrivateDatasourceProperties.initializeDataSourceBuilder().build();
        }
        return this.nonExposedDatasource;
    }

    @Bean
    public TaskConfigurer taskConfigurer() {
        return new DefaultTaskConfigurer(this.nonExposedSingletonDataSource());
    }

    @Bean
    public BatchConfigurer batchConfigurer() {
        return new DefaultBatchConfigurer(this.nonExposedSingletonDataSource());
    }

My question is: Do I really have a risk to overlook this? Isn't Spring smart enough?

  • Regarding thread safeness, I understand that for my code to be problematic, there should happen 2 threads processing the @Configuration. Does Spring does that??

  • Regarding resource leaking, if my Datasource had been a @Bean managed by Spring, like most applications work, wouldn't have been this a potential pitfall if the app closes anyway?

How would you make safer this code?

Whimusical
  • 6,401
  • 11
  • 62
  • 105
  • `DataSource` is [not a Closeable](https://docs.oracle.com/javase/8/docs/api/javax/sql/DataSource.html), so I'm not sure what you mean by "not explicitly closed" here. Neither do `DataSource` docs discuss the thread-safety guarantees of the particular source or its connections - you will have to check with your driver implementor as to what guarantees are given. Also, consider that Spring transactions are always thread-bound (attributes are `ThreadLocal`), so I fully expect it to thread-bind the `Connection` objects as well. – M. Prokhorov Mar 22 '19 at 12:11
  • This is regarding one of the comments in here: https://stackoverflow.com/questions/55248571/use-configurationproperties-over-non-managed-bean?noredirect=1#comment97295198_55248571 "When doing things like this make sure you also register a callback to close the connections when the application is stopped. Else you might leave open (tcp) connections, normally this would be handled due to the fact it is a bean." (but it is not a @Bean) – Whimusical Mar 22 '19 at 14:03
  • 1
    I don't even know how one would go about closing connections that's open from the datasource if one didn't open it in the first place: the interface gives no ability to do so. Though given that in linked question you say it's a HikariCP source - you can register a shutdown hook if you want. As for data safety, I expect HikariDS to be thread-safe, but what's not thread-safe is you accessing instances of it. You need to synchronize that yourself somehow. – M. Prokhorov Mar 28 '19 at 13:21
  • So if I understand correctly, I should not worry about leaked connection, but I should about synchronization, so does this mean that Spring might load the @Configuration through different threads? – Whimusical Apr 02 '19 at 17:29
  • The thing to notice here is that the sole usage of my Datasource object is by Spring Framework through DefaultTaskConfigurer and DefaultBatchConfigurer ( as shown in code), so I guess the question is whether the fact of not being managed as a @Bean requires any special treatment for synchronization – Whimusical Apr 02 '19 at 17:46
  • if I understand it right, you might declare your beans as lazy-init, at which point Spring won't really care to create your beans unless something depends on them. This dependency might be realized by your code, calling `BeanFactory` to obtain an instance from different threads. In your setup, I think configuration will be single-threaded. – M. Prokhorov Apr 03 '19 at 14:02
  • Since that's already a pretty long discussion, might I ask why are you doing any of this in the first place (i.e. why is your datasource not a `@Bean`)? If you don't want bean exposed to outside, then Spring [already got you covered](https://docs.spring.io/spring-javaconfig/docs/1.0-m2/reference/html/bean-visibility.html), no need to go through all this nonsence. Also note, that if your bean is-a `Closeable` at all, then Spring [also got you covered](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html#destroyMethod--). – M. Prokhorov Apr 03 '19 at 14:04
  • I already saw this documentation but it must be old or something since it did not work for me. https://stackoverflow.com/questions/55063611/bean-in-configuration-for-private-usage-i-e-not-exposed-further-that-contain – Whimusical Apr 03 '19 at 15:40
  • That's a different piece of functionality that wasn't working, it sounds like. You wanted to not export a bean, but.. *still export it* so it's accessible by autoconfigurers? Not a huge amount of making sense to but Ok. What's a configurer - a bean post processor? Which post processor implementation you have that doesn't work? – M. Prokhorov Apr 03 '19 at 15:50
  • Just the opposite. I wanted Spring to manage the bean but not out of the @Configuration for my autoconfigurers not to be triggered – Whimusical Apr 04 '19 at 10:50

0 Answers0