Is it possible to access the spring context outside of a spring-boot application? - spring-boot

I am trying to create a standalone database application which can offer CRUD operations to other applications/modules...
I am aware of the need to create the entities and services used by the application in another artifact since you cannot depend on a spring-boot application alone.
But, can one get the runtime spring-configuration of a spring-boot application? So one can access a service that is deployed on my application?
For best through-put I am looking for a way to use services on a running spring-boot database application on the same JVM in order to minimise overhead...

RMI
What you want is technically it is possible using basic Java RMI (remote method invocation), you just register the bean as the implementation instance and share the interface between the two JVMs, either on localhost or even on different machines.
Spring even gives some additional support for this using RmiProxyFactoryBean, see Spring Remoting RMI article.
From above article, you can export it, using:
#Bean
RmiServiceExporter exporter(CabBookingService implementation) {
Class<CabBookingService> serviceInterface = CabBookingService.class;
RmiServiceExporter exporter = new RmiServiceExporter();
exporter.setServiceInterface(serviceInterface);
exporter.setService(implementation);
exporter.setServiceName(serviceInterface.getSimpleName());
exporter.setRegistryPort(1099);
return exporter;
}
and import it, using:
#Bean
RmiProxyFactoryBean service() {
RmiProxyFactoryBean rmiProxyFactory = new RmiProxyFactoryBean();
rmiProxyFactory.setServiceUrl("rmi://localhost:1099/CabBookingService");
rmiProxyFactory.setServiceInterface(CabBookingService.class);
return rmiProxyFactory;
}
Then you can use it in your application context based on your interface.
However I would not suggest to share beans like this because it has the same problem RMI has.
Shared library
Another way to do what you want is to create a shared library that can be included in other projects.
If all the project, which want to use it are Spring Boot application you can create a Spring Boot starter, see Spring documentation.
This way, other applications just have to add the dependency and they already has access to the beans in their application context, as well as the shared domain objects.
If other application use just regular Spring, they can just #Import your main configuration class.
If other apps are using Java, but not Spring, you can still use Spring inside, just provide a factory, which creates an internal Spring context.
REST service
If other applications are not written in Java, your best bet is to expose a REST interface for them to use the database applications.

Related

Bind Spring datasource to JNDI

I have a spring boot based spring application that is deployed into an external tomcat instance.
The application creates few datasources. These datasources are added to entitymanager and transaction manager is setup accordingly.
However, recently we have integrated programmatically an ETL tool that works with JNDI datasources. The ask here is to bind the current spring datasources into the JNDI tree at startup.
I have tried to create an initial context post datasource bean creation and bind the datasources there, however, i do see a NoInitialContext exception being thrown.
How can i bind these spring datasources into the JNDI tree of the external tomcat? Appreciate the help!
Note: I cannot/am not allowed to edit the tomcat configuration as it is initialized from a PaaS template. So need to work on the approach of being able to bind to the JNDI tree from within the application.
AFAIK this is not possible. Take a look at the JEE spec:
The container must ensure that the application component instances have only read access to their naming context. The container must throw the javax.naming.OperationNotSupportedException from all the methods of the javax.naming.Context interface that modify the environment naming context and its subcontexts.
Jakarta EE Spec - Resources, Naming, and Injection
See this SO post has some interesting code examples if you want to play around.
IMHO you can achieve what you want by creating JNDI resources and passing these to the EntityManger/Spring. But that means that the configuration would exist outside of Spring completely. So this may not do what you want to do.

Using SpringBoot as an application loader

I have a spring-boot app that acts as a small framework for other apps. It provides a couple of JMS queues and a DAO layer to retrieve and store data from a common set of data stores. The problem is that the original developer of this framework app is scanning all the package "com.mycompany" (rather than com.mycompany.framework) so that it can load the beans of the specific app that may be declared under com.mycompany.myapp1 or com.mycompany.myapp2 an which JARs are bundled together with the JARs of the framework.
We only load a single app in the JVM (app1 or app2), but these apps may share other libraries and sometimes we end up with beans in the context that we don't need. (these may be needed in app1 but not in app2)
So, what would be your advice ?
My problem is similar to what was described here:
https://github.com/spring-projects/spring-boot/issues/3300
I am debating if each app should be aware of the framework and load it. Or if the framework should instantiate a class loader and create a new Spring context loading the app specific code as suggested in the link above.
Perhaps you should consider leveraging some of Spring Boot's Auto Configuration capabilities such as #ConditionalOnProperty or #ConditionalOnClass in your framework. That way, you can only actually enable certain beans if and when the application using your framework takes some specific action (e.g. has a given jar on the classpath, or sets a configuration value). For reference check out: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-developing-auto-configuration

