Support for caches (and other injectables)

33 views
Skip to first unread message

Jim Marino

unread,
Sep 7, 2015, 9:35:04 AM9/7/15
to fabric3
Hi,

I've started looking into how best to enable caching in 3.0 and I wanted to get feedback and see if others had ideas on how to best approach this. Here are my thoughts.

I'd like to see if we can develop a simple, generic mechanism for supporting a variety of cache providers in the runtime as opposed to having specific extensions for each provider (e.g. EHCache, Infinispan, Hazelcast, etc).

My thought is to use the DSL to configure cache providers in the following way:


public class DSLProvider {

   @Cache(name="MyCache")
   public static CacheProviderInterface createCache() {
      // ... create the cache and return it programmatically

   }

}


The cache can then be injected on a component:

@Component
public class MyComponent {

   @Cache(name="MyCache")
   protected CacheProviderInterface cache;

}


This could be supported by provided a generic feature that allows users to place other annotations on a provider method (i.e. not just @Cache) and have the returned instance injected anywhere that other annotation is used. 

Does this approach sound like a good one or do others have alternative ideas?

Jim


 

Tomáš Fecko

unread,
Sep 7, 2015, 10:16:19 AM9/7/15
to fabric3
- I like that approach...
If I get it right, you want to allow users to create custom annotations, that can be than used in provider and in code?

that would mean, that in e.g. redisson provider, which is redis client implementation which provides, java data structures like List, Map, Queue, Deque, Publish/Subscribe on top of Redis, I could create annotations like @DistributedList, or @DistributedSet and it inject the appropriate instance...

I would also suggest to allow to use dynamic parameters, like:

@Component
public class MyComponent {

   @Cache(name="MyCache")
   protected CacheProviderInterface cache;

}


