• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Liutauras Vilda
  • Ron McLeod
Sheriffs:
  • Jeanne Boyarsky
  • Devaka Cooray
  • Paul Clapham
Saloon Keepers:
  • Scott Selikoff
  • Tim Holloway
  • Piet Souris
  • Mikalai Zaikin
  • Frits Walraven
Bartenders:
  • Stephan van Hulst
  • Carey Brown

Tricky question on Spring beans autowiring.

 
Bartender
Posts: 1381
39
IBM DB2 Netbeans IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm struggling to found a solution to a problem that I started to think it's above me. To be honest, I wonder if the problem itself is well-defined and it makes sense.

Scenario: I'm gonna build a large application based upon spring boot. I will use several Services, and , to avoid strictly coupling beetwen services, besides heavily using interfaces i want to slice the whole codebase in more maven projects.
I will have a core project in which I will define all business interfaces (which will be implemented by @Service classes), value objects and some commons utilities, plus a number of separated projects where I will implement actual services and that will act as application modules.
Each single "application module" will depend on "core" module, and the whole resulting application will ultimately be composed by both core and  application modules.

The key idea behind this approach is to "start monolithic, and be prepared for microservices".
I want to be able, eventually, to deploy each application module in a separated JVM (if necessary, of course) with minimal efforts.

Because each service will inject interfaces and it will always have the core module as dependency, where all interfaces are defined, at least at compile-time I could separate modules without any issue.

The problem of course it's at during runtime because I cannot find a way to :

- autowire a "local" implementation of a given service interface,  if it's available in the application classpath;
- autowire a remote proxy for a given interface, if no implementing class it's available in the application classpath.

So I have two question for you, guys:

a) what do you think of the whole approach ?
b) do you have any advice about the problem of developing a "dynamic autowiring" mechanism ?

Thanks in advance !

 
Bartender
Posts: 1868
81
Android IntelliJ IDE MySQL Database Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This book Learning Spring Boot 2.0 - Second Edition by Greg L. Turnquist (a Pivotal developer) which can be found here https://www.packtpub.com/application-development/learning-spring-boot-20-second-edition kind of does this sort of thing.
I did say kind of and not exactly because it breaks the application into microservices, and I would suggest that you do the same.

