2014年5月25日日曜日
Spring でのAsync処理 Queue
Queuingといえばメール送信や重たい処理を非同期で実行させる場合に
使わないと行けないというケースがあります。Spring には TaskExecutor という
非同期で処理を実行するQueueを取り扱うクラスがあります
これが何かと便利なので覚書
コマンド実行をQueueにするサンプル
asyncExecutorをautowiredして使います。
AsyncExecutor.java :
public class AsyncExecutor {
String command;
public void setCommand(String command) {
this.command = command;
}
@Autowired
private TaskExecutor taskExecutor;
public void execute(File file) {
taskExecutor.execute(new AsyncTask(file));
}
private class AsyncTask implements Runnable {
File file;
private AsyncTask(File file) {
this.file = file;
}
public void run() {
Runtime rt = Runtime.getRuntime();
try {
Process pr = rt.exec(command + " " + file.toString());
pr.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
bean定義
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" p:corePoolSize="5"
p:maxPoolSize="10" p:queueCapacity="100" p:waitForTasksToCompleteOnShutdown="true"/>
<bean id="asyncExecutor" class="sample.AsyncExecutor">
<property name="command" value=”/opt/jetty/bin/batch.sh"></property> </bean>
MailをTaskExecutorでおくる例は下記参照
http://www.i-develop.be/blog/2010/10/01/execute-tasks-asynchronously-with-spring-3-0/
非同期処理は自分で実装するのは気が引けるのでSpringでの実装は助かります
2014年5月15日木曜日
Spring Batch Adminにスケジュール機能をつけてみる
前回、Spring Batch Adminについて触れましたが、
Springには 3.0からTaskSchedulerという機能がついているのでそれを使って
Spring Batch Adminにスケジュールをホストさせてみます。
あくまで、Spring Batch Adminの使っているtaskLauncherを
TaskSchedulerから使うというものでAdminからスケジュールを編集できるとかではありません。
あしからず。
RunScheduler.java :
@Component
public class RunScheduler {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private ListableJobLocator jobLocator;
private String jobName;
public void setJobName(String jobName) {
this.jobName = jobName;
}
public void run() {
try {
String dateParam = new Date().toString();
JobParameters param = new JobParametersBuilder().addString("date",
dateParam).toJobParameters();
System.out.println(dateParam);
Job job = jobLocator.getJob(jobName);
JobExecution execution = jobLauncher.run(job, param);
} catch (Exception e) {
}
}
bean定義に次のようにスケジュールを定義します。
下の例では、テンプレートにあるsimpleJobを5分毎に実行します。
<bean id="runScheduler" class="my.package.RunScheduler">
<property name="jobName" value="simpleJob"/>
</bean>
<!-- Run every 5 minutes -->
<task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" cron="0 */5 * * * *" />
</task:scheduled-tasks>
cronの記述方法については下記
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06
記事を書いていて気づいた、
このscheduler自体をJob化すればadminからスケジュールの開始、停止もできる
Springには 3.0からTaskSchedulerという機能がついているのでそれを使って
Spring Batch Adminにスケジュールをホストさせてみます。
あくまで、Spring Batch Adminの使っているtaskLauncherを
TaskSchedulerから使うというものでAdminからスケジュールを編集できるとかではありません。
あしからず。
RunScheduler.java :
@Component
public class RunScheduler {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private ListableJobLocator jobLocator;
private String jobName;
public void setJobName(String jobName) {
this.jobName = jobName;
}
public void run() {
try {
String dateParam = new Date().toString();
JobParameters param = new JobParametersBuilder().addString("date",
dateParam).toJobParameters();
System.out.println(dateParam);
Job job = jobLocator.getJob(jobName);
JobExecution execution = jobLauncher.run(job, param);
} catch (Exception e) {
e.printStackTrace();
}}
}
bean定義に次のようにスケジュールを定義します。
下の例では、テンプレートにあるsimpleJobを5分毎に実行します。
<bean id="runScheduler" class="my.package.RunScheduler">
<property name="jobName" value="simpleJob"/>
</bean>
<!-- Run every 5 minutes -->
<task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" cron="0 */5 * * * *" />
</task:scheduled-tasks>
cronの記述方法については下記
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06
記事を書いていて気づいた、
このscheduler自体をJob化すればadminからスケジュールの開始、停止もできる
Spring Batch AdminのMySQL設定
バッチ実行にSpring Batchを利用しようかと検討しています。
jBatchがJavaEEに組み込まれたこともあり、
それに準拠した形でバッチを作ったほうがなにかと恩恵があるのかなと思ったというだけですが。
で、Spring BatchにはSpring Batch AdminというWebUIがあるので
使ってみます。あくまで、実行、停止、実行履歴が見れる程度のものです。
標準のdatabaseがhsqldbとなっているのでMySQLに変更します。
Adminのテンプレートでは
META-INF/batch-hsql.properties
というファイルがあるので次のファイルに変更します。
META-INF/batch-mysql.properties:
batch.jdbc.driver=com.mysql.jdbc.Driver
batch.jdbc.url=jdbc:mysql://localhost/test
batch.jdbc.user=user
batch.jdbc.password=
batch.jdbc.testWhileIdle=true
batch.jdbc.validationQuery=SELECT 1
batch.jdbc.maxActive=70
batch.jdbc.initialSize=20
batch.schema.script=classpath:/org/springframework/batch/core/schema-mysql.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-mysql.sql
batch.business.schema.script=classpath:/business-schema-mysql.sql
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer
# Non-platform dependent settings that you might like to change
batch.data.source.init=false
batch.data.source.init=falseはdatabase初期化するかという設定です。
一番最初に起動するときのみtrueにする必要があります。
このままだと、遅いので dataSourceをoverrideします。
次のファイルを作成します。
META-INF/spring/batch/override/war-content.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>
<property name=”driverClassName” value=”${batch.jdbc.driver}” />
<property name=”url” value=”${batch.jdbc.url}” />
<property name=”username” value=”${batch.jdbc.user}” />
<property name=”password” value=”${batch.jdbc.password}” />
<property name=”initialSize” value=”${batch.jdbc.initialSize}”/>
<property name=”maxActive” value=”${batch.jdbc.maxActive}”/>
</bean>
</beans>
実行時に引数を渡す必要があります。
-DENVIRONMENT=mysql
なのでmaven でデバッグするときは 次のようになる
jetty:run -Dmaven.surefire.debug test -DENVIRONMENT=mysql
せっかくなのでスケジュールに機能もつけてみました→次
jBatchがJavaEEに組み込まれたこともあり、
それに準拠した形でバッチを作ったほうがなにかと恩恵があるのかなと思ったというだけですが。
で、Spring BatchにはSpring Batch AdminというWebUIがあるので
使ってみます。あくまで、実行、停止、実行履歴が見れる程度のものです。
標準のdatabaseがhsqldbとなっているのでMySQLに変更します。
Adminのテンプレートでは
META-INF/batch-hsql.properties
というファイルがあるので次のファイルに変更します。
META-INF/batch-mysql.properties:
batch.jdbc.driver=com.mysql.jdbc.Driver
batch.jdbc.url=jdbc:mysql://localhost/test
batch.jdbc.user=user
batch.jdbc.password=
batch.jdbc.testWhileIdle=true
batch.jdbc.validationQuery=SELECT 1
batch.jdbc.maxActive=70
batch.jdbc.initialSize=20
batch.schema.script=classpath:/org/springframework/batch/core/schema-mysql.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-mysql.sql
batch.business.schema.script=classpath:/business-schema-mysql.sql
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer
# Non-platform dependent settings that you might like to change
batch.data.source.init=false
batch.data.source.init=falseはdatabase初期化するかという設定です。
一番最初に起動するときのみtrueにする必要があります。
このままだと、遅いので dataSourceをoverrideします。
次のファイルを作成します。
META-INF/spring/batch/override/war-content.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>
<property name=”driverClassName” value=”${batch.jdbc.driver}” />
<property name=”url” value=”${batch.jdbc.url}” />
<property name=”username” value=”${batch.jdbc.user}” />
<property name=”password” value=”${batch.jdbc.password}” />
<property name=”initialSize” value=”${batch.jdbc.initialSize}”/>
<property name=”maxActive” value=”${batch.jdbc.maxActive}”/>
</bean>
</beans>
実行時に引数を渡す必要があります。
-DENVIRONMENT=mysql
なのでmaven でデバッグするときは 次のようになる
jetty:run -Dmaven.surefire.debug test -DENVIRONMENT=mysql
せっかくなのでスケジュールに機能もつけてみました→次
2014年4月11日金曜日
HttpServletRequestのthread内共有 Spring編
HttpServletRequestを参照しようとした時に
引数で渡さずに、static fieldのthread localに保存して
スレッド内から参照できるようにする方法を昔紹介していましたが、
Spring使用時には標準の機能としてすでにあります。
次のようにRequestContextHolderからHttpServletRequestを取得します。
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
HttpServletRequest request =
(HttpServletRequest)attrs.resolveReference(RequestAttributes.REFERENCE_REQUEST);
web.xmlにlistenerを登録する必要があります。
web.xml:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Spring 2.5以上が必要です
使い道としては、エラー出力にリクエスト情報を出すとか
エラーハンドルのためにいちいち、
リクエストを引数には渡せないのでthreadに保持しているものを参照します。
ThreadLocalに自分で保存する記事よりは
既存のものを使うべきでしょう
引数で渡さずに、static fieldのthread localに保存して
スレッド内から参照できるようにする方法を昔紹介していましたが、
Spring使用時には標準の機能としてすでにあります。
次のようにRequestContextHolderからHttpServletRequestを取得します。
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
HttpServletRequest request =
(HttpServletRequest)attrs.resolveReference(RequestAttributes.REFERENCE_REQUEST);
web.xmlにlistenerを登録する必要があります。
web.xml:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Spring 2.5以上が必要です
使い道としては、エラー出力にリクエスト情報を出すとか
エラーハンドルのためにいちいち、
リクエストを引数には渡せないのでthreadに保持しているものを参照します。
ThreadLocalに自分で保存する記事よりは
既存のものを使うべきでしょう
2014年3月28日金曜日
Spring Security Auto Login
Spring Security を利用してログインセッション管理を
している方も多いと思います。
Spring Securityデフォルトのままで使うと
アカウント作成後に一度ユーザにログインしてもらわないといけないとか
イケてないので、そういう時に自動でログインセッションを作成する方法です
アカウント作成後に次のようなメソッドを呼びます
AuthenticationProvideのBeanを指定します(自作クラスでも動きます)
@Autowired
AuthenticationProvider authenticationProvider;
HttpServletRequestを予め取得しておいて、username, passwordから
tokenを発行し、authenticationProviderに登録します
private void doAutoLogin(String username, String password,
HttpServletRequest request) {
try {
// Must be called from request filtered by Spring Security,
// otherwise SecurityContextHolder is not updated
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
username, password);
token.setDetails(new WebAuthenticationDetails(request));
Authentication authentication = this.authenticationProvider
.authenticate(token);
// logger.debug("Logging in with [{}]",
// authentication.getPrincipal());
SecurityContextHolder.getContext()
.setAuthentication(authentication);
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
logger.error("Failure in autoLogin", e);
}
}
AutowiredしなくてもSecurityContextHolderからいけるかも
しれないですね。そのうちやってみよ。
している方も多いと思います。
Spring Securityデフォルトのままで使うと
アカウント作成後に一度ユーザにログインしてもらわないといけないとか
イケてないので、そういう時に自動でログインセッションを作成する方法です
アカウント作成後に次のようなメソッドを呼びます
AuthenticationProvideのBeanを指定します(自作クラスでも動きます)
@Autowired
AuthenticationProvider authenticationProvider;
HttpServletRequestを予め取得しておいて、username, passwordから
tokenを発行し、authenticationProviderに登録します
private void doAutoLogin(String username, String password,
HttpServletRequest request) {
try {
// Must be called from request filtered by Spring Security,
// otherwise SecurityContextHolder is not updated
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
username, password);
token.setDetails(new WebAuthenticationDetails(request));
Authentication authentication = this.authenticationProvider
.authenticate(token);
// logger.debug("Logging in with [{}]",
// authentication.getPrincipal());
SecurityContextHolder.getContext()
.setAuthentication(authentication);
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
logger.error("Failure in autoLogin", e);
}
}
AutowiredしなくてもSecurityContextHolderからいけるかも
しれないですね。そのうちやってみよ。
登録:
投稿 (Atom)