spring as a cloud platform (developer summit 2011 17-c-5)
TRANSCRIPT
Developers Summit 2011
17-C-5
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Simple Object
Portable Service Abstraction
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
水平方向への拡張 →対応プラットフォーム
時間軸方向への拡張 →開発ライフサイクル
垂直方向への拡張 →プラットフォームスタック
Developers Summit 2011
Developers Summit 2011
H/W
OS
Middle Ware
Framework
Application
Developers Summit 2011
JVM
Servlet その他の仕様
Spring
Roo/Grails
既存のパワフルで 拡張性の高いレイヤ
選択肢が広い
生産性が高い
代わりに選択肢は狭まる
既存のレイヤの上に構築
ランタイムはそのまま
Developers Summit 2011
App
App
App
App
App
App
vSphere
vCloud Other Cloud
Developers Summit 2011
Force.com Database
Force.com Platform Services
Your Java App
VMware vSphere
Spring & Tomcat
VMware vCloud
Developers Summit 2011
Scaling(スケールアップ) and Load-balancing(ロードバランス) as a service
アプリケーションライフサイクル管理
自動バックアップ & ディザスタリカバリ
Monitoring(監視) and diagnostics(診断) as a service
Your Java App
Force.com Database
プラットフォームがサービスとして
提供
Developers Summit 2011
GAE/Jのスタックの上でSpringを提供
GWTとの連携 Hypericに
よる監視機能を提供
Developers Summit 2011
Developers Summit 2011
vSphere
vCloud
SUSE Linux
Developers Summit 2011
vSphere
vCloud
App App App
Linux
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Spring
Web Service Data Access
JPA
Hibernate
JDBC HSQLDB
Spring tc Server
Developers Summit 2011
@Controller @RequestMapping("/login.form") public class LoginController { private LoginService loginService; @Autowired public void setLoginService(LoginService loginService) { this.loginService = loginService; } ... @RequestMapping(method = RequestMethod.GET) public String setupForm(ModelMap model) { if (loginService.isLogin()) { model.addAttribute("login", loginService.getLoginUser()); return loginService.getWelcomePage(); } else { model.addAttribute("login", new LoginBean()); return loginService.getLoginPage(); } } … }
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <context:component-scan base-package="sample.spring.mvc.web" /> <bean id="messageSource" class="org.springframework.context.support. ResourceBundleMessageSource"> <property name="basename" value="messages" /> </bean> </beans>
appContext-web.xml
Developers Summit 2011
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS" isELIgnored="false" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Login Page</title> </head> <body> <h1>Login!</h1> <form:form modelAttribute="login"> <table> <tr> <td>Login Name:</td> <td> <form:input path="loginname"/> <font color="red"><form:errors path="loginname"/></font> </td> </tr> .... <tr> <td colspan="2"><input type="submit" name="Login" value="Login"></td> </tr> </table> </form:form> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <beans:beans ...> <annotation-driven /> <resources mapping="/resources/**" location="/resources/" /> <beans:bean class="org.springframework.web.servlet.view. InternalResourceViewResolver"> <beans:property name="prefix" value="/WEB-INF/views/" /> <beans:property name="suffix" value=".jsp" /> </beans:bean> </beans:beans> login.jsp
appContext-view.xml
Developers Summit 2011
@Service("loginService") public class LoginServiceImpl implements LoginService { @Autowired private MemberDao memberDao; public void setMemberDao(MemberDao memberDao) { this.memberDao = memberDao; }
@Transactional(readOnly=true) public boolean login(String loginname, String password) { List<LoginBean> beans = memberDao.findByLoginname(loginname); if (beans.size() > 0) { LoginBean bean = beans.get(0); if (bean.getPassword() != null && bean.getPassword().equals(password)) { loginManager.setLoginUser(bean); return true; } } return false; } }
<?xml version="1.0" encoding="UTF-8"?> <beans …> <context:annotation-config/> <context:component-scan base-package="sample.spring.mvc.service"/>
<bean id="loginManager" scope="session" class="sample.spring.mvc.service.LoginManager"> <aop:scoped-proxy/> </bean> </beans>
appContext-service.xml
Developers Summit 2011
@Repository("memberDao") public class MemberDaoImpl implements MemberDao { @PersistenceContext EntityManager em;
public List<LoginBean> findByLoginname(String loginname) { Query query = em.createQuery( "SELECT l FROM LoginBean l WHERE l.loginname = :loginname"); query.setParameter("loginname", loginname); return query.getResultList(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans… <context:annotation-config/> <context:component-scan base-package="sample.spring.mvc.dao"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="sample" /> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true" /> </bean> </property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:hsql://localhost/"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
appContext-dao.xml
Developers Summit 2011
@Entity @Table(name="member") public class LoginBean implements Serializable { public LoginBean() {} @Id @GeneratedValue private Long id; @Column(unique=true) private String loginname; private String password; @Column(name="name") private String nickname; … }
<?xml version="1.0" encoding="UTF-8"?> <persistence …> <persistence-unit name="sample" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>sample.spring.mvc.bean.LoginBean</class> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> </properties> </persistence-unit> </persistence>
persistence.xml
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Spring
Web Service Data Access
JPA Datanucleus
Connector Force.com Database
Spring tc Server on VMForce
Webサービス API
Developers Summit 2011
@Controller @RequestMapping("/login.form") public class LoginController { private LoginService loginService; @Autowired public void setLoginService(LoginService loginService) { this.loginService = loginService; } ... @RequestMapping(method = RequestMethod.GET) public String setupForm(ModelMap model) { if (loginService.isLogin()) { model.addAttribute("login", loginService.getLoginUser()); return loginService.getWelcomePage(); } else { model.addAttribute("login", new LoginBean()); return loginService.getLoginPage(); } } … }
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <context:component-scan base-package="sample.spring.mvc.web" /> <bean id="messageSource" class="org.springframework.context.support. ResourceBundleMessageSource"> <property name="basename" value="messages" /> </bean> </beans>
appContext-web.xml
Developers Summit 2011
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS" isELIgnored="false" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Login Page</title> </head> <body> <h1>Login!</h1> <form:form modelAttribute="login"> <table> <tr> <td>Login Name:</td> <td> <form:input path="loginname"/> <font color="red"><form:errors path="loginname"/></font> </td> </tr> .... <tr> <td colspan="2"><input type="submit" name="Login" value="Login"></td> </tr> </table> </form:form> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <beans:beans ...> <annotation-driven /> <resources mapping="/resources/**" location="/resources/" /> <beans:bean class="org.springframework.web.servlet.view. InternalResourceViewResolver"> <beans:property name="prefix" value="/WEB-INF/views/" /> <beans:property name="suffix" value=".jsp" /> </beans:bean> </beans:beans>
appContext-view.xml
login.jsp
Developers Summit 2011
@Service("loginService") public class LoginServiceImpl implements LoginService { @Autowired private MemberDao memberDao; public void setMemberDao(MemberDao memberDao) { this.memberDao = memberDao; }
@Transactional(readOnly=true) public boolean login(String loginname, String password) { List<LoginBean> beans = memberDao.findByLoginname(loginname); if (beans.size() > 0) { LoginBean bean = beans.get(0); if (bean.getPassword() != null && bean.getPassword().equals(password)) { loginManager.setLoginUser(bean); return true; } } return false; } }
<?xml version="1.0" encoding="UTF-8"?> <beans …> <context:annotation-config/> <context:component-scan base-package="sample.spring.mvc.service"/>
<bean id="loginManager" scope="session" class="sample.spring.mvc.service.LoginManager"> <aop:scoped-proxy/> </bean> </beans>
appContext-service.xml
Developers Summit 2011
@Repository("memberDao") public class MemberDaoImpl implements MemberDao { @PersistenceContext EntityManager em;
public List<LoginBean> findByLoginname(String loginname) { Query query = em.createQuery( "SELECT l FROM LoginBean l WHERE l.loginname = :loginname"); query.setParameter("loginname", loginname); return query.getResultList(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <context:annotation-config/> <context:component-scan base-package="sample.spring.mvc.dao"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="sample" /> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
appContext-dao.xml
Developers Summit 2011
@Entity @Table(name="member") public class LoginBean implements Serializable { public LoginBean() {}
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private String id; @Column(unique=true) private String loginname; private String password; //@Column(name="name") private String nickname; ... }
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence ...> <persistence-unit name="sample"> <provider>org.datanucleus.jpa.PersistenceProviderImpl</provider> <properties> <property name="datanucleus.Optimistic" value="false"/> <property name="datanucleus.datastoreTransactionDelayOperations" value="true"/> <property name="sfdcConnectionName" value="DefaultSFDCConnection"/> <property name="datanucleus.ConnectionURL" value="sfdc:https://xxx.salesforce.com/services/Soap/u/20.0"/> <property name="datanucleus.ConnectionUserName" value="[email protected]"/> <property name="datanucleus.ConnectionPassword" value="xxxx"/> <property name="datanucleus.autoCreateSchema" value="false"/> <property name="datanucleus.autoCreateTables" value="true"/> <property name="datanucleus.autoCreateColumns" value="false"/> <property name="datanucleus.autoCreateConstraints" value="false"/> <property name="datanucleus.validateTables" value="false"/> <property name="datanucleus.validateConstraints" value="false"/> <property name="datanucleus.jpa.addClassTransformer" value="false"/> </properties> </persistence-unit> </persistence>
IDフィールドはStringでなければならない
カスタムフィールドは 標準フィールドの名前とかぶらない
force.comのAPIのエンドポイント
persistence.xml
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
サーバの追加
VMForce用の Extensionを追加
Developers Summit 2011
カスタム オブジェクトの 作成
カスタム フィールドの 追加
初期データの投入
Developers Summit 2011
実行するインスタンス数の選択
アクセス先のURL
インスタンスの 状況を参照
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Spring
Web Service Data Access
JPA Datanucleus
Connector
Google AppEngine BigTable
Developers Summit 2011
@Controller @RequestMapping("/login.form") public class LoginController { private LoginService loginService; @Autowired public void setLoginService(LoginService loginService) { this.loginService = loginService; } ... @RequestMapping(method = RequestMethod.GET) public String setupForm(ModelMap model) { if (loginService.isLogin()) { model.addAttribute("login", loginService.getLoginUser()); return loginService.getWelcomePage(); } else { model.addAttribute("login", new LoginBean()); return loginService.getLoginPage(); } } … }
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <context:component-scan base-package="sample.spring.mvc.web" /> <bean id="messageSource" class="org.springframework.context.support. ResourceBundleMessageSource"> <property name="basename" value="messages" /> </bean> </beans>
appContext-web.xml
Developers Summit 2011
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS" isELIgnored="false" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>Login Page</title> </head> <body> <h1>Login!</h1> <form:form modelAttribute="login"> <table> <tr> <td>Login Name:</td> <td> <form:input path="loginname"/> <font color="red"><form:errors path="loginname"/></font> </td> </tr> .... <tr> <td colspan="2"><input type="submit" name="Login" value="Login"></td> </tr> </table> </form:form> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <beans:beans ...> <annotation-driven /> <resources mapping="/resources/**" location="/resources/" /> <beans:bean class="org.springframework.web.servlet.view. InternalResourceViewResolver"> <beans:property name="prefix" value="/WEB-INF/views/" /> <beans:property name="suffix" value=".jsp" /> </beans:bean> </beans:beans>
appContext-view.xml
login.jsp
Developers Summit 2011
<?xml version="1.0" encoding="utf-8" standalone="no"?> <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> <application>xxx</application> <version>2</version> <sessions-enabled>true</sessions-enabled> </appengine-web-app>
セッションを使う宣言
appengine-web.xml
Developers Summit 2011
@Service("loginService") public class LoginServiceImpl implements LoginService { @Autowired private MemberDao memberDao; public void setMemberDao(MemberDao memberDao) { this.memberDao = memberDao; }
@Transactional(readOnly=true) public boolean login(String loginname, String password) { List<LoginBean> beans = memberDao.findByLoginname(loginname); if (beans.size() > 0) { LoginBean bean = beans.get(0); if (bean.getPassword() != null && bean.getPassword().equals(password)) { loginManager.setLoginUser(bean); return true; } } return false; } }
<?xml version="1.0" encoding="UTF-8"?> <beans …> <context:annotation-config/> <context:component-scan base-package="sample.spring.mvc.service"/>
<bean id="loginManager" scope="session" class="sample.spring.mvc.service.LoginManager"> <aop:scoped-proxy/> </bean> </beans>
appContext-service.xml
Developers Summit 2011
@Repository("memberDao") public class MemberDaoImpl implements MemberDao { @PersistenceContext EntityManager em;
public List<LoginBean> findByLoginname(String loginname) { Query query = em.createQuery( "SELECT l FROM LoginBean l WHERE l.loginname = :loginname"); query.setParameter("loginname", loginname); return query.getResultList(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <context:annotation-config/> <context:component-scan base-package="sample.spring.mvc.dao"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="sample" /> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
appContext-dao.xml
Developers Summit 2011
@Entity @Table(name="member") public class LoginBean implements Serializable { public LoginBean() {}
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private String id; //@Column(unique=true) private String loginname; private String password; //@Column(name="name") private String nickname; ... }
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <persistence …> <persistence-unit name="sample"> <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider> <properties> <property name="datanucleus.NontransactionalRead" value="true"/> <property name="datanucleus.NontransactionalWrite" value="true"/> <property name="datanucleus.ConnectionURL" value="appengine"/> <property name="datanucleus.ConnectionUserName" value=""/> <property name="datanucleus.ConnectionPassword" value=""/> <property name="datanucleus.autoCreateSchema" value="false"/> <property name="datanucleus.autoCreateTables" value="true"/> <property name="datanucleus.autoCreateColumns" value="false"/> <property name="datanucleus.autoCreateConstraints" value="false"/> <property name="datanucleus.validateTables" value="false"/> <property name="datanucleus.validateConstraints" value="false"/> <property name="datanucleus.jpa.addClassTransformer" value="false"/> </properties> </persistence-unit> </persistence>
使えない設定も多い
AppEngine専用のJPAプロバイダー
persistence.xml
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011
Developers Summit 2011