πŸ“œ ⬆️ ⬇️

Using Spring in the OSGi Container


There is hardly a Java developer who does not know what the Spring Framework is. One of the basic technologies of this framework is the IoC container and AOP support. These technologies allow you to successfully break the application architecture into separate layers, both at the class level and at the object layout level at run time. It would seem that the application is perfectly structured into elements / layers, but in essence it remains monolithic. Capless at runtime! Only within the framework of this framework, there are no universal solutions to this problem. Slightly fewer Java developers have heard of OSGi. This is the specification of modular systems for the Java platform. Using a specific implementation of this specification as the basis of an application allows you to make it modular, both at runtime and at the physical (file) level. About the synergy of these technologies and will be discussed in this article.

Spring framework


I expect that the reader is familiar with this framework at least at the level of reading the first ten chapters from the official manual. It is not possible to describe all this in one article. Therefore, I refer all those who need it to the official leadership. Below is just a brief help on the main components of the Spring Framework.

Many different subprojects from the SpringSource portfolio.

Modularity


Ideally, a truly modular program should consist of elements that have the following pronounced features: weak connectivity (interaction through a well-defined interface, easy replaceability, repeated use), encapsulation (the module is viewed from the outside as a black box with a specific interaction interface), dynamism ( ability to change multiple modules at run time). Java allows for weak connectivity and encapsulation, both at the class level and at the package level. Of course, there are ways to break encapsulation at the level of access modifiers (private, protected) using reflection (Reflection API) and thereby link your code with the internal mechanisms of third-party code, or use the mechanisms for changing the code of classes (javassist, cglib, changing the code of classes manually and .d.), but it is rather khaki. But what about the dynamism, that is, the ability to replace modules at run time. In this area things are worse. You can of course implement dynamic support by redefining class loaders (ClassLoader) with your implementations, but this is a very large amount of work that implementers of OSGi have already done for us. Any OSGi container already supports modularity at the core architecture and API level.
')

OSGi


Open Services Gateway initiative is a specification with many implementations. The main open source implementations are Apache Felix, Equinox and Knopflerfish. This specification describes a modular system that can dynamically bundle various modules (bundles). The composition of the modules may change at run time. The interaction between the modules is carried out using services that are registered in the Service Register. Modules have a life cycle that consists of several states (INSTALLED, RESOLVED, STARTING, ACTIVE, STOPPING, UNINSTALLED). The life cycle of the module is managed by the OSGi container.


Module state diagram

The OSGi-module (bundle) must have additional metadata in the META-INF / MANIFEST.MF file. Some of the main ones are presented below:


How did you get the opportunity to use Spring with OSGi


OSGi implementations allow you to create truly modular Java programs. The Spring Framework makes it possible to get rid of manual support for connections between objects through the use of an IoC container, extend the functionality of existing classes using AOP, and use any related technologies from the SpringSource portfolio. Combining these technologies should bring considerable benefits in software development. Not surprisingly, this thought came to mind of several people from Interface21 (later SpringSource) in 2006 and they were able to connect people from OSGi Alliance, BEA, Oracle, IBM to the development. As a result of joint efforts, the Spring dm product appeared under the SpringSource wing, later this product gave life to the Blueprint specification in the OSGi Service Platform Service Compendium. Its codebase was taken over by the Eclipse Foundation and was named Gemini Blueprint. SpringSource also released dm Server, now its codebase has become a project of Virgo in the Eclipse Foundation.

Gemini Blueprint Architecture (Spring DM)


So how does Gemini Blueprint allow you to use the Spring Framework in an OSGi container? To answer this question, you need to consider the main points of the Gemini Blueprint architecture.

The basic element of the architecture is extender (implementation of the OSGi pattern extender). The Extender monitors the launch events for new modules (bundle) in the OSGi service platform and checks whether this module supports the blueprint specification. If the module supports this specification, extender creates the Spring context of the module and initializes it. Thus, each Spring module has its own Spring context. In addition, the extender calls the code that is responsible for publishing Spring-beans as OSGi services and getting links to OSGi services, and so on.


Extender function diagram

All information on the basis of which the extender creates the context is taken from the configuration as xml files. Here it is necessary to emphasize the existence of two possible configuration options spring and blueprint. Both options are very similar, but if the first corresponds to the native Spring configuration with additional named spaces for configuring services, the second is clearly defined by the Blueprint OSGi specification of the Service Platform Service Compendium. In fact, there is a third option, backward compatible with Spring dm.
For a more detailed study of the architecture, see the links at the end of the article.

Gemini Blueprint and OSGi usage example



As an example of use, we will write a GUI application with two implementations of services and one client. This example will demonstrate how the use of Gemini Blueprint makes it easier to develop OSGi programs. First, we do not need to use the OSGi API. Secondly, the issue of dynamic services is solved independently by Gemini Blueprint, we only need to take care of the application logic. Third, we will use the Spring Framework to build the application.

The application is built using maven 3. The file structure of the project is as follows:

 blueprint example consumer── consumer β”‚ β”œβ”€β”€ pom.xml β”‚ └── src β”‚ β”œβ”€β”€β”€ main β”‚ β”‚ β”œβ”€β”€ java β”‚ β”‚ └── blueprint β”‚ └─── β”‚ β”‚ β”‚ └─── ConsumerFrame.java Consumer.java resh β”‚ β”‚ β”œβ”€β”€ Consumer.java RefreshListener.java spring β”‚ resources──resource MET β”‚ β”‚ resources───Resa Spring β”‚ MET Os── osgi-context.xml spring β”‚ └── spring-context.xml test └── test β”‚ β”œβ”€β”€ java β”‚ └─── β”œ date-producer β”‚ β”œβ”€β”€ pom.xml β”‚ └── src main β”œβ”€β”€ main β”‚ β”‚ β”œβ”€β”€ java blue β”‚ β”‚ └── blueprint example β”‚ β”‚ └──example example β”‚ β”‚ └─── dateproducer MET── META-INF spring β”‚ └── spring β”‚ β”‚ β”œβ”€ osgi-context.xml β”‚ β”‚ └── spring-context.  xml test └── test β”‚ β”œβ”€β”€ java β”‚ └── resources β”œβ”€β”€ int-producer β”‚ β”œβ”€β”€ pom.xml β”‚ └── src main β”œβ”€β”€β”€ main β”‚ β”‚ β”œβ”€β”€ java β”‚ β”‚ β”‚ └─ ─ blueprint β”‚ β”‚ β”‚ └── example int β”‚ β”‚ └── intproducer resources β”‚ β”‚ β”‚ ─── ProducerImpl.java β”‚ β”‚ └─── resources β”‚ β”‚ └───- osgi-context.xml spring β”‚ └── spring-context.xml test └── test β”‚ β”œβ”€β”€ java β”‚ └── resources β”œβ”€β”€ pom.xml producer── producer-api β”œβ”€β”€ pom.xml └─ Src main── main β”‚ β”œβ”€β”€ java blue β”‚ └──blueprint producer β”‚ └── example β”‚ β”‚ └─── producer β”‚ └── api β”‚ β”‚ └─── Producer.java └── resources β”‚ β”” ── META-INF └── test β”œβ”€β”€ java ── resources 


In the consumer, producer-api, date-producer and int-producer directories, the client projects, the service API, the implementation of services based on date and integer are respectively located. Sounds confusing? Do not worry, now we will sort everything out in order.

Each of the listed projects is a separate module (bundle) for the OSGi-container. The project producer-api contains only one file with the Producer interface. This is a typical example of allocating an OSGi application API to a separate module that all modules that need it will import. This module is not a blueprint module, because its purpose is only to provide the necessary classes.

To build all the modules used maven-bundle-plugin. This is a plug-in from the Apache Felix developers, which uses the Bnd utility (famous in OSGi circles). This plugin is configured as follows:

<plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>2.3.5</version> <extensions>true</extensions> <configuration> <instructions> <Bundle-Name> ${name} ${version} </Bundle-Name> <Bundle-SymbolicName> ${groupId}.${artifactId} </Bundle-SymbolicName> <Export-Package> blueprint.example.producer.api </Export-Package> <Import-Package>*</Import-Package> </instructions> </configuration> </plugin> 

The attentive reader should note that the names of the entries in the instructions section match the names of the specific headers for the OSGi-module metadata in META-INF / MANIFEST.MF. This is what they are, not only in their natural form, but in the form of bnd instructions. This utility is quite intelligent and can calculate dependencies by code and substitute them into the Import-Package section, as well as add various metadata. Based on its configuration and calculations, it generates a MANIFEST.MF. In this case, we define only the main headers.

In order for the extender to recognize the module as a blueprint module, by default, the following rule is used: the module must have xml configuration files in the META-INF / spring directory, or the Spring-Context header indicating the location of the configuration must be present. The projects listed above use two configuration files in the META-INF / spring directory. The first with the prefix "osgi-" contains a blueprint-specific configuration. The second one with the prefix "spring-" contains the usual configuration for the spring-application.
Consider the implementation of services based on date and on the basis of an arbitrary integer:

 @Component public class ProducerImpl implements Producer { @Override public String produceString() { return new Date().toString(); } } @Component public class ProducerImpl implements Producer { private Random random = new Random(new Date().getTime()); @Override public String produceString() { return String.valueOf(random.nextInt()); } } 

The service in our training example is just a class with one method String produceString (), which returns an arbitrary string. In the first case, the localized date, in the second line with an arbitrary integer. In the spring configuration of these modules, the process of scanning annotated classes is specified. The osgi configuration registers the service.

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <context:annotation-config/> <context:component-scan base-package="blueprint.example"/> </beans> <?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.eclipse.org/gemini/blueprint/schema/blueprint" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.eclipse.org/gemini/blueprint/schema/blueprint http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd "> <service id="producerService" ref="producerImpl" interface="blueprint.example.producer.api.Producer"/> </beans:beans> 

Here is the promised example of simplifying the life of a developer. There is no need to use the OSGi API to register the service, you just need to fill in the xml configuration.

It is time to consider the last module. The client of our services displays a GUI form with a text display field and a value update button. Let's take a look at the client code.

 @Component public class Consumer { @Autowired private ConsumerFrame consumerFrame; @Autowired private Producer producer; @PostConstruct public void start() { consumerFrame.setRefreshListener(new RefreshListener() { @Override public String refresh() { return producer.produceString(); } }); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { consumerFrame.setVisible(true); } } ); } } 

Consumer class is very simple. It contains two attributes that are injected by the container. This is a form object and a link to our service. Further, in the method that is called after the construction of the object, a listener of the update event is registered with the service access code and the form display code on the screen. The spring configuration of this project looks identical to the one presented above, and the osgi configuration looks like this:

 <?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.eclipse.org/gemini/blueprint/schema/blueprint" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.eclipse.org/gemini/blueprint/schema/blueprint http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd "> <reference id="producer" interface="blueprint.example.producer.api.Producer"/> </beans:beans> 

In this configuration, a link to the service is registered. By default, this service is mandatory, and all calls to it, in its absence, will be blocked for a certain interval, after which an exception will occur. This behavior is completely configurable.

Programmers familiar with the Spring Framework probably had a question. How does the link to the service ensure the dynamism of this service? After all, all objects are configured at the download stage (eager), or at the appeal stage (lazy). What will happen if the producer link is no longer relevant due to the disappearance of the service. Answer: blueprint takes care of this. In fact, a proxy object is injected into the service as a reference to the service, which serves the dynamism. This object provides call blocking behavior as well as generating an exception.

In the archive with the source code, in addition to it there is a directory with a configured equinox container and all the necessary libraries (equinox-for-example). I think this will facilitate a quick start. To start the container, you need to go to the directory with it and execute the command:

 java -jar org.eclipse.osgi_3.6.2.R36x_v20110210.jar -console

After it, messages from initializing modules will appear on the screen. And finally, the equinox command line prompt. After entering the ss command, the output should be identical to the one shown below:

 osgi> ss

 Framework is launched.

 id state bundle
 0 ACTIVE org.eclipse.osgi_3.6.2.R36x_v20110210
 1 ACTIVE com.springsource.net.sf.cglib_2.2.0
 2 ACTIVE com.springsource.org.aopalliance_1.0.0
 3 ACTIVE com.springsource.org.apache.log4j_1.2.16
 4 ACTIVE com.springsource.slf4j.api_1.6.1
                     Fragments = 5
 5 RESOLVED com.springsource.slf4j.log4j_1.6.1
                     Master = 4
 6 ACTIVE com.springsource.slf4j.org.apache.commons.logging_1.6.1
 7 ACTIVE org.eclipse.gemini.blueprint.core_1.0.0.RELEASE
 8 ACTIVE org.eclipse.gemini.blueprint.extender_1.0.0.RELEASE
 9 ACTIVE org.eclipse.gemini.blueprint.io_1.0.0.RELEASE
 10 ACTIVE org.springframework.aop_3.0.6.RELEASE
 11 ACTIVE org.springframework.asm_3.0.6.RELEASE
 12 ACTIVE org.springframework.aspects_3.0.6.RELEASE
 13 ACTIVE org.springframework.beans_3.0.6.RELEASE
 14 ACTIVE org.springframework.context_3.0.6.RELEASE
 15 ACTIVE org.springframework.context.support_3.0.6.RELEASE
 16 ACTIVE org.springframework.core_3.0.6.RELEASE
 17 ACTIVE org.springframework.expression_3.0.6.RELEASE

This is a list of all the modules currently installed. Now you need to install a test application. To do this, call the install file command: /// path_to_jar_module_file for each of the 4 modules (you can assemble the modules with the maven-package command). After that, run the start id command on the modules with the API, one of the services and the client. The test application window should appear on the screen.


Using date-producer

Then stop the service module with the stop id command and start another service. Refresh the window text field by clicking the refresh button.


Using int-producer

This completes the test case description. I want to emphasize that this is only a small part of the capabilities of Gemini Blueprint.

Application area



OSGi has long been something more than a standard for modular systems for embedded technology. In confirmation of the above, it is enough to give an example of such widespread OSGi-based projects like Eclipse and Glassfish. The Spring Framework has a strong position in the corporate market. What can the synergy of these technologies be used for? The main area of ​​application of this bundle, according to the creators, was to be the area of ​​corporate applications. Actually this is a successful attempt to bring OSGi into the corporate world. And now we have the opportunity to use OSGi in any corporate and application applications with the Spring Framework.

disadvantages



Despite the great advantages that a dynamic modular architecture offers, the bundle of Spring and OSGi has its drawbacks. I think the most significant drawback is the relatively low prevalence of this ligament. Of course, separately, these technologies do not cause doubts in their survivability, but the number of users using them together is not so great. Subjectively, the process of transferring projects from SpringSource under the wing of the Eclipse Foundation has slowed their development. The second drawback is the additional complexity that the use of this bundle adds to the project. And this is not so much the complexity of using these technologies, as the complexity added by compatibility problems with third-party libraries, or rather the problems of using them in an OSGi container.

Projects associated with the use of Spring in the OSGi container



Conclusion



I conceived the article as an introductory acquaintance with the technology of sharing Spring and OSGi. In order to fully describe all the information on the introductory part, I would need a much larger volume, so I suggest that the interested reader independently explore additional sources. In addition, I will be happy to answer questions on this wonderful technology (within the limits of my competence).

Additional sources



Archive with an example
Eclipse gemini
Bnd
OSGi Specifications
Spring framework
Spring dynamic modules
OSGi SpringSource Blog
Spring Dynamic Modules in Action
Eclipse virgo

Source: https://habr.com/ru/post/128653/


All Articles