Can I run springboot's with outer libraries? - spring-boot

Now I've got two jars: main-run.jar and my-starter.jar.
my-starter.jar is a simple custom spring boot starter, which contains some ApplicationRunner in it.
main-run.jar is a whole application but without dependency of my-starter, so I want to add the dependency of my-starter when i run main-run.jar, here is my folder tree:
my-folder
+-- main-run.jar
+-- lib/
+-- my-starter.jar
and I run java -cp lib/my-starter.jar -jar main-run.jar, and it just run the main application, other ApplicationRunner in my-starter.jar doesn't run.
So, is there any way to make it work? I know I can rebuild and repackage the main-run with the dependency of my-starter, but I have no right to rebuild it.

I think I find a solution, just run this :
java \
-cp <your main springboot jar>
-Dloader.path=<starter jar>
org.springframework.boot.loader.PropertiesLauncher
here's the link : https://mash213.wordpress.com/2017/01/05/hack-how-2-add-jars-2-springboot-classpath-with-jarlauncher/

Related

How can I submit an Apache Storm topology to a Storm cluster?

I'm following this tutorial: https://learn.microsoft.com/en-us/azure/hdinsight/storm/apache-storm-develop-java-topology
What I've done so far is
maven setting
vi *.java files (in src/main/java/com/microsoft/example directory)
RandomSentenceSpout.java
SplitSentence.java
WordCount.java
WordCountTopology.java
mvn compile
jar cf storm.jar *.class (in target/classes/com/microsoft/example directory)
RandomSentenceSpout.class SplitSentence.class WordCount.class WordCountTopology.class
The above 4 files were used to make storm.jar file
Then, I tried
storm jar ./storm.jar com.microsoft.example.WordCountTopology WordCountTopology
and
storm jar ./storm.jar WordCountTopology
, but both of these failed, saying:
Error: Could not find or load main class com.microsoft.example.WordCountTopology
or
Error: Could not find or load main class WordCountTopology
According to a document, it says
Syntax: storm jar topology-jar-path class ...
Runs the main method of class with the specified arguments. The storm
jars and configs in ~/.storm are put on the classpath. The process is
configured so that StormSubmitter will upload the jar at
topology-jar-path when the topology is submitted.
I cannot find where to fix.
How can I resolve this?
I think your jar file does not contain class WordCountTopology. You can check it with jar tf storm.jar | grep WordCountTopology.
Looks like your jar does not contain a Manifest file which keeps information about the main class.
Try including the Manifest file or you can run the below java command to include the Manifest file
Hope this works!
jar cvfe storm.jar mainClassNameWithoutDotClassExtn *.class

unable to execute jar file(consists dependencies), which is build from gradle

i am very new to gradle, i was trying to build a java file which is dependent on other jar file. It is building properly but when i try to execute it, it is giving "NoClassDefinitionFoundError".
my build.gradle file is:
apply plugin : 'java'
jar {
manifest {
attributes 'Main-Class': 'Hey'
}
}
dependencies
{
compile files('lib/BuildBasicJavaProject.jar') ------line A
}
if i remove the above line A then it is not even building the project.
if i keep that line A then it is building properly and producing the jar file, but when i execute it using ,
java -jar jarfilename.jar
then it is giving me a NoClassDefinitionFoundError.
Where do i need to specify the dependents path while running the jar file??
May be its a basic doubt but i wasted 2 days already in it, i tried giving
1) absolute path of the dependency file
2) adding the following line,
runtime files('lib/BuildBasicJavaProject.jar')
But did not succeed.
Thanks in advance
First welcome to Gradle world.
Your Gradle scripts seems to be correct. When you have a dependency, one jar depends on another like in your case at compile time you define compile time dependency like you did. So if you need this jar to run it you need runtime dependency, in your case. But Gradle automatically put all your compile time dependencies to be runtime dependencies. So you do not need to specify them explicitly.
So why then your code does not working?
The classpath (-cp) option is ignored if using the -jar option. So you can not specify dependent jar using -cp when type jar.So you have to write If you are on Windows
java -cp myJar.jar;.\lib\BuildBasicJavaProject.jar Hey
or use (:) and slashes(/) for Linux.
Where Hey is the full-quallified name of your main class, which have to be defind in the Manifest.
So if your class Hey is in the package:com.alabala.dev and it's name is Hey it's full qualified name is com.alabala.dev.Hey. So you have to tell Gradle
mainClassName = "com.alabala.dev.Hey"
So now Gradle put it in the manifest and when you are trying to load this jar in the JVM, she will know that to start it, she have to execute com.alabala.dev.Hey.
What is cp and why you have to specify it? Said with simple word cp is classpath - directories and archives in which JVM searches when want to load something. So here there is nothing linekd with Gradle it is Java.
You'll want to specify dependency jar(s) as a part of classpath, when you are executing your jar.
Something along these these lines:
java -cp myJar.jar:./lib/BuildBasicJavaProject.jar my.package.MyMainClass
Bare in mind that classpath delimiters are different on different platforms (: is for *nix based systems).

Spring Boot and external configurations

I am trying to make a Spring Boot application. Everything is fine once I deploy to the fat jar file with everything contained in it. But, what I actually want is the configuration files to be located externally. for example I have the following directory structure:
bin - contains startup and shutdown scripts
conf - all configurations. i.e. application.properties, logback.xml i18n.properties
logs - log files
libs - app.jar
If I use this directory structure and execute the jar using
java -cp ./conf -jar ../libs/app.jar
then the properties in the conf directory are not loaded or recognized. Is there a better way to do this maintaining the directory structure above? Or, what is the alternative/best practice?
Boot external config is what you are looking for.
Especially it mentions:
SpringApplication will load properties from application.properties
files in the following locations and add them to the Spring
Environment:
A /config subdir of the current directory.
The current directory
A classpath /config package
The classpath root
So I would say adding the config folder on classpath is good step. Them it should find application.properties and load it automatically.
For different config files I use:
#Configuration
#EnableAutoConfiguration
#PropertySource({
"classpath:path/some.properties",
"classpath:another/path/xmlProperties.xml"
})
public class MyConfiguration {
// ...
}
Edit:
As Dave pointed out (Thank Dave!) there is either -cp or -jar, so you can't add it to classpath like that. But there are options. This should help you to solve the problem: Call "java -jar MyFile.jar" with additional classpath option.
Additionally #PropertySource doesn't require the resources to be classpath resources if I'm not mistaken.
It should also be mentioned that there is a spring.config.location parameter that allows one to specify a file system / classpath location for externalized configuration files. This is documented in the following section of the Spring Boot reference guide:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files

Spring does not find WebApplicationInitializer when packaged in a fat Jetty jar

I am trying to create a single "FAT" jar of embedded Jetty and my code. Unfortunatly if I run from the jar I get this error: No Spring WebApplicationInitializer types detected on classpath
If I unpack the jar it works just fine.
The question is can I run the app from the jar or does it have to be unpacked?
Here is a sample project and the steps to reproduce the issue:
git clone https://github.com/steveliles/jetty-embedded-spring-mvc-noxml.git
cd jetty-embedded-spring-mvc-noxml
mvn clean install
cd target
java -jar jetty-noxml-1.0-SNAPSHOT.jar
You will get this output "...No Spring WebApplicationInitializer types detected on classpath...".
but if you do this:
mkdir temp
cd temp
unzip jetty-noxml-1.0-SNAPSHOT.jar
java -cp . com.sjl.Main
This will work just fine.
So what can be done to make this work directly from the jar without unpacking it first?
== Update ==
The author of the project resolved the issue. The following code was needed to pickup webapps from a shaded jar:
parser = new AnnotationParser() {
#Override
public void parse(Resource aDir, ClassNameResolver aResolver) throws Exception {
if (aDir.isDirectory()) {
super.parse(aDir, aResolver);
} else {
super.parse(aDir.getURI(), aResolver);
}
}
};
See: https://github.com/steveliles/jetty-embedded-spring-mvc-noxml/commit/789663310b2fa2bdc0b101658275758a26cec229

Maven plugin to generate an executable web application (war->executable jar-war)

I have a maven project that is generating a .war file.
I want to configure maven to generate an executable jar, that embeds a servlet container (jetty, tomcat, or others) plus my war application, and generate an executable jar that can run my web application with a command like:
java -jar mywebapp.war
Is there a maven plugin to obtain such artifact?
At the moment I'm using jetty-runner to run a test version of my app, it's quite satisfying for test, but not as as handy for redistribution as it would be an executable war (like in jenkins).
Update
#jesse-mcconnell: I don't want to change a single line in my web application (except in the pom.xml) to achieve the result. It's just a matter to package my war differently, and keep it deployable under an appserver of choice, plus having the ability to run it as an executable war.
A perfect solution should also give me the ability to choose which appserver to embed, also specifying all needed configuration files contained in the executable war itself.
#khmarbaise: I know about jenkins, I already checked the code long time back, it uses winstone servlet container, and it puts a Main.class in the war which is accessible from http (and I think it's wrong)
A perfect solution could generate a war containing stuff like this:
├── META-INF
│ └── MANIFEST.MF (Main-Class: WEB-INF.container.classes.Main)
└── WEB-INF
   ├── web.xml
   ├── classes
   ├── lib
└── container
├── lib (jetty.jar/tomcat.jar/whatever.jar)
   ├── etc (configuration files for the container)
└── classes
└── Main.class
Main.class should use etc configuration as default, but being able to override common parameters at the command line (port, context,etc) or specifying a new configuration.
Main.class should be able to load the container jar and configuration from inside the container (or extract into tmp.dir) and start up the appserver.
This is how I would make it.
At the end, you have a normal war, that can be deployed in any appserver, with the ability to run in a self-contained way.
Tomcat Maven plugin do that have a look here http://tomcat.apache.org/maven-plugin-2.0/executable-war-jar.html
HTH
Use the maven jar plugin to set the Main-Class in the manifest, and then write a main method with something akin to this (or that calls into code like this):
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContext.java?h=jetty-8
You can register your servlets and wire up the webapp accordingly.
The issue with bundling a war file proper inside of a jar file is that you would need a specialized deployer that understands deploying a war file from within a jar, not a common thing. So creating an uber type jar is probably the better way to go. Besides, one of the big reasons of the actual WebAppContext is the classloader isolation which is kinda moot in these cases.
You can use the maven-dependency-plugin to unpack the various dependencies you need. There are other plugins you can use like the maven-uberjar-plugin (I think that was the name) but you can do it simply with the maven-dependency-plugin + a custom main class akin to something like the above.
I like this approach as you end up with a main method that you can run in eclipse that starts up the whole application and lets you debug the whole thing as well, often quite a win.
Edit: for posterity, jetty also releases with an artifact called jetty-runner that allows for running war files directly off of the command line
No that i know but check the jenkins source code which supports starting directly from command like you expected to work.

Resources