0

I just used spring boot to develop a non web project , actually a simple project used as a shell script, just access a url by RestTemplate then send email to some body tell them the result by Freemaker template.

at first I just dependency

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>

then build executable jar(mvn package), it's very big, have 17M. Then after several attempts, now the dependency is

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
    </dependency>

even so the executable jar still big, have 12M.

Could exist any manner to reduce executable jar size? after all it's a very small project only have several small class.

In additional, could exist some best practice to create shell script by spring boot, now for this purpose I disable these things

spring.main.web-environment=false
spring.main.banner_mode=off
spring.devtools.livereload.enabled=false
spring.jmx.enabled=false

and disable logger

logging.level.org.springframework=ERROR
logging.level.com.foo=ERROR

could have some best practice to create shell script by spring boot?

zhuguowei
  • 8,401
  • 16
  • 70
  • 106

1 Answers1

0

In order to reduce the jar size, you can always start excluding all the dependencies that are not going to be used. You can list the dependencies of your project with mvn dependency:tree.

Since Spring Boot provides a large amount of default settings, many dependencies are also pulled by default, so check what is being used, that you aren't going to need, but be careful with what is it that you are excluding.

Update

To be able to access the command line parameters, in the reference documentation explains how you can do it:

By default SpringApplication will convert any command line option arguments (starting with ‘--’, e.g. --server.port=9000) to a property and add it to the Spring Environment. As mentioned above, command line properties always take precedence over other property sources.

source

So to implement what you need, you need to follow these steps:

1) Create a bean that process these properties and then perform all the logic that you need, in your case, sending an email.

One way to retrieve these properties is with the @Value annotation, for example, to retrieve the property mentioned in the previous example:

@Service
public class Service {

    @Value("${server.port}")
    private Integer port;

    // rest of the code that injects/executes the sending email bit

}

although, if you are not injecting the value to a String, you need to be aware of the possible type conversion issues if it is not provided in a valid format when invoking the application.

2) Execute that Service after the application has been started, which can be done, either by declaring a @Bean of CommandLineRunner, or by making the service implement that interface.

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    CommandLineRunner someMeaningfulMethodName( Service service ) {
        return args -> {
            // execute your code here, using the injected Service
        };
    }

}

Note that by passing the service with your logic as parameter, you are injecting the service into the bean.

3) Terminate the spring boot app after the execution is finished. In order to do this, you basicall need to close the application context. I personally haven't done that myself, but found this answer here in SO that explains how to do so.

You'll probably want to perform that action at the end of the CommandLineRunner bean.


Update 2

One consideration to keep in mind by using this approach is that every time you execute the application, is that you are initializing the application context every time.

What i want to point out by this, is that, if you plan to send a batch of emails, for example 1000 emails, you'll be starting the application 1000 times aswell, if the startup takes 6 seconds, you'll be spending 6000 seconds starting the application 1000 times. Add to that, the amount of time that takes to shut it down, and sending a single email.

Community
  • 1
  • 1
saljuama
  • 2,906
  • 1
  • 20
  • 42
  • e.g. I want to create a shell script for sending mail in server. after build executable jar (e.g. send-mail.jar) then scp to server, then alias sendmail = /var/send-mail.jar, then could use this way `sendmail -to bbb@bbb.com -subject "hello world" -body "test" -attach /tmp/data.txt` is this description clear? – zhuguowei Jan 04 '16 at 11:27
  • what i meant is, do you want a shell script invoking the running spring boot app, or do you want a spring boot app that can be executed from a terminal like any unix command and terminate after its execution? – saljuama Jan 04 '16 at 12:42
  • the latter. And I know could generate a executable jar by true . then you could just use it as a normal shell script e.g. ./send-mail.jar -to xxx -subject xxx – zhuguowei Jan 04 '16 at 12:47
  • Sorry! maybe actually not. Now I just use `@Override public void run(String... args) throws Exception {}` and I feel it's more easier to receive command arguments than your way at least in my busi case. And I feel if `run` method is over, process automatically exit. – zhuguowei Jan 09 '16 at 12:01