Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
1be12ee9
Commit
1be12ee9
authored
Jan 20, 2015
by
Dave Syer
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch '1.1.x'
parents
6975b206
4e907f19
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
304 additions
and
16 deletions
+304
-16
appendix-executable-jar-format.adoc
...ocs/src/main/asciidoc/appendix-executable-jar-format.adoc
+1
-1
pom.xml
spring-boot-tools/spring-boot-loader/pom.xml
+6
-0
pom.xml
...-tools/spring-boot-loader/src/it/executable-props/pom.xml
+92
-0
jar-with-dependencies.xml
...cutable-props/src/main/assembly/jar-with-dependencies.xml
+26
-0
EmbeddedJarStarter.java
...springframework/launcher/it/props/EmbeddedJarStarter.java
+33
-0
SpringConfiguration.java
...pringframework/launcher/it/props/SpringConfiguration.java
+53
-0
application.properties
...xecutable-props/src/main/resources/application.properties
+1
-0
verify.groovy
.../spring-boot-loader/src/it/executable-props/verify.groovy
+32
-0
PropertiesLauncher.java
...a/org/springframework/boot/loader/PropertiesLauncher.java
+60
-15
No files found.
spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc
View file @
1be12ee9
...
@@ -142,7 +142,7 @@ Their purpose is to load resources (`.class` files etc.) from nested jar files o
...
@@ -142,7 +142,7 @@ Their purpose is to load resources (`.class` files etc.) from nested jar files o
files in directories (as opposed to explicitly on the classpath). In the case of the
files in directories (as opposed to explicitly on the classpath). In the case of the
`[Jar|War]Launcher` the nested paths are fixed (`+lib/*.jar+` and `+lib-provided/*.jar+` for
`[Jar|War]Launcher` the nested paths are fixed (`+lib/*.jar+` and `+lib-provided/*.jar+` for
the war case) so you just add extra jars in those locations if you want more. The
the war case) so you just add extra jars in those locations if you want more. The
`PropertiesLauncher` looks in `lib/` by default, but you can add additional locations by
`PropertiesLauncher` looks in `lib/`
in your application archive
by default, but you can add additional locations by
setting an environment variable `LOADER_PATH` or `loader.path` in `application.properties`
setting an environment variable `LOADER_PATH` or `loader.path` in `application.properties`
(comma-separated list of directories or archives).
(comma-separated list of directories or archives).
...
...
spring-boot-tools/spring-boot-loader/pom.xml
View file @
1be12ee9
...
@@ -30,6 +30,11 @@
...
@@ -30,6 +30,11 @@
<artifactId>
logback-classic
</artifactId>
<artifactId>
logback-classic
</artifactId>
<scope>
test
</scope>
<scope>
test
</scope>
</dependency>
</dependency>
<dependency>
<groupId>
org.springframework
</groupId>
<artifactId>
spring-webmvc
</artifactId>
<scope>
test
</scope>
</dependency>
<!-- Used to provide a signed jar -->
<!-- Used to provide a signed jar -->
<dependency>
<dependency>
<groupId>
org.bouncycastle
</groupId>
<groupId>
org.bouncycastle
</groupId>
...
@@ -57,6 +62,7 @@
...
@@ -57,6 +62,7 @@
<addTestClassPath>
true
</addTestClassPath>
<addTestClassPath>
true
</addTestClassPath>
<skipInvocation>
${skipTests}
</skipInvocation>
<skipInvocation>
${skipTests}
</skipInvocation>
<streamLogs>
true
</streamLogs>
<streamLogs>
true
</streamLogs>
<parallelThreads>
4
</parallelThreads>
</configuration>
</configuration>
<executions>
<executions>
<execution>
<execution>
...
...
spring-boot-tools/spring-boot-loader/src/it/executable-props/pom.xml
0 → 100644
View file @
1be12ee9
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
org.springframework.boot.launcher.it
</groupId>
<artifactId>
executable-props
</artifactId>
<version>
0.0.1.BUILD-SNAPSHOT
</version>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<version>
3.1
</version>
<configuration>
<source>
1.6
</source>
<target>
1.6
</target>
</configuration>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-dependency-plugin
</artifactId>
<version>
2.9
</version>
<executions>
<execution>
<id>
unpack
</id>
<phase>
prepare-package
</phase>
<goals>
<goal>
unpack
</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>
@project.groupId@
</groupId>
<artifactId>
@project.artifactId@
</artifactId>
<version>
@project.version@
</version>
<type>
jar
</type>
</artifactItem>
</artifactItems>
<outputDirectory>
${project.build.directory}/assembly
</outputDirectory>
</configuration>
</execution>
<execution>
<id>
copy
</id>
<phase>
prepare-package
</phase>
<goals>
<goal>
copy-dependencies
</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/assembly/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>
maven-assembly-plugin
</artifactId>
<version>
2.4
</version>
<configuration>
<descriptors>
<descriptor>
src/main/assembly/jar-with-dependencies.xml
</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>
org.springframework.boot.loader.PropertiesLauncher
</mainClass>
</manifest>
<manifestEntries>
<Start-Class>
org.springframework.boot.load.it.props.EmbeddedJarStarter
</Start-Class>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>
jar-with-dependencies
</id>
<phase>
package
</phase>
<goals>
<goal>
single
</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>
org.springframework
</groupId>
<artifactId>
spring-context
</artifactId>
<version>
4.1.4.RELEASE
</version>
</dependency>
</dependencies>
</project>
spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/assembly/jar-with-dependencies.xml
0 → 100644
View file @
1be12ee9
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns=
"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"
>
<id>
full
</id>
<formats>
<format>
jar
</format>
</formats>
<includeBaseDirectory>
false
</includeBaseDirectory>
<dependencySets>
<dependencySet>
<useProjectArtifact/>
<includes>
<include>
${project.groupId}:${project.artifactId}
</include>
</includes>
<unpack>
true
</unpack>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>
${project.build.directory}/assembly
</directory>
<outputDirectory>
/
</outputDirectory>
</fileSet>
</fileSets>
</assembly>
spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/java/org/springframework/launcher/it/props/EmbeddedJarStarter.java
0 → 100644
View file @
1be12ee9
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
load
.
it
.
props
;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext
;
/**
* Main class to start the embedded server.
*
* @author Phillip Webb
*/
public
final
class
EmbeddedJarStarter
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
AnnotationConfigApplicationContext
context
=
new
AnnotationConfigApplicationContext
(
SpringConfiguration
.
class
);
context
.
getBean
(
SpringConfiguration
.
class
).
run
(
args
);
context
.
close
();
}
}
spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/java/org/springframework/launcher/it/props/SpringConfiguration.java
0 → 100644
View file @
1be12ee9
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
load
.
it
.
props
;
import
java.io.IOException
;
import
javax.annotation.PostConstruct
;
import
org.springframework.context.annotation.ComponentScan
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.io.support.PropertiesLoaderUtils
;
/**
* Spring configuration.
*
* @author Phillip Webb
*/
@Configuration
@ComponentScan
public
class
SpringConfiguration
{
private
String
message
=
"Jar"
;
@PostConstruct
public
void
init
()
throws
IOException
{
String
value
=
PropertiesLoaderUtils
.
loadAllProperties
(
"application.properties"
).
getProperty
(
"message"
);
if
(
value
!=
null
)
{
this
.
message
=
value
;
}
}
public
void
run
(
String
...
args
)
{
System
.
err
.
println
(
"Hello Embedded "
+
this
.
message
+
"!"
);
}
}
spring-boot-tools/spring-boot-loader/src/it/executable-props/src/main/resources/application.properties
0 → 100644
View file @
1be12ee9
message
:
World
\ No newline at end of file
spring-boot-tools/spring-boot-loader/src/it/executable-props/verify.groovy
0 → 100644
View file @
1be12ee9
def
jarfile
=
'./target/executable-props-0.0.1.BUILD-SNAPSHOT-full.jar'
new
File
(
"${basedir}/application.properties"
).
delete
()
String
exec
(
String
command
)
{
def
proc
=
command
.
execute
([],
basedir
)
proc
.
waitFor
()
proc
.
err
.
text
}
String
out
=
exec
(
"java -jar ${jarfile}"
)
assert
out
.
contains
(
'Hello Embedded World!'
),
'Using -jar my.jar should use the application.properties from the jar\n'
+
out
out
=
exec
(
"java -cp ${jarfile} org.springframework.boot.loader.PropertiesLauncher"
)
assert
out
.
contains
(
'Hello Embedded World!'
),
'Using -cp my.jar with PropertiesLauncher should use the application.properties from the jar\n'
+
out
new
File
(
"${basedir}/application.properties"
).
withWriter
{
it
->
it
<<
"message: Foo"
}
out
=
exec
(
"java -jar ${jarfile}"
)
assert
out
.
contains
(
'Hello Embedded World!'
),
'Should use the application.properties from the jar in preference to local filesystem\n'
+
out
out
=
exec
(
"java -Dloader.path=.,lib -jar ${jarfile}"
)
assert
out
.
contains
(
'Hello Embedded Foo!'
),
'With loader.path=.,lib should use the application.properties from the local filesystem\n'
+
out
new
File
(
"${basedir}/target/application.properties"
).
withWriter
{
it
->
it
<<
"message: Spam"
}
out
=
exec
(
"java -Dloader.path=target,.,lib -jar ${jarfile}"
)
assert
out
.
contains
(
'Hello Embedded Spam!'
),
'With loader.path=target,.,lib should use the application.properties from the target directory\n'
+
out
\ No newline at end of file
spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java
View file @
1be12ee9
...
@@ -124,7 +124,7 @@ public class PropertiesLauncher extends Launcher {
...
@@ -124,7 +124,7 @@ public class PropertiesLauncher extends Launcher {
*/
*/
public
static
final
String
SET_SYSTEM_PROPERTIES
=
"loader.system"
;
public
static
final
String
SET_SYSTEM_PROPERTIES
=
"loader.system"
;
private
static
final
List
<
String
>
DEFAULT_PATHS
=
Arrays
.
asList
(
"lib/"
);
private
static
final
List
<
String
>
DEFAULT_PATHS
=
Arrays
.
asList
();
private
static
final
Pattern
WORD_SEPARATOR
=
Pattern
.
compile
(
"\\W+"
);
private
static
final
Pattern
WORD_SEPARATOR
=
Pattern
.
compile
(
"\\W+"
);
...
@@ -136,6 +136,8 @@ public class PropertiesLauncher extends Launcher {
...
@@ -136,6 +136,8 @@ public class PropertiesLauncher extends Launcher {
private
final
Properties
properties
=
new
Properties
();
private
final
Properties
properties
=
new
Properties
();
private
Archive
parent
;
public
PropertiesLauncher
()
{
public
PropertiesLauncher
()
{
if
(!
isDebug
())
{
if
(!
isDebug
())
{
this
.
logger
.
setLevel
(
Level
.
SEVERE
);
this
.
logger
.
setLevel
(
Level
.
SEVERE
);
...
@@ -144,6 +146,7 @@ public class PropertiesLauncher extends Launcher {
...
@@ -144,6 +146,7 @@ public class PropertiesLauncher extends Launcher {
this
.
home
=
getHomeDirectory
();
this
.
home
=
getHomeDirectory
();
initializeProperties
(
this
.
home
);
initializeProperties
(
this
.
home
);
initializePaths
();
initializePaths
();
this
.
parent
=
createArchive
();
}
}
catch
(
Exception
ex
)
{
catch
(
Exception
ex
)
{
throw
new
IllegalStateException
(
ex
);
throw
new
IllegalStateException
(
ex
);
...
@@ -314,15 +317,12 @@ public class PropertiesLauncher extends Launcher {
...
@@ -314,15 +317,12 @@ public class PropertiesLauncher extends Launcher {
path
=
cleanupPath
(
path
);
path
=
cleanupPath
(
path
);
// Empty path (i.e. the archive itself if running from a JAR) is always added
// Empty path (i.e. the archive itself if running from a JAR) is always added
// to the classpath so no need for it to be explicitly listed
// to the classpath so no need for it to be explicitly listed
if
(!
(
path
.
equals
(
"."
)
||
path
.
equals
(
""
)
))
{
if
(!
path
.
equals
(
""
))
{
paths
.
add
(
path
);
paths
.
add
(
path
);
}
}
}
}
if
(
paths
.
isEmpty
())
{
if
(
paths
.
isEmpty
())
{
// On the other hand, we don't want a completely empty path. If the app is
paths
.
add
(
"lib"
);
// running from an archive (java -jar) then this will make sure the archive
// itself is included at the very least.
paths
.
add
(
"."
);
}
}
return
paths
;
return
paths
;
}
}
...
@@ -449,6 +449,8 @@ public class PropertiesLauncher extends Launcher {
...
@@ -449,6 +449,8 @@ public class PropertiesLauncher extends Launcher {
}
}
}
}
addParentClassLoaderEntries
(
lib
);
addParentClassLoaderEntries
(
lib
);
// Entries are reversed when added to the actual classpath
Collections
.
reverse
(
lib
);
return
lib
;
return
lib
;
}
}
...
@@ -493,41 +495,84 @@ public class PropertiesLauncher extends Launcher {
...
@@ -493,41 +495,84 @@ public class PropertiesLauncher extends Launcher {
}
}
private
Archive
getNestedArchive
(
final
String
root
)
throws
Exception
{
private
Archive
getNestedArchive
(
final
String
root
)
throws
Exception
{
Archive
parent
=
createArchive
();
if
(
root
.
startsWith
(
"/"
)
if
(
root
.
startsWith
(
"/"
)
||
parent
.
getUrl
().
equals
(
this
.
home
.
toURI
().
toURL
()))
{
||
this
.
parent
.
getUrl
().
equals
(
this
.
home
.
toURI
().
toURL
()))
{
// If home dir is same as parent archive, no need to add it twice.
// If home dir is same as parent archive, no need to add it twice.
return
null
;
return
null
;
}
}
EntryFilter
filter
=
new
PrefixMatchingArchiveFilter
(
root
);
EntryFilter
filter
=
new
PrefixMatchingArchiveFilter
(
root
);
if
(
parent
.
getNestedArchives
(
filter
).
isEmpty
())
{
if
(
this
.
parent
.
getNestedArchives
(
filter
).
isEmpty
())
{
return
null
;
return
null
;
}
}
// If there are more archives nested in this subdirectory (root) then create a new
// If there are more archives nested in this subdirectory (root) then create a new
// virtual archive for them, and have it added to the classpath
// virtual archive for them, and have it added to the classpath
return
new
FilteredArchive
(
parent
,
filter
);
return
new
FilteredArchive
(
this
.
parent
,
filter
);
}
}
private
void
addParentClassLoaderEntries
(
List
<
Archive
>
lib
)
throws
IOException
,
private
void
addParentClassLoaderEntries
(
List
<
Archive
>
lib
)
throws
IOException
,
URISyntaxException
{
URISyntaxException
{
ClassLoader
parentClassLoader
=
getClass
().
getClassLoader
();
ClassLoader
parentClassLoader
=
getClass
().
getClassLoader
();
List
<
Archive
>
urls
=
new
ArrayList
<
Archive
>();
for
(
URL
url
:
getURLs
(
parentClassLoader
))
{
for
(
URL
url
:
getURLs
(
parentClassLoader
))
{
if
(
url
.
toString
().
endsWith
(
".jar"
)
||
url
.
toString
().
endsWith
(
".zip"
))
{
if
(
url
.
toString
().
endsWith
(
".jar"
)
||
url
.
toString
().
endsWith
(
".zip"
))
{
lib
.
add
(
0
,
new
JarFileArchive
(
new
File
(
url
.
toURI
())));
urls
.
add
(
new
JarFileArchive
(
new
File
(
url
.
toURI
())));
}
}
else
if
(
url
.
toString
().
endsWith
(
"/*"
))
{
else
if
(
url
.
toString
().
endsWith
(
"/*"
))
{
String
name
=
url
.
getFile
();
String
name
=
url
.
getFile
();
File
dir
=
new
File
(
name
.
substring
(
0
,
name
.
length
()
-
1
));
File
dir
=
new
File
(
name
.
substring
(
0
,
name
.
length
()
-
1
));
if
(
dir
.
exists
())
{
if
(
dir
.
exists
())
{
lib
.
add
(
0
,
urls
.
add
(
new
ExplodedArchive
(
new
File
(
name
.
substring
(
0
,
new
ExplodedArchive
(
new
File
(
name
.
substring
(
0
,
name
.
length
()
-
1
)),
false
));
name
.
length
()
-
1
)),
false
));
}
}
}
}
else
{
else
{
String
filename
=
URLDecoder
.
decode
(
url
.
getFile
(),
"UTF-8"
);
String
filename
=
URLDecoder
.
decode
(
url
.
getFile
(),
"UTF-8"
);
lib
.
add
(
0
,
new
ExplodedArchive
(
new
File
(
filename
)));
urls
.
add
(
new
ExplodedArchive
(
new
File
(
filename
)));
}
}
// The parent archive might have a "lib/" directory, meaning we are running from
// an executable JAR. We add nested entries from there with low priority (i.e. at
// end).
addNestedArchivesFromParent
(
urls
);
for
(
Archive
archive
:
urls
)
{
// But only add them if they are not already included
if
(
findArchive
(
lib
,
archive
)
<
0
)
{
lib
.
add
(
archive
);
}
}
}
private
void
addNestedArchivesFromParent
(
List
<
Archive
>
urls
)
{
int
index
=
findArchive
(
urls
,
this
.
parent
);
if
(
index
>=
0
)
{
try
{
Archive
nested
=
getNestedArchive
(
"lib/"
);
if
(
nested
!=
null
)
{
List
<
Archive
>
extra
=
new
ArrayList
<
Archive
>(
nested
.
getNestedArchives
(
new
ArchiveEntryFilter
()));
urls
.
addAll
(
index
+
1
,
extra
);
}
}
catch
(
Exception
e
)
{
// ignore
}
}
}
private
int
findArchive
(
List
<
Archive
>
urls
,
Archive
archive
)
{
// Do not rely on Archive to have an equals() method. Look for the archive by
// matching strings.
if
(
archive
==
null
)
{
return
-
1
;
}
int
i
=
0
;
for
(
Archive
url
:
urls
)
{
if
(
url
.
toString
().
equals
(
archive
.
toString
()))
{
return
i
;
}
}
i
++;
}
}
return
-
1
;
}
}
private
URL
[]
getURLs
(
ClassLoader
classLoader
)
{
private
URL
[]
getURLs
(
ClassLoader
classLoader
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment