afnf.net

Spring Boot 1.4 への移行

blog-java2ブログエンジンをSpring Boot 1.4.0にアップグレードしてみました。

5件の修正を行ったのでご紹介。

ちなみにリリースノートの拙訳はこちら

セキュリティ関連の変更

executable jarから起動すると、以下のエラーが発生しました。

2016-07-09 23:31:14,354 [main] WARN  o.s.b.c.e.AnnotationConfigEmbeddedWebApplicationContext(549) - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'loginAction': Unsatisfied dependency expressed through field 'us': Error creating bean with name 'userService':(中略): Is there an unresolvable circular reference?
2016-07-09 23:31:14,409 [main] WARN  o.springframework.boot.SpringApplication(91) - Error handling failed (Error creating bean with name 'delegatingApplicationListener' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name (中略)
2016-07-09 23:31:14,467 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter(42) -

***************************
APPLICATION FAILED TO START
***************************

Description:

There is a circular dependency between 3 beans in the application context:
        - loginAction (field protected net.afnf.blog.service.UserService net.afnf.blog.web.admin.LoginAction.us)
        - userService (field private org.springframework.security.crypto.password.PasswordEncoder net.afnf.blog.service.UserService.passwordEncoder)
        - securityConfig
        - passwordEncoder

1.4からエラー原因が分かりやすくなっています。Autowire時に循環参照が発生したようです。

変更前のSecurityConfig.javaは以下。

// 変更前
@Override
@Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
  JdbcDaoImpl userDetailsService = new JdbcDaoImpl();
  userDetailsService.setDataSource(dataSource);
  userDetailsService.setUsersByUsernameQuery
    ("select username, password, true from users where username = ?");
  userDetailsService.setAuthoritiesByUsernameQuery
    ("select username, role from users where username = ?");
  return userDetailsService;
}

@Autowired
public void configureGlobal(
  AuthenticationManagerBuilder auth, 
  UserDetailsService userDetailsService,
  PasswordEncoder passwordEncoder) throws Exception {
  auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}

ドキュメントを見るとGlobalAuthenticationConfigurerAdapterを使うのが正解のようなので、以下のように変更しました。

// 変更後
@Configuration
public class AuthenticationManagerConfiguration extends GlobalAuthenticationConfigurerAdapter {

  @Override
  public void init(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication()
      .dataSource(dataSource)
      .usersByUsernameQuery
        ("select username, password, true from users where username = ?")
      .authoritiesByUsernameQuery
        ("select username, role from users where username = ?")
      .passwordEncoder(passwordEncoder());
  }
}

プロパティ変更

いくつかのプロパティが変更されたので、これに対応しました。

# 変更前
shell.ssh.enabled=false
spring.datasource.min-idle=1
spring.datasource.initial-size=1
spring.datasource.max-active=2
spring.datasource.max-idle=1
# 変更後
management.shell.ssh.enabled=false
spring.datasource.tomcat.min-idle=1
spring.datasource.tomcat.initial-size=1
spring.datasource.tomcat.max-active=2
spring.datasource.tomcat.max-idle=1

テスト関連の変更

SpringTestBase.javaクラスのアノテーションを以下のように変更しました。

// 変更前
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BlogJava2App.class)
@WebIntegrationTest
public abstract class SpringTestBase {
// 変更後
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
public abstract class SpringTestBase {

統合テスト時のポート番号を固定したいので、WebEnvironment.DEFINED_PORTを指定しました。

二重起動検出方法の変更

これまで二重起動は例外メッセージで判定していたのですが、PortInUseExceptionが返ってくるようになったので修正しました

// 変更前
try {
  return run(clazz, args);
}
catch (Exception e) {
  // 二重起動
  if ("Unable to start embedded Tomcat servlet container".equals(e.getMessage())) {
   (略)
  }
  else {
    throw e;
  }
}
// 変更後
try {
  return run(clazz, args);
}
// 二重起動
catch (PortInUseException e) {
 (略)
}

mybatis-spring-boot-starterの導入

これは Spring Boot 1.4 とは関係ないのですが、これまで使用していたmybatis-springをやめて、mybatis-spring-boot-starterを使用するようにしました。

@Mappermybatis.type-aliases-package=net.afnf.blog.domainを導入し、MyBatisConfig.javaを削除しました。

@kazuki43zooさんのQiitaエントリが非常に参考になります。


所感

結構影響がありました。特にexecutable jarになって初めて見つかるパターンの不具合は、対応が面倒ですね。

統合テストも問題なさそうだったので、既にリリース済です。

変更履歴

  • 2016/07/31 RC1から正式版に移行、追加修正は不要でした
comments (0)

blog-java2 engine (build:2017-08-10 17:37 JST)