If you follow all of the examples in this book you end up create a number of different Spring Boot apps which all come together, plus you create one app for each which uses each of the following technologies:
  • Cloud Config Server for centralize yet distributed configurations
  • Hyrstrix for grace degradation of services
  • RabbitMQ for service to service messaging
  • Eureka for service load balancing

  • The book include much more like using Reactive IO aka Spring WebFlux and notes on testing.

    Sometimes Packtpub.com has sales on it's electronic material so it's worth checking out their site even now and then.

    Book push aside, I would suggest that instead of starting with a monolithic you start with microservices.
    For app to app (or even within the app) communication you could use JMS, which is somewhat of a standard.
    You can then limit some of the dependencies or at least fail gracefully and scale quickly if needed.
     
    Claude Moore
    Bartender
    Posts: 1381
    39
    IBM DB2 Netbeans IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Pete, thanks for your reply and for your advices. Starting with microservices is intriguing, but honestly I prefer to begin with the old fashioned monolithic approach, as Martin Fowler suggests to do. Starting with microservices would not give me many advantages: the project will be made of of rather strictly dependent modules, and honestly I'm afraid that orchestrating all modules as microservice already at time zero would be an unuseful approach (at least for mine scenario). At the same time, I cannot ignore that modularization of moder software is a must. So I'm trying to organize my codebase accordingly with modular software principles.

    Good idea to use JMS for integration. I think I'll use an AMQP-based RPC schema between modules (when modules won't be co-located in the same JVM, of course). I dropped the idea to use REST-based APIs even for modules intra-communication. All modules are going to be written in Java language, so I can't see the point to use REST API; moreover,  whenever modules will be deployed within separated JVM instances, I think that they will be deployed in the same LAN (with very low latency), so using a lightweight communication protocol won't be a key requirement.

    Thanks again for your help.
     
    Pete Letkeman
    Bartender
    Posts: 1868
    81
    Android IntelliJ IDE MySQL Database Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Claude Moore wrote:I'm afraid that orchestrating all modules as microservice already at time zero would be an unuseful approach (at least for mine scenario)

    Yes, service orchestrating can be somewhat overwhelming, luckily Pivotal has reorganized this which is where Eureka, Cloud Config Server and Hystrix can help out.
    I do understand that microservices are not for every project or every developer and there is a certain amount of duplication in data or effort when implementing them.

    Claude Moore wrote:I think I'll use an AMQP-based RPC schema between modules (when modules won't be co-located in the same JVM, of course)

    I'm unsure as to why you would limit AMQP to the same JVM, as I don't think that you do not need to.
    By the way RabbitMQ implements AMQP and it created by and maintained by Pivotal.

    Claude Moore wrote:I can't see the point to use REST API

    Implementing REST endpoints can be useful if you are going with different client implementations including but not limited to Android and IOS devices.
    However many times a responsive web site can be used instead of Android or IOS programs.

    Claude Moore wrote:I think that they will be deployed in the same LAN (with very low latency), so using a lightweight communication protocol won't be a key requirement.

    Are sure you can control the network and hardware? If you are pushing your project to a cloud provider then implementing a lightweight communication protocol may be a requirement.
     
    Saloon Keeper
    Posts: 28414
    210
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    That's a big steak to chew on, so to speak. And if you're looking at messaging protocols, I'm thinking that probably something at least slightly micro-service-like is almost inevitable, whether you actually adopt industry-standard techniques or essentially end up re-inventing them. Beyond that it's hard to say, since I'd need more specific details on the architecture of the system.

    The one thing that did stick out is your confusion about auto-wiring local and remote interfaces. Spring is based on a bean factory and wires bean instances. You cannot manufacture and instantiate an interface, only a bean that implements that interface. Likewise you cannot inject an interface. An interface is an abstraction and Spring deals in concretes.
     
    Claude Moore
    Bartender
    Posts: 1381
    39
    IBM DB2 Netbeans IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tim Holloway wrote:
    The one thing that did stick out is your confusion about auto-wiring local and remote interfaces. Spring is based on a bean factory and wires bean instances. You cannot manufacture and instantiate an interface, only a bean that implements that interface. Likewise you cannot inject an interface. An interface is an abstraction and Spring deals in concretes.



    I admit that i'm rather a newbie with Spring, so that terminology I use won't be the best, but I suppose that working with interfaces instead of wiring directly concrete class is a paradigm that Spring supports well (even if I don't know if encourages to do so).
    I'm afraid that what I'm trying to do with Spring may not be a good programming practice, so please help me to better undestand.

    Let's suppose I have a trivial class which extends an interface:



    In Spring I can inject a concrete instance of SampleService , but at the same time, I'm formally  working with an interface:



    and AFAIK this code is perfectly valid. What I want to achieve is a way to inject a different concrete instance of ISampleService dinamically, and treat my services like "plugins" so that:
    - if a concrete class is available in the classpath of my application, a concrete local instance will be injected;
    - otherwise, a stub to call remote instances will be created (and injected)

    Is there anything wrong with this ?

    Thanks in advance.


     
    Tim Holloway
    Saloon Keeper
    Posts: 28414
    210
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I don't think your example will compile, actually.

    The statement


    is not syntactically valid Java, and annotations such as @Autowired cannot change that.

    What you actually need is something more like this:


    Because this is an autowired property, the annotation processor will internally generate injection logic:


    The Spring framework's annotation processor will also inject autowired values when an instance of the bean that contains this properly is instantiated (assuming that the class is on the Spring annotation scanning path). Spring will check its inventory for a bean named "iSampleService" (the default name, created by lowercasing the class name's first character). If the bean exists, Spring will invoke the target bean's "setSampleService" method (the effect is the same whether you explicitly declare this method or let the annotation processor synthesize it). If the bean does not exist, then the Spring bean factory will attempt to construct it using a no-element constructor, effectively doing a "new ISampleService()" to do so (actually, it invokes ISampleService.class.newInstance(), but so does the "new" operator).

    However, since ISampleService is an interface, it can have no constructor, by definition. So the attempt will fail. Probably at runtime. Possibly by injecting null as the property, but there's also the possibility that the Spring framework will simply throw an exception.

    Just to repeat, Spring works with beans. Its primary purpose is to manufacture and wire together beans. So abstract objects are anathema to it.
     
    Claude Moore
    Bartender
    Posts: 1381
    39
    IBM DB2 Netbeans IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Initial typo apart, the following code:



    Of course the injected object IS an instance of the class SampleService - no abstract objects at all.
    A more complex use case may involve a FactoryBean:



    Sorry if I bother you...
     
    Tim Holloway
    Saloon Keeper
    Posts: 28414
    210
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Yes, if you introduce a custom bean factory into your mix you can make it decide whether to return a remote interface object or a local object, sure. No problem.

    Most of the time you'd prefer to have the app make the choice and use regular injection logic without requiring Spring's help, but I can definitely see cases where you would prefer to abstract it into the general bean wiring process.
     
    Claude Moore
    Bartender
    Posts: 1381
    39
    IBM DB2 Netbeans IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Tim Holloway wrote:Yes, if you introduce a custom bean factory into your mix you can make it decide whether to return a remote interface object or a local object, sure. No problem.


    Thanks. And  does the returned bean follow the whole lifecycle of a "normally" injected bean ? (i.e: could its methods be declared @Transactional, can it have a scope etc) ?
     
    Tim Holloway
    Saloon Keeper
    Posts: 28414
    210
    Android Eclipse IDE Tomcat Server Redhat Java Linux
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    A Spring Bean Factory manufactures/locates and dispenses beans. After that, the beans are on their own. They're just POJOs with all rights and privileges thereof.

    And yes, you can definitely mark them @Transactional, etc. I use Spring to manage all my JPA beans. Or at least all the ones that JPA doesn't manage itself.
     
    A timing clock, fuse wire, high explosives and a tiny ad:
    We need your help - Coderanch server fundraiser
    https://coderanch.com/wiki/782867/Coderanch-server-fundraiser
    reply
      Bookmark Topic Watch Topic
    • New Topic