@Cache
public static CacheProviderInterface createCache(String name) {

Teemu Hiltunen

unread,
Sep 8, 2015, 2:40:00 AM9/8/15
to fabric3
Hi!

How does this approach relate to using Spring-implemented SCA-components and Spring's @Cacheable etc annotations in them? Would there be some kind of wrapper thing that would provide Spring Cache interfaces so that those Spring annotations would still work but would be connected to this new fabric3 cache framework instead of connecting directly to EhCache cache provider for example? Or would using Spring @Cacheable be a totally different thing apart from this?

In Spring one does something like this for EhCache annotation-based caching (Spring XML - Java DSL-based configuration should also work - in fabric3 too?):

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

        <cache:annotation-driven />
        <bean id="cacheManager"
              class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>

        <!-- EhCache library setup -->
        <bean id="ehcache"
              class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>
</beans>

Would this new fabric3 framework provide implementations of Spring's org.springframework.cache.Cache and org.springframework.cache.CacheManager interfaces so that the configuration above would be something like this:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

        <cache:annotation-driven />
        <bean id="cacheManager"
              class="org.fabric3.cache.spring.SpringCacheManager" p:cache-manager-ref="ehcache"/>

        <!-- EhCache library setup -->
        <bean id="ehcache"
              class="org.fabric3.cache.spring.ehcache.SpringEhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>
</beans>

Or how would it go?


--teemu

Jim Marino

unread,
Sep 8, 2015, 4:14:42 PM9/8/15
to fabric3
Forwarding to the list as I hit "reply-to" instead of "reply-all"...

Jim

---------- Forwarded message ----------
From: Jim Marino <jim.m...@gmail.com>
Date: Tue, Sep 8, 2015 at 10:13 PM
Subject: Re: Support for caches (and other injectables)
To: Teemu Hiltunen <hiltune...@gmail.com>


Hi Teemu,

For Spring, I'd like to let applications use the Spring approach instead of an alternative because that is what they are used to. So, for cases where Spring is used, I would say the application should construct their application context as you show above.

One thing I've also been thinking about it changing the approach to Spring support to make Fabric3 more transparent. Currently, users need to write composites that have components which point to application context files. I was thinking this could be greatly simplified if Fabric3 were to support loading of application context files (or annotation scanning) directly. So, instead of creating a JAR with a composite file and other SCA artifacts, users could just create a JAR file with just Spring artifacts in it (e.g. application contexts or JavaConfig). Fabric3 would recognize the Spring JAR and load the appropriate bean contexts.

Specific SCA features such as eventing and remote bindings could be configured using Java annotations on the Spring beans or with namespace extensions in Spring XML.

Do you think that approach would be valuable and provide more flexibility than what we currently have?

Jim
 

--
You received this message because you are subscribed to the Google Groups "fabric3" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fabric3+u...@googlegroups.com.
To post to this group, send email to fab...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fabric3/d6458a79-0630-47c8-9baf-ac00c4c69a20%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


Jim Marino

unread,
Sep 8, 2015, 4:15:08 PM9/8/15
to fabric3
Forwarding to the list as I hit "reply-to" instead of "reply-all"...

Jim

---------- Forwarded message ----------
From: Jim Marino <jim.m...@gmail.com>
Date: Tue, Sep 8, 2015 at 10:04 PM
Subject: Re: Support for caches (and other injectables)
To: Tomáš Fecko <tomas...@gmail.com>


Hi Tomas,

Yes, that's correct. Users can create custom annotations and use them to inject instances along with support for matching. To achieve this, I was thinking of having a meta-annotation use as @Injectable (I'm not sure about the name, I'm open to suggestions) on the custom annotation:

@Injectable
@Target({METHOD, FIELD, PARAMETER})
public @interface Cache {

    @Qualifier
    String name();
}

The @Qualifier can be used to mark an annotation attribute that  is used for matching.

I think that will open a range of possibilities for applications to inject all types of things. Does that fit with what you are thinking?

Jim


--
You received this message because you are subscribed to the Google Groups "fabric3" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fabric3+u...@googlegroups.com.
To post to this group, send email to fab...@googlegroups.com.

Teemu Hiltunen

unread,
Sep 9, 2015, 2:12:28 AM9/9/15
to fabric3
Hi Jim!

Making Spring more transparent sounds like a wonderful idea to me! Would it be possible to push that idea a bit further and create a Fabric3 Spring Boot application? A single executable jar file with all the Spring AND SCA goodies in it. For easily creating small-footprint microservices with SCA capabilities. I know there are some tools in Fabric3 already for this kind of feature - creating an executable jar (or was it just a zip package?) and packaging all necessary stuff into it but as I - and I think many others - are more familiar programming Spring than Fabric3 it might help them to get up and running in SCA world if they could easily spin up a Spring Boot app and wire them together as a SCA domain. Maybe this kind of microservice apps could be dockerized and deployed into a Kubernetes or such platform.

And for the idea that keeping using Spring Caching "clean" sound also good to me.


--teemu

Jim Marino

unread,
Sep 15, 2015, 9:48:53 AM9/15/15
to fabric3
Hi Teemu,

I agree trying to make F3 easier for people with Spring applications is really important.

I've been looking at Spring Boot lately and there are a couple of things I have some questions about. I'm curious what you and others think:

1. Dealing with Spring boot dependencies seems to be a bit complex. For example, it appears you need to chose the correct POM (when using Maven) to include the correct combinations. This could be the result of simply having a lot of options. In your experience has it been a problem setting up a Spring boot project that isn't trivial, that is, uses a number of features not included in the base distribution?

2. Deployment time configuration. I like the idea of a single JAR deployment artifact but have you had issues with configuration at deployment time? My understanding is Spring Boot can refer to external properties files for deployment-time overrides. This seems to result in two deployment artifacts for systems that cannot have all of their deployment information encapsulated into a single JAR. Have you run into this?

I'm asking the above because I'm trying to understand as much as I can about how people who are Spring-centric like to structure their apps.

In terms of getting this to work in F3, we have experimented with an embedded distribution of F3 that we could potentially repurpose into working inside of Spring Boot. One thing I need to look at is handling classloader isolation and how best to get all of the F3 JARs packaged into a Spring Boot app - hence the two questions above.

Jim
 

Teemu Hiltunen

unread,
Sep 16, 2015, 1:06:05 AM9/16/15
to fabric3
Hi Jim!

1. If you mean with complexity those numerous Spring Boot "starter poms" (http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-starter-poms) I guess we could create our own Spring Boot starter pom for fabric3 (fabric3-spring-boot-starter)? I am not sure what it would include though. But I do know that one can combine those starter poms based on what the project needs (eg. include security and data-mongodb and actuator etc). I have had no trouble - so far - with this in my Spring Boot projects. They have been fairly simple though; eg. a RESTful interface for MongoDB or a Camel routing application.

2. For the external configuration (http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config) there are lots of options. If we want to have OS environment variables (eg. for a Docker container deployment) it can be done. Or an external properties file. Or a bundled properties file. Or command line arguments. It is possible to use Spring Profiles too (eg. "dev", "test", "prod" etc) and bundle all different properties files into the jar. I have usually used command line arguments in case I need to override some defaults bundled into the jar (application.properties).

I have no idea how difficult task it would be to get fabric3 to work as a Spring Boot app (especially the classloader issue) but if it can be done I think it would greatly benefit both fabric3 and SCA in general.


--teemu




2.

Jim Marino

unread,
Sep 16, 2015, 4:15:06 AM9/16/15
to fabric3
Hi Teemu,

Thanks for your input. That gives me a number of data points to go on. Here is how I was thinking of proceeding:

1. Bootstrap the Fabric3 runtime in a Spring Boot jar. This may take some investigation to get working but I'm hoping to reuse the node runtime to do this. There are probably a number of subtasks here, including:

a. Deciding how classloaders will work
b. Figuring out how Fabric3 extension jars can be packaged with Spring Boot

2. Once #1 is done, support F3/SCA reference injection by creating Spring namespace handlers and bean post-processors for injecting Fabric3/SCA references into Spring beans. The namespace handlers would be used to create F3/SCA references in Spring XML while the bean post-processors will be used to handle annotation-driven beans (e.g. putting binding information on the Spring @Autowire or target annotation) 

3. Support F3/SCA service export with handlers and post-processors.

So the next question is: do you (opinions from others are welcome too) think supporting Spring Boot in this manner is more important than supporting native Spring applications in the F3 runtime? This can hep prioritize the work.

Jim 



Teemu Hiltunen

unread,
Sep 16, 2015, 6:01:27 AM9/16/15
to fabric3
Hi Jim!

If I think about my own recent projects and those that might begin soon here's how I would like to use SCA in them:

1. use microservices acrhitecture (Spring Boot is a good platform candidate for this)

2. connect multiple services that belong to the same system together as a single SCA domain, so that they can easily be wired together. They should still be easily replaceable (upgrade = start up new version, shut down old version) and configurable (preferably no XML configration needed at all or just some minimal configuration (composite-file?)) and be as much independent as they can.

3. there would be services that poll a SQL database and publish events to message queues (topics), services that receive events via their SOAP WS interface, services that receive events via their RESTful WS interface, services that subscribe messages from topics and call perhaps some external systems (outside the SCA domain) via their WS interfaces, services that offer an WS interface to external systems and store their data into a no-SQL database.

4. most inter-service communications would be done asynchronically via message queues but there might some need for synchonous communications with WS interfaces (SOAP / RESTful)

5. the apps could be wrapped as a container (eg. Docker) and be deployed, administrated (automatic load-balancing etc) and monitored with tools like Kubernetes and fabric8


Does that sound like a viable use case for SCA/fabric3 and Spring Boot? And does this answer your question? This kind of system can be constructed with eg. Apache Camel and Spring Boot (as we are currently planning to do but plans can still change and nothing is decided, but the old system uses heavily Camel so it would come more naturally in this particular project) and it would support all the mentioned scenarios quite well. But it would still need "hard-wiring" things together with properties files and hand-written WS-clients etc. What I like in SCA is its ability to make that kind of hard-wiring go away and make the wiring transparent and protocol-independent.

If a SCA application could be constructed with f3 and Spring Boot, would it need to bundle its own Jetty (f3's Jetty that is) or could it use the one that Spring Boot can offer (Tomcat or Jetty)?


--teemu

Tomáš Fecko

unread,
Sep 28, 2015, 10:02:52 AM9/28/15
to fabric3
I think we can use some of the annotations from JSR 107 

Jim Marino

unread,
Oct 10, 2015, 11:08:09 AM10/10/15
to fabric3
OK I managed to do some more work on getting Fabric3 to play well with Spring Boot based on suggestions by Teemu and Tomas. Sorry for the delay but we've had a lot of work on projects recently.

I used the previous work that was done on the Fabric3 Node runtime and fortunately it will integrate nicely with the way Spring Boot expects things to work. I don't have everything working yet but I have started on a sample repo (based on Gradle but the Maven equivalent should work as well) here:


The developer workflow is as follows:

1. Create a project using the Gradle Application plugin (later I will change this to the Spring Boot plugin, see below).

2. Add the following core dependencies to your project:

    compile group: fabric3Group, name: 'fabric3-node', version: fabric3Version , transitive: false
    compile group: fabric3Group, name: 'fabric3-node-extensions', version: fabric3Version, transitive: false 

These will place two archives (a Jar and Zip) in the application /lib directory. Transitive is important so the app plugin does not pull down the entire dependency tree. The two archives contain all of the core dependencies required to boot F3. I like this approach because it avoids polluting the /lib directory with tons of Jars and also provides classpath isolation from the application classes. 

3. Add any profiles you want to configure the runtime with to your project:

    compile group: fabric3Group, name: 'profile-rs', version: fabric3Version, classifier: 'bin', ext: 'zip'

This will add the RS profile Zip to the /lib directory.

4. Create a Main class and configure your project to use it:

mainClassName = 'org.fabric3.samples.node.StartSample'

The main class can boot the runtime, use the DSL (or composites) to deploy services or dynamically wire to services. For example:

public static void main(String... args) throws Exception {
        Fabric fabric = Bootstrap.initialize();
        fabric.addProfile("rs");  // enable the REST profile
        fabric.start();

        Domain domain = fabric.getDomain();
        domain.deploy("Foo", new FooServiceImpl());
        
        FooService service = domain.getService(FooService.class);
        service.hello();
        fabric.stop();
    }

----------------------
After that is complete, the main class can either be launched from the command line using the app start script created by Gradle or from within the IDE.

For next steps, I plan on following:

1. Get the above setup working in a single JAR file using the Spring Boot plugin
2. Integrate Fabric3 into Spring application contexts so Spring can transparently inject SCA proxies into beans without having to use SCA annotations.
3. Create Spring bean post-processors so that Spring Beans annotated with SCA annotations will be enabled. For example, enable a service endpoint over REST, ZeroMQ, etc. 
4. Integrate the Spring Boot embedded Servlet container with the Fabric3 node runtime so Fabric3 can transparently export service endpoints (required for above).

I'm hoping this will make the development experience very simple. Let me know your thoughts.

Jim  




Teemu Hiltunen

unread,
Oct 12, 2015, 3:52:31 AM10/12/15
to fabric3
Hi Jim!

What you have done and what you are still planning to do sound great!

What I also would like to see and read is some kind of small proof-of-concept use case for this. If you had time to write a blog entry perhaps describing such a use case? That would be really nice and helpful for me and for others too I think.


--teemu
...

Jim Marino

unread,
Oct 12, 2015, 5:56:56 PM10/12/15
to fabric3
Hi Teemu,

A blog write-up is a great idea. Give me a few days to do that. In the meantime, I managed to get F3 integrated and working with Spring Boot - and from a single JAR :-)

I've created a sample here: 


An application can create a standard Spring Bean and add JAX-RS or Fabric3 binding annotations (e.g. JMS, ZeroMQ, Web Services) to have the bean exported as an endpoint:

@EndpointUri("ui")
@Path("messages")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
@Component  // the Spring annotation
public class RestService {

    @GET
    @Path("hello")
    public String hello() {
        return "hello";
    }

}

I created a Fabric3 Spring Boot module that simplifies getting a Spring Boot application running with F3:


This can be used as follows (taken from the sample):

   public static void main(String... args) {
        // sets the Spring boot servlet container port
        System.setProperty("server.port", "8193");

        SpringApplication application = new SpringApplication(StartSample.class);

        // bootstrap the Fabric3 runtime with the REST profile
        Fabric fabric = Bootstrap.initialize();
        fabric.addProfile("rs");

        // define the context path for HTTP/S endpoints
        String contextPath = System.getProperty("fabric3.context.path", "/fabric3");
        Map<String, Object> properties = Collections.<String, Object>singletonMap("http.context", contextPath);

        // initialize the Spring boot application with Fabric3
        SpringApplicationConfigurer.initialize(application, fabric, properties);

        // run the application
        ApplicationContext context = application.run(args);

        // publish the remote endpoints and start receiving requests
        SpringApplicationConfigurer.startFabric(context, fabric);
   }

Next steps will be to support injection of remote services and channels, something like:


@Component // Spring annotation
public class SpringBean {
    
    @ZeroMQ  // Fabric3 annotation
   protected RemoteService service
   
    @Producer   // Fabric3 annotation
   protected SomeChannel channel;

    @Consumer // Fabric3 annotation
    public void onEvent(Event event) {...}

}

In the above Fabric3 binding annotations are used to wire remote services. I think that is OK given there is not really a Spring equivalent - let me know if there is or you think a different way should be supported.

For @Producer we could possibly user @Autowired but I think the semantics are slightly different. Also, I can't find a Spring equivalent to @Consumer so my opinion is that we should preserve those two annotations, which connect beans to channels. Again, let me know if you think I have missed something.

I think this should all hook up nicely with Camel as well since routes could be beans that are injected with Fabric3 services (or exposed as endpoints).
 
Eventually, if we support Reactive Streams (http://www.reactive-streams.org/) with our channel implementations (something I would like to get to), we should be able to deliver an interoperable event-based programming model that can be switch from local to remote bindings without changing application code.

Jim
 









Reply all
Reply to author
Forward
0 new messages