Is it possible to change properties of a bean (defined for a service) and reload it when the application is running?

I migrated a simple CRUD application developed in Java using OSGi to Grails using Spring. I converted all the REST resources to controllers and HTML pages to GSP views, keeping the rest of the Java code as such.
I have a DBService service, which helps connect to the DB and run queries on it, and a ProcessorService, which uses DBService to perform business operations.
I created beans for these services as follows:
beans = {
dbServiceBean(DBService, "test_db")
processorServiceBean(ProcessorService,ref("dbServiceBean"))
}
Everything is working fine with the above config.
Now, I want the application to be able to process multiple DBs (multi-tenant). I won’t know the name of the DB beforehand, however, so I can’t have a list of dbServiceBeans predefined.
Is it possible to rebuild/reload a bean with dynamically obtained values and reload the dependent beans as well when the application is running?
Grails already have the option to use multiple datasources.
You can change your DBService to get a connection from the datasources configured. If you just change it to a Groovy class and put it in grails-app/service you will get transactions and dependency injection by attribute name for free.

Which Spring Entity Manager Factory should I use?

There are two entity manager factory beans in Spring that would work for my application. The org.springframework.orm.jpa.LocalEntityManagerFactoryBean and org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean. I am using Spring 3.0 with EclipseLink JPA 2.2.
What I've read about these two are that they are the same. Except that LocalContainerEntityManagerFactoryBean uses weaving. What is it? And, why would I want to use it?
"Weaving" is a term for program transformation, usually heard around "aspect oriented programming" area. The transformation is usually not done to the source but the .class (the bytecode) and a techy term for changing bytecode is "bytecode instrumentation".
why would I want to use it?
The JPA implementation you use may rely on such bytecode instrumentation for some features it provides and hence you might be forced into using it.
And for weaving to work correctly, you might need to specify a -javaagent: For eg,see section 'Eclipse Junit' here.
It looks like LocalContainerEntityManagerFactoryBean allows you to configure a weaver implementation ( one of DefaultContextLoadTimeWeaver, GlassFishLoadTimeWeaver, InstrumentationLoadTimeWeaver, OC4JLoadTimeWeaver, ReflectiveLoadTimeWeaver, SimpleLoadTimeWeaver, WebLogicLoadTimeWeaver
at an XML file, instead of relying on a -javaagent runtime argument.
This configuration isn't such a big factor, I'd guess.
Other features which the docs explain, sound like deciding factors.
LocalEntityManagerFactoryBean bootstrap is appropriate for standalone applications which solely use JPA for data access. If you want to set up your persistence provider for an external DataSource and/or for global transactions which span multiple resources, you will need to either deploy it into a full Java EE 5 application server and access the deployed EntityManagerFactory via JNDI, or use Spring's LocalContainerEntityManagerFactoryBean with appropriate configuration for local setup according to JPA's container contract.
If you plan on deploying your application to an Application Server and letting the Application Server manage the Entity Manager Factory and Transactions than the LocalContainerEntityManagerFactoryBean might be a better option. If you rather have the Application be more isolated, than the LocalEntityManagerFactoryBean would be more appropriate.
This blog can help provide more insight: http://second-kind-demon.blogspot.com/2011/06/spring-jpa-java-ee-jboss-deployment.html

Spring 3.1 Environment Abstraction and EJB integration

I'm trying to use the new environment abstraction in our Java EE/EJB application. We're already using SpringBeanAutowiringInterceptor to inject Spring Beans into EJBs by using the standard beanRefContext.xml to bootstrap the shared application context for the Java EE app.
Now I've written a concrete Environment class (derived from Spring 3.1 AbstractEnvironment) which uses some kind of environment "auto" detection to select the correct active profile for the machine on which the app is running on. With this feature our app can be delivered with all properties for all environements (inside the ear) and auto select the correct property set.
The problem is now that org.springframework.beans.factory.access.SingletonBeanFactoryLocator.createDefinition(String, String) builds a bean factory group around the beans/context in beanRefContext.xml using the StandardEnvironment class, and I see no simple way to configure the environment implementation to use here without rewriting(overwriting) some part of SingletonBeanFactoryLocator.
Is there a simple solution for this, or is s.th. planned in the direction for supporting to specify the Environment implementation with the EJB/Java EE integration?

Resources