How can we integrate a simple Java Project with a Spring Project? - java

I have a working Spring(MVC) project which I want to integrate with a simple java project (intended as daemon process).
I have added the Spring project to the simple Java Project in Eclipse but I am unable to invoke the Spring behavior for the service I want to use from the Spring-Hibernate project in the simple java project. All in am getting is a NullPointerException for the #Autowired entity in the Spring project. The Spring MVC project is already up and running while I am trying to run the daemon java program.
Though I am able to run the daemon process if I copy all the required service classes from the Spring project to the java project along with adding the required Spring jars (Basically making the original simple java as a Spring project now), I want to know how can Spring services be expoited by another simple java program.

You didn't state what spring version you are using. I assume it could be Spring3, but there should not be much differences in other versions ( > 2.5 ).
According to the Spring Framework Reference Manual (Chapter The IoC container) : Several implementations of the ApplicationContext interface are supplied out-of-the-box with Spring. In standalone applications it is common to create an instance of ClassPathXmlApplicationContext or FileSystemXmlApplicationContext
A little further in same chapter :
Instantiating a Spring IoC container is straightforward. The location path or paths supplied to an ApplicationContext constructor are actually resource strings that allow the container to load configuration metadata from a variety of external resources such as the local file system, from the Java CLASSPATH, and so on.
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
The javadoc of ClassPathXmlApplicationContext says that this constructor (specifying context locations Create a new ClassPathXmlApplicationContext, loading the definitions from the given XML file(s) and automatically refreshing the context.
I currently use that kind of standalone initialization in tests.

Related

Spring: Dynamic registrations of beans, rest-controllers, and more

I am new to Spring and would like to convert my existing applications to Spring Boot.
However, I am using a self-written module framework that allows me to add or remove components or additional functions of the application dynamically at runtime. The whole thing can be compared to plugin frameworks like PF4J or the plugin mechanism in Minecraft servers.
The advantage of this is obvious. The application is much more dynamic and certain parts of the program can be updated at runtime without having to restart the whole application.
Under the hood, a new ClassLoader is created for each module when it is loaded. The ClassPath of this ClassLoader contains the JAR file of the module. Afterwards, I load the respective classes with this ClassLoader and execute there an init method, which contains each module.
Now, I would like of course in connection with Spring that both the dependency injection in the modules functions, and that beans or, for example, rest controllers, which are in the modules, register with the module loading and unregister with the module unloading.
Example: I have a staff module. When I register it, the employee endpoint is registered and is functional. When I unload the module, the employee endpoint is removed again.
Now to my problem:
Unfortunately, I don't know how to implement this with Spring, or if something like this is even possible in Spring. Or are there even already other solutions for this?
I also read something about application contexts. Do I have to create a new application context for each module, which I then somehow "closed" when unloading the module?
I hope you can help me, also with code examples.
This post helped me a bit: https://hdpe.me/post/modular-architecture-with-spring-boot/
In short for each module a new ApplicationContext (e.g. AnnotationConfigApplicationContext) is created. If you want to share beans between the modules, you have to publish them to the main application context.
Beans can be registered at runtime by ((GenericApplicationContext) applicationContext).registerBeanDefinition(name, beanDefinition); at the main Application Context.
Another problem is that additional configurations are required, for example for #RestController or similar, in order for them to work. See other questions on StackOverFlow from me.

How to test Java Spring Boot application without #SpringBootApplication using JUnit?

I created a Spring Boot Java library which has a set of utilities that perform certain functions. This library can then be used across multiple applications that require its utilities. This library was designed as a Spring Boot application to allow these utilities to be injected in the application context.
Now I wish to execute a JUnit test on one of the utilities to ensure it is working correctly. However, since this application is basically a collection of utilities and not a stand-alone application, it does not have a main class or the main method annotated with #SpringBootApplication. Now, when I run the JUnit test, it comes up with an error.
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...)
Is it possible to test this Java library, or should we write the test cases only in the application that will be using this library?
I think there is some contradiction in what you say:
Created a Library...that was designed as a Spring Boot Application.
Library can be used across multiple applications that require its utilities.
If you implement "1" then there is a module with spring boot maven/gradle plugin configured to create a JAR of the application which is a library.
But if you have, say, module X that wishes to use your library, its impossible to add the dependency on your library in this module, spring boot JAR artifacts are not JARs in a Java Sense... So this won't work in both IDE and maven (I mean technically you'll have compilation errors).
Then you write something that completely makes sense: You say that the library by itself doesn't have a main class/#SpringBootApplication annotated class. From this I conclude that its not a spring boot application, but rather a spring boot starter module.
In this case you should not use #SpringBootTest annotation since it mimics the way of starting up the spring boot application (finds main class, scans the packages according to the package structure, loads the configurations and so forth). You don't need all this. Well, maybe technically you can still create a main class annotated with #SpringBootApplication and put it into src/test/java/.../ in a relevant package, but it doesn't really makes sense.
So basically you have two choices:
You can test the utilities without spring at all as if the utility is just a Java class, mock the dependency with Mockito and you're good to go. Since these tests are fast, it you be the best option.
You can run the integartion test by means of loading the spring context with all the required beans created by the application.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {MyLibraryConfiguration.class})
public class SampleLibraryTest {
#Autowired
private SomeBeanFromTheLibrary theBean;
#Test
public void testFoo() {
....
}
}
Now although you can use component scanning (in this case you'll need slightly different annotations), in the example I've assumed that you're using java config, register all the beans of the library there and create a spring.factories that uses this Java Configuration file to create an autoconfiguration (you add a dependency on the library in module X and it loads the beans defined in the library automatically).
This #ExtendsWith (#RunWith for junit 4) has nothing to do with Spring Boot, it behaves as a "plain" spring, you can autowire beans, create mock beans, there is caching of configurations, etc.

How to dynamically load jar files with application context by Spring (with no OSGi)?

I am going to create Java Application that can load external jar files at runtime by FileChooser. I am using Spring Framework, and I want to load jar file and its applicationContext.xml file and inject its dependencies dynamically. I tried to achieve this by OSGi, but it seems very complicated so that I am searching another appropriate variants.
I want to make something like Intellij IDEA plugin installation from the disk.
How can I do this? (After the jar file chosen restarting an application also accepted)
I realy like your approach, unfortunately spring has lifecycles that are strict. As you might know, spring autowires "beans" only. Exactly one lifecycle registers the different bean candidates. After that lifecycle spring (by default) does not accept new classes.
You must use the spring-osgi.
If you only need the CDI part out of spring, you might like to use a different CDI like red hat's jboss server.

Should I use the Spring Framework jar files or Spring Batch jar files while creating a java email batch program?

I am trying to create a java email batch program that sends an email with an attachment each day to a specific email address, and I have to use Spring as the framework for this program. It is not going to be a web application, but since I'm implementing Spring into this, how would I go about this? I am totally new to Spring (and Java for that matter), but am unsure of which direction I need to go. Which jar files do I need? Spring Batch or Spring Framework? Also, where can I download the jar files for Spring Framework? The spring.io site won't let me download those jar files.
I very strongly suggest you use a build tool that handles dependency management. Such tools are Ant+Ivy, Maven and Gradle. They will take care of downloading the appropriate jars based on your declaration of what dependencies you need and will take care of all the transitive dependencies.
One good way of getting started with Spring Batch is to follow this tutorial using either Maven or Gradle (the latter would probably be easier since you don't need to install it - the tutorial's code has a wrapper).
The tutorial uses Spring Boot which vastly simplifies Spring configuration (which is a serious benefit especially for someone who is new to Spring)
As others already told you, I personally would not start any spring based project (means: any project) without maven! You have so much benefits from it, not only depencency management.
To start a spring app outside an application context:
#Configuration
public class AppConfig {
//any bean configurations here
}
//your entry class
static void main(String args[]) {
//get a reference to the spring context. use this context throughout your app!
ApplicationContext ctx = new AnnotationConfigApplicationContext(CacheConfig.class).get();
//optain any beans from the context. inside these beans, you can use any spring feature you like, eg #Autowired
ctx.getBean(YourBean.class).executeMethod();
}
I'd recommend starting with Spring Boot which will handle all of that for you. As others have mentioned, pick a build tool (Maven or Gradle) and follow the guide we provide on building a batch application here: http://spring.io/guides/gs/batch-processing/.

Spring jar auto-loading

My project uses a simple plugin mechanism based on multiple application contexts defined in plugin jars. However for this to work i have to include all of the plugin jars on the classpath. It would be nice if Spring could automatically load jars and containing components on it's own which are for example placed in the 'plugins' subdirectory of my project.
Is there some solution for this?
I went a bit furtherer and tried to solve this with Jar Class Loader.
Because i'm instantiating the Spring application context manually i can do the following:
GenericApplicationContext ctx = new GenericApplicationContext();
// Load context definitions from plugin jars
JarClassLoader jcl = new JarClassLoader();
jcl.add("plugins/");
XmlBeanDefinitionReader classPathBeansReader = new XmlBeanDefinitionReader(ctx);
classPathBeansReader.setBeanClassLoader(jcl);
classPathBeansReader.setResourceLoader(new PathMatchingResourcePatternResolver(jcl));
classPathBeansReader.loadBeanDefinitions("classpath*:META-INF/my-plugins-*.xml");
However this is not working. From Spring's log i can see that it doesnt read the XML definition in the plugin jar. If i replace the bottom block with
XmlBeanDefinitionReader classPathBeansReader = new XmlBeanDefinitionReader(ctx);
classPathBeansReader.setBeanClassLoader(jcl);
classPathBeansReader.loadBeanDefinitions(new ClassPathResource("META-INF/my-plugins-somemodule.xml",jcl));
it finds and loads the XML definition file and beans from the jar. However this way i'm hardwiring the XML resource name for one plugin, which i don't wan't. How can i make the pattern matching working with JCL?
You might like to consider using OSGi as your plugin loading mechanism.
The Eclipse Virgo open source project provides an OSGi runtime environment that is suited to your project because it has Spring built in. Virgo offers Tomcat and Jetty based servers and a standalone kernel which can be used on its own or to construct other types of server. See the Virgo web site for features and benefits.
OSGi has quite a different design point than you may be used to in Java. It gives you controlled isolation between plugins, known as bundles, unlike a linear classpath. Bundles are wired together in a dependency graph and support versioning and dynamic life cycle operations.
The preferred means for a bundle to use the facilities of other bundles is via the OSGi service registry. The Spring DM project enables normal Spring beans to be published to the service registry and looked up from the service registry. Spring DM is also built in to Virgo. Spring DM has been donated to Eclipse as the Gemini Blueprint project.
To use Virgo, you would add some Spring DM configuration to each of your plugins in the META-INF/spring directory. This configuration, which is a normal XML Spring configuration file, can reference beans in your other Spring files and publish those beans in the service registry, or can provide beans for services looked up in the service registry which may then be referenced by, and injected into, beans in your other Spring files.
You would then deploy your plugins into Virgo using any of the supported mechanisms. You could simply drop them in dependency order into the pickup directory. Or you could use the web admin console or shell console to deploy then.
Alternatively, and this would seem to fit your requirement rather well, you could place plugins providing packages for other plugins in the Virgo repository by dropping them into repository/usr and then deploy the plugins which depend (transitively) on the repository plugins via the pickup directory or web admin console. Virgo will automatically deploy the dependencies from the repository as the dependent plugins are deployed.
You could also group plugins together either in an archive, known as a PAR, or by storing them in the Virgo repository and then referencing them in an XML file, known as a plan. You would then deploy the PAR or plan as describe above. You can even put some of the dependencies in the Virgo repository and reduce the PAR or plan to contain just the dependent plugins.
If you would like further information about Virgo, just ask on the Virgo community forum.
It seems that JCL doesn't override ClassLoader#findResource(String)
JarClassLoader.java
AbstractClassLoader.java
PathMatchingResourcePatternResolver JavaDocs state:
Internally, this happens via a ClassLoader.getResources() call
JavaDocs for ClassLoader#getResources(String) defers to documentation for ClassLoader#findResource(String), which states:
Finds the resource with the given name. Class loader implementations should override this method to specify where to find resources.
So while my answer is based on just reading a few bits of docs, I'd surmise that JCL doesn't support this due to not overriding the documented methods.
You could test this by subclassing JarClassLoader and implementing findResource(String), to test my hypothesis.
Of course, I could be wildly wrong.

Categories

Resources