2008-11-20 23 views
40

Tôi có một tập lệnh groovy cần thư viện trong một cái lọ. Làm thế nào để thêm nó vào classpath? Tôi muốn tập lệnh có thể thực thi được vì vậy tôi đang sử dụng #!/usr/bin/env groovy ở đầu tập lệnh của mình.Làm cách nào để đưa các jars vào trong một tập lệnh hấp dẫn?

+2

Có vẻ như điều này đã được yêu cầu: http://stackoverflow.com/questions/254385/how-do-i-auto-load-a-database-jar-in-groovy-without-using-the-cp- chuyển đổi – timdisney

Trả lời

30

Nếu bạn thực sự phải bạn cũng có thể tải một JAR khi chạy với:

this.getClass().classLoader.rootLoader.addURL(new File("file.jar").toURL()) 
+0

Heh, chắc chắn bỏ lỡ phần "Thêm điều vào đường dẫn class" lần đầu tiên tôi đọc điều đó. – timdisney

+0

Tôi không thể làm cho trình nạp lớp đó hoạt động ... bất kỳ ai khác có thể sử dụng nó? – Zombies

+4

Có những hạn chế không được đề cập trong tài liệu khi chạy với một shebang (#!). Tôi giải thích thêm cho họ [xuống] (http://stackoverflow.com/a/8945888/54396). @Zombies, kỹ thuật của trình nạp lớp chỉ hoạt động khi bạn không cần nhập các lớp từ đó .jar. Các lần nhập được giải quyết trước khi tập lệnh chạy và nhập .jar – Patrick

4

Giống như bạn sẽ ở Java.

Đây là ví dụ về chạy tập lệnh theo dõi trạng thái MySQL. mysql.jar chứa trình kết nối MySQL mà tôi gọi từ kịch bản status.groovy.

groovy -cp mysql.jar status.groovy ct1

20

Bạn có thể thêm các lọ đến $ HOME/.groovy/lib

+0

hoạt động với tôi (sử dụng Groovy 2.1.2 với Windows 7) – pinei

+0

Điều này thật tuyệt vời trừ khi bạn đang chạy quá nhiều quy trình Groovy. giới hạn. –

10

Bạn cũng có thể thử Groovy nho. Nó cho phép bạn sử dụng chú thích để sửa đổi classpath. Thử nghiệm của nó ngay bây giờ, nhưng khá thú vị. Xem docs.groovy-lang.org/.../grape

44

Bắt đầu tập lệnh có kích thước hấp dẫn với #!/usr/bin/env groovy có giới hạn rất quan trọng - Không thể thêm đối số bổ sung. Không có đường dẫn lớp có thể được cấu hình, không chạy groovy với định nghĩa hoặc gỡ lỗi. Đây không phải là vấn đề groovy, nhưng giới hạn về cách hoạt động của shebang (#!) - tất cả các đối số bổ sung được coi là đối số duy nhất để #!/usr/bin/env groovy -d yêu cầu /usr/bin/env chạy lệnh groovy -d rathen rồi groovy với đối số d.

Có một giải pháp cho vấn đề này, bao gồm việc bẻ khóa bootstrapping với bash trong tập lệnh groovy.

#!/bin/bash                                         
//usr/bin/env groovy -cp extra.jar:spring.jar:etc.jar -d -Dlog4j.configuration=file:/etc/myapp/log4j.xml "$0" [email protected]; exit $? 

import org.springframework.class.from.jar 
//other groovy code 
println 'Hello' 

Mọi phép thuật xảy ra trong hai dòng đầu tiên. Dòng đầu tiên cho chúng ta biết rằng đây là tập lệnh bash. bash bắt đầu chạy và thấy dòng đầu tiên. Trong bash# dành cho nhận xét và // bị thu gọn thành / là thư mục gốc. Vì vậy, bash sẽ chạy /usr/bin/env groovy -cp extra.jar:spring.jar:etc.jar -d -Dlog4j.configuration=file:/etc/myapp/log4j.xml "$0" [email protected] bắt đầu với tất cả các đối số mong muốn của chúng tôi. "$0" là đường dẫn đến tập lệnh của chúng tôi và [email protected] là các đối số. Bây giờ groovy chạy và nó bỏ qua hai dòng đầu tiên và thấy kịch bản groovy của chúng tôi và sau đó thoát trở lại bash. bash sau đó thoát (exit $?1) với mã trạng thái từ groovy.

+0

Điều này có thể được thực hiện với một tập tin batch Windows không? – djangofan

+2

Mẹo hay - mặc dù nó không hoạt động trong vỏ Windows Cygwin, vì dấu gạch chéo kép trong // usr/bin/env không bị sập. – Henry

+0

Mẹo thực sự tốt đẹp –

19

Cách yêu thích của tôi để làm điều này là với Groovy Grapes. Những truy cập này vào Kho lưu trữ trung tâm Maven, tải về jar được tham chiếu, và sau đó đặt nó trên đường dẫn lớp. Sau đó, bạn có thể sử dụng thư viện như bất kỳ thư viện nào khác. Cú pháp rất đơn giản:

@Grab(group='com.google.collections', module='google-collections', version='1.0') 

Bạn có thể đọc thêm chi tiết here. Một lợi thế lớn ở đây là bạn không cần phải phân phối các phụ thuộc của bạn khi bạn phân phối kịch bản của bạn. Hạn chế duy nhất của phương thức này là Jar phải nằm trong kho lưu trữ Maven.

+0

Liên kết bị hỏng ở đây – Leo

3

Thêm vào @Patrick câu trả lời của anh ấy, điều đã giúp tôi rất nhiều, gần đây tôi đã phát hiện ra một mẹo khác.

Nếu bạn thêm nhiều lọ vào đường dẫn lớp trên cùng một dòng, mọi thứ có thể trở nên khá khó đọc.Nhưng bạn có thể làm như sau!

#!/bin/bash 
//bin/true && OPTS="-cp blah.jar -Dmyopt=value" 
//bin/true && OPTS="$OPTS -Dmoreopts=value2" 
//usr/bin/env groovy $OPTS "$0" [email protected]; exit $? 

println "inside my groovy script" 

Hãy để trí tưởng tượng của bạn chạy hoang dã vào độ phức tạp một dòng lệnh, bạn có thể phá vỡ theo cách này vào phần quản lý

Maarten

3

Dưới đây là một sự kết hợp của Patrick's solution, Maarteen Boekhold's solution, và bình luận foozbar của làm việc với cả Linux và Cygwin:

#!/bin/bash 
// 2>/dev/null; SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 
// 2>/dev/null; OPTS="-cp $SCRIPT_DIR/lib/extra.jar:$SCRIPT_DIR/lib/spring.jar" 
// 2>/dev/null; OPTS="$OPTS -d" 
// 2>/dev/null; OPTS="$OPTS -Dlog4j.configuration=file:/etc/myapp/log4j.xml" 
// 2>/dev/null; exec groovy $OPTS "$0" "[email protected]"; exit $? 

import org.springframework.class.from.jar 
//other groovy code 
println 'Hello' 

Cách hoạt động:

  • // là nhận xét groovy hợp lệ, vì vậy tất cả các lệnh bash đều bị Groovy bỏ qua.
  • // sẽ trả về lỗi, nhưng đầu ra lỗi được chuyển hướng đến /dev/null và do đó không được hiển thị.
  • bash thực hiện các lệnh sau dấu chấm phẩy mặc dù lệnh trước đó không thành công.
  • exec thay thế chương trình hiện tại trong quy trình hiện tại mà không cần giả mạo quy trình mới. Do đó, chạy groovy trong quá trình kịch bản gốc (ps cho thấy quá trình như kịch bản chứ không phải là thực thi groovy)
  • Tuyên bố exit $? sau exec groovy ngăn bash từ cố gắng để giải thích phần còn lại của kịch bản như một kịch bản bash, và cũng có thể bảo tồn mã trả về từ tập lệnh groovy.

Bí quyết bash ở trên thuận tiện hơn trong một số trường hợp hơn the RootLoader trick vì bạn có thể sử dụng câu lệnh nhập thông thường trong tập lệnh. Sử dụng thủ thuật RootLoader buộc bạn phải tải tất cả các lớp bằng cách sử dụng sự phản chiếu. Điều này là tốt trong một số trường hợp (chẳng hạn như khi bạn cần tải một trình điều khiển JDBC), nhưng bất tiện ở những người khác.

Nếu bạn biết tập lệnh của mình sẽ không bao giờ được thực hiện trên Cygwin, thì việc sử dụng giải pháp của Patrick hoặc Maarteen có thể dẫn đến hiệu năng tốt hơn một chút vì chúng tránh được chi phí phát sinh và vứt bỏ lỗi.

1

Nếu bạn muốn sử dụng nó ngay lập tức trước khi import tờ khai nó có thể như :) này:

// printEmployees.groovy 
this.class.classLoader.rootLoader.addURL(
    new URL("file:///C:/app/Dustin/product/11.1.0/db_1/jdbc/lib/ojdbc6.jar")) 
import groovy.sql.Sql 
sql = Sql.newInstance("jdbc:oracle:thin:@localhost:1521:orcl", "hr", "hr", 
         "oracle.jdbc.pool.OracleDataSource") 
sql.eachRow("SELECT employee_id, last_name, first_name FROM employees") 
{ 
    println "The employee's name is ${it.first_name} ${it.last_name}." 
} 

Taken từ javaworld.com article này.