Upload
taiichilow-nagase
View
8.591
Download
0
Tags:
Embed Size (px)
DESCRIPTION
Citation preview
http://www.flickr.com/photos/jox1989/5327951306
おっぴろげ JavaEE DevOps
おっぴろげ is 何
でもJavaEEの導入事例って あんま聞かなくない?
http://www.flickr.com/photos/dogwelder/94393980
せっかく作ったんだし シガラミがないうちに 全部話してしまえー
http://www.flickr.com/photos/pmillera4/8914149268
永瀬 泰一郎 グリー株式会社
@nagaseyasuhito
http://builder.japan.zdnet.com/sp_oracle/weblogic_2013/35040464/
meets
Scalaでやろうぜ!
やっぱ別チーム行くわ!ノシ
JavaEEやるチャンスや!
ひとりDevOps
http://www.flickr.com/photos/nanophoto69/5294068212
開発 テスト
リリース&デプロイ 運用
椿http://bit.ly/jjug-camellia
開発するぞ
Overviewhttp://www.flickr.com/photos/codlibrary/2282696252
EJB Timer
JMSCDI
JAX-RS
JPA
Abstract Entity
@MappedSuperclass@Setter @Getter@EqualsAndHashCode(of = { "id" })public abstract class BaseEntity { @Id @GeneratedValue(strategy = IDENTITY) private Long id;! @Column(nullable = false) @Version @XmlTransient private Long version;! @Column(nullable = false) @Temporal(TemporalType.TIMESTAMP) @XmlJavaTypeAdapter(ISO8601DateAdapter.class) private Date createdAt;}
LombokJPA JAXB
Xml Adapter
public class ISO8601DateAdapter extends XmlAdapter<String, Date> {! @Override public Date unmarshal(String v) throws Exception { return new Date(ISODateTimeFormat. dateTimeNoMillis().withZoneUTC().parseMillis(v)); }! @Override public String marshal(Date v) throws Exception { return ISODateTimeFormat. dateTimeNoMillis().withZoneUTC().print(v.getTime()); }}
LombokJPA JAXB
Concrete Entity
@Entity@Setter @Getterpublic class User extends BaseEntity { @Column(nullable = false, unique = true) @Pattern(regexp = "[\\p{Alnum}]*") private String name;! @Column(nullable = false) @XmlTransient private String password;}
Bean ValidationLombokJPA JAXB
Abstract Dao
public interface Query<T> { CriteriaQuery<T> execute( CriteriaBuilder b, CriteriaQuery<T> q, Root<T> r);}
JPA
Abstract Dao
public abstract class BaseDao<T> { protected T getSingleResult(Query<T> query) { CriteriaBuilder b = this.entityManager.getCriteriaBuilder();! CriteriaQuery<T> q = b.createQuery(this.getEntityClass());! Root<T> r = q.from(this.getEntityClass());! return this.entityManager.createQuery( query.execute(b, q, r)).getSingleResult(); }! protected abstract Class<T> getEntityClass();}
JPA
Concrete Dao
public class UserDao extends BaseDao<User> {! public User findByName(final String name) { return this.getSingleResult(new Query<User>() { @Override public CriteriaQuery<User> execute( CriteriaBuilder b, CriteriaQuery<User> q, Root<User> r) {! return q.select(r). where(b.equal(r.get(User_.name), name)); } }); }}
JPA
Concrete Dao
public class UserDao extends BaseDao<User> {! public User findByName(String name) { return this.getSingleResult((b, q, r) -> q.select(r).where(b.equal(r.get(User_.name), name)); }}
Service
@Transactionalpublic class UserService { @Inject private UserDao userDao;! public User create(@NotNull String name) { User user = new User(name); this.userDao.persist(user);! return user; }! public User show(@NotNull String name) { return this.userDao.findByName(name); }}
Bean ValidationCDI
JAX-RS
@Path("user")public class UserResource { @Inject private UserService userService;! @Path("{name}") // PUT /user/{name} @PUT public User create(@PathParam("name") String name) { return this.userService.create(name); }! @Path(“{name}") // GET /user/{name} @GET public User show(@PathParam("name") String name) { return this.userService.show(name); }}
CDIJAX-RS
テストするぞ
http://www.flickr.com/photos/mattt_org/2831690932
Separate UT and IT
どう分けるか
Integration Test
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <executions> <execution> <goals> <goal>integration-test</goal> </goals> </execution> </executions></plugin>
Integration Test
mvn verify
Unit Test
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <excludes> <exclude>**/*IT.java</exclude> </excludes> </configuration></plugin>
Unit Test
mvn test
Preparing Entity
Manager
<persistence> <persistence-unit name="camellia" transaction-type="JTA">! <jta-data-source>jdbc/camellia</jta-data-source>! <exclude-unlisted-classes> false </exclude-unlisted-classes>! <properties> <property name="eclipselink.ddl-generation" value="create-tables" /> </properties>! </persistence-unit></persistence>
Preparing Entity
Manager
Map<String, String> prop = Maps.newHashMap();!prop.put("javax.persistence.transactionType", "RESOURCE_LOCAL");prop.put("javax.persistence.jtaDataSource", "");prop.put("javax.persistence.jdbc.driver", "org.h2.Driver");prop.put("javax.persistence.jdbc.url", "jdbc:h2:mem:");!EntityManagerFactory entityManagerFactory = Persistence. createEntityManagerFactory("camellia", prop);!EntityManager entityManager = entityManagerFactory.createEntityManager();
JPA
Concrete Dao Test
public class UserDaoTest extends BaseDaoTest { private FixtureHelper fixtureHelper = new FixtureHelper();! private UserDao userDao = new UserDao();! @Before public void before() throws Throwable { Deencapsulation.setField(this.fixtureHelper, this.getEntityManager());! Deencapsulation.setField(this.userDao, this.getEntityManager()); }
JUnit JMockit
Concrete Dao Test
@Test public void findByNameSuccess() { this.fixtureHelper. createUser("user", "password");! assertThat( this.userDao.findByName("user”).getName(), is("user")); }}
JUnit
Abstract Integration
Test
@RunWith(Arquillian.class)public abstract class BaseServiceIT {! @Deployment public static Archive<?> createDeployment() { WebArchive war = ShrinkWrap.create(WebArchive.class);! war.addPackages(true, Root.class.getPackage()); war.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); war.addAsResource("META-INF/persistence.xml");! return war; }}
ArquillianJUnit
Concrete Integration
Test
public class UserServiceIT extends BaseServiceIT { @Inject private FixtureHelper fixtureHelper; @Inject private UserService userService;! @Test public void createSuccess() { assertThat( this.userService.create("create user", "password"), is(notNullValue())); }! @Test(expected = TransactionalException.class) public void createFailureByDuplicatedName() { this.userService.create("duplicated user","password"); this.userService.create("duplicated user","password"); }}
CDIJUnit
リリース&デプロイするぞ
http://www.flickr.com/photos/ivyfield/4763965911
Release and
Versionリリースとバージョン
maven release plugin
<scm> <url>https://github.com/nagaseyasuhito/camellia</url> <connection> scm:git:[email protected]:nagaseyasuhito/camellia.git </connection> <tag>HEAD</tag></scm>!<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-release-plugin</artifactId> <configuration> <tagNameFormat>@{project.version}</tagNameFormat> <goals>package</goals> </configuration> </plugin> </plugins></build>
maven release plugin
mvn release:prepare release:perform
Jenkins Build
Pipeline Plugin
Unit Test
Integration Test Release
Production Deploy
Staging Deploy
Development Deploy
Clone workspace
SCM Plugin
GitHub
Clone workspace SCM
Unit Test
Integration Test
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0
as1.camellia camellia:1.0.0
as2.camellia camellia:1.0.0
Reverse Proxy
Production Deploy
通常時
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0 camellia:1.0.1
as1.camellia camellia:1.0.0
as2.camellia camellia:1.0.0
Reverse Proxy
Production Deploy
asadmin deploy --target=camellia --enabled=false --name camellia:1.0.1 /tmp/camellia:1.0.1.war
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0 camellia:1.0.1
as1.camellia camellia:1.0.0
as2.camellia camellia:1.0.0
Reverse Proxy
Production Deploy
リバースプロキシからas1.camelliaを抜く
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0 camellia:1.0.1
as1.camellia camellia:1.0.1
as2.camellia camellia:1.0.0
Reverse Proxy
Production Deploy
asadmin enable --target=as1.camellia camellia:1.0.1
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0 camellia:1.0.1
as1.camellia camellia:1.0.1
as2.camellia camellia:1.0.0
Reverse Proxy
Production Deploy
リバースプロキシにas1.camelliaを入れる
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0 camellia:1.0.1
as1.camellia camellia:1.0.1
as2.camellia camellia:1.0.0
Reverse Proxy
Production Deploy
リバースプロキシからas2.camelliaを抜く
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0 camellia:1.0.1
as1.camellia camellia:1.0.1
as2.camellia camellia:1.0.1
Reverse Proxy
Production Deploy
asadmin enable --target=as2.camellia camellia:1.0.1
Deploy to
GlassFish
camellia
das.camellia camellia:1.0.0 camellia:1.0.1
as1.camellia camellia:1.0.1
as2.camellia camellia:1.0.1
Reverse Proxy
Production Deploy
リバースプロキシにas2.camelliaを入れる
運用するぞ
http://www.flickr.com/photos/defenceimages/6331498981
logging
asadmin set-log-levels org.eclipse.persistence.session=FINE
logging
[#|2013-11-23T21:37:11.979+0900|INFO|glassfish 4.0|javax.enterprise.system.core|_ThreadID=101;_ThreadName=Thread-16;_TimeMillis=1385210231979;_LevelValue=800;_MessageID=NCLS-CORE-00022;| Loading application __admingui done in 6,277 ms|#]
[2013-11-23T21:39:41.869+0900] [glassfish 4.0] [INFO] [NCLS-CORE-00022] [javax.enterprise.system.core] [tid: _ThreadID=100 _ThreadName=Thread-16] [timeMillis: 1385210381869] [levelValue: 800] [[ Loading application __admingui done in 5,286 ms]]
com.sun.enterprise.server.logging.UniformLogFormatter
com.sun.enterprise.server.logging.ODLLogFormatter
JMX
@MXBeanpublic interface UserMonitor { long getNumberOfUsers();}
JMX
JMX
@Startup @Singletonpublic class UserMonitorImpl implements UserMonitor { @Inject private UserDao userDao;! @SneakyThrows @PostConstruct public void initialize() { ObjectName objectName = new ObjectName("Camellia:type=User"); MBeanServer server = ManagementFactory.getPlatformMBeanServer() if (server.isRegistered(objectName)) { server.unregisterMBean(objectName); } server.registerMBean(this, objectName); }! @Override public long getNumberOfUsers() { return this.userDao.count(); }}
LombokJMX EJB CDI
Demoデモしたい
Gangliaで出したい
jmetric
asadmin create-jvm-options '-javaagent\: ${com.sun.aas.instanceRoot}/lib/jmxetric-1.0.4.jar= config=${com.sun.aas.instanceRoot}/config/jmxetric.xml'
jmetric
<jmxetric-config> <jvm process="Camellia" />! <sample delay="300"> <mbean name="Camellia:type=User" pname="User"> <attribute name="NumberOfUsers" type="int16" /> </mbean> </sample>! <ganglia hostname="localhost" port="8649" mode="multicast" wireformat31x="true" /></jmxetric-config>
まとめ
Conclusionエンタープライズ言うな
Copyright © GREE, Inc. All Rights Reserved.
インターネットを通じて、世界をより良くする。
Copyright © GREE, Inc. All Rights Reserved.