3. maj 2010 | Øvrige artikler
Java EE 6 - det med småt
Det er ingen hemmelighed at releaset af Java EE 6 stadig optager os. Nicky Mølholm er dykket ned i specifikationen og har skrevet en artikel om de ændringer, der har med hele platformen at gøre.
De enkelte dele af Java EE 6, som JAX-WS, EJB 3.1, JPA 2.0 etc, er efterhånden blevet grundigt beskrevet og vurderet i diverse artikler, fora og blogs. Nicky angriber platformen fra en anden vinkel i sin artikel, ved at tage fat i tværgående emner som de nye Java EE profiler, pruning i Java EE platformen, classloading, naming environments og deployment af DataSources.
Java Enterprise Edition 6 (aka Java EE 6) blev gjort tilgængelig i december 2009. Den nye udgave af Java EE platformen indeholder en række opdateringer til velkendte teknologier som EJB, Servlets, JCA, JAX-WS og mange andre. Nyhederne i hver af disse konkrete teknologier er efterhånden ved at være afdækket på diverse blogs, fora og nyhedssites. Denne artikel gennemgår de forandringer, der er sket på tværs af alle teknologierne - nemlig dem som er beskrevet i JSR 316 - Java Platform, Enterprise Edition 6 (Final Release):
- API- og Java SE versioner
- Pruning
- Java EE platform profiler
- Nyheder i applikationskomponenternes naming environment
- DataSources
- Class loading
API- og Java SE- versioner
I Java EE 5 var det påkrævet, at leverandører understøttede minimum Java SE 5. I Java EE 6 skal leverandører tilsvarende understøtte Java SE 6. En del af de APIs, som tidligere var placeret i Java EE platformen, er nu en integreret del af Java SE, herunder: JAF 1, SAAJ 1.3, og StAX 1.0. Derudover er JDBC 4.0 også en integreret del af Java SE 6 - og altså nu også til rådighed for Java EE 6 udviklere. Udover de APIs som Java SE 6 indeholder, stiller specifikationen en række krav til ekstra enterprise APIs der skal være i enhver Java EE 6 kompatibel applikationsserver. Nedenstående figur illustrerer hvilke APIs, i hvilke versioner, der skal være tilgængelige på en Java EE 6 server. Af nye APIs finder du blandt andet JAX-RS 1.1 API'et til udvikling af restful Web services, Bean Validation 1.0 til validering af POJOs i JPA og JSF applikationer, og det vel nok mest skelsættende API: Contexts and Dependency Injection (CDI) for Java EE 1.0, som introducerer elementer kendt fra Spring og Seam, men som samtidigt rykker grænsen med endnu flere innovative features! Blandt de opdaterede APIs findes blandt andet EJB 3.1 med nyheder som no-interface view og singleton session beans, JSF 2.2 som har udskiftet renderingsmotoren med facelets, samt Servlet 3.0 der blandt andet tilbyder asynkrone kald og meget mere.Pruning
Efterhånden som Java EE 6 platformen har udviklet sig, er en del af de inkluderede teknologier ikke helt så relevante som tidligere. For at kunne håndtere den voksende mængde af efterhånden irrelevante teknologier, introducerer Java EE 6 platformen den såkaldte ’Pruning’ process. Processen består af følgende steps for Java EE ekspert gruppen:- For release N af platformen udvælges en liste af teknologier, som man vil gøre valgfrie i senere releases – de får status: ”proposed removal”.
- For release N+1 af platformen gennemgåes listen af proposed removals for at afgøre følgende: om teknologien skal gøres valgfri, forblive i platformen som en påkrævet teknologi, eller om den skal forblive i status ”proposed removal” til senere Java EE releases.
Java EE platform profiler
Sun introducerer nu mulighed for, at man via Java Community Process (JCP) kan lave specialiserede udgaver af Java EE platformen, kaldet profiler. En Java EE profil udarbejdes i form af en JSR (Java Specification Request) - typisk af en eller flere Java EE produkt leverandører. Alle profiler skal som minimum implementere en fællesmængde af teknologier, herunder naming samt dependency injection af resurser. Derudover er der ret frie hænder til at definere profiler. Eksempelvis har profiler lov til at:- Fjerne passende subsets af Java EE platformen
- Tilføje en eller flere teknologier
- Bygge videre på en eksisterende Java EE profil
- Markere teknologier som valgfrie (for produkter baseret på profilen) Et oplagt eksempel på en Java EE profil kunne være en hypotetisk Java EE Portal profil. En sådan profil ville sandsynligvis inkludere den fulde Java EE 6 platform, samt relevante Portlet APIs.
Class loading
Java EE 6 specifikationen inkluderer som noget nyt en beskrivelse af kravene til class loading. For hver container type beskrives hvilke klasser og resurser der skal være tilgængelige i classpath for applikationen. Netop formaliseringen af disse krav er et super værktøj til dig som lægger en ære i udvikleportable applikationer. Hvis man eksempelvis skal migrere en applikation fra en JBoss Java EE 6 server til en Oracle WebLogic Java EE 6 server, så bør en af aktionerne være at sørge for at class loading reglerne i dette afsnit er overholdt. I figuren anvendes begrebet library: Et library i Java EE platformen refererer til en JAR fil med klasser og diverse ressourser. Ved hjælp af META-INF/MANIFEST.MF filen kan man erklære afhængigheder til disse libraries. Libraries kommer i to varianter: ’bundled’ eller ’installed’. Eksempler på bundlede libraries er JAR filer som man lægger i WAR modulers WEB-INF/lib folder og EAR modulers library folder (typisk: ’lib’). Et installeret library er typisk en JAR fil som er præ-installeret i en Java EE server. Med class loader reglerne for Java EE 6 har vi altså nu fået formaliseret præcis hvilke klasser og resurser vores komponenter kan anvende. Formaliseringen af class loader reglerne er uden tvivl et stort skridt frem. Bemærk dog at man i specifikationen ikke har medtaget konkrete regler for hvordan class loadere skal organiseres i Java EE 6 servere - dette er helt op til server leverandørerne. En konsekvens af dette er at man ikke kan anvende ovenstående regler til at resonere omkring ordenen for loading af diverse klasser. Ønsker man dette så må man, nøjagtigt som er tilfældet i dag, ty til leverandørens produktdokumentation.Naming environment
En ganske betydelig nyhed er introduktionen af tre nye applikationskomponent namespaces: java:module, java:app, og java:global. Disse udgør nu sammen med java:comp de fire namespaces som er tilgængelige for applikationskomponenter som EJB’ere og Servlets. Som i Java EE 5 kan applikationskomponenterne enten vælge at slå resurser i namespaces op vha JNDI eller at få dem indsat i member variable vha dependency injection (vha annotationer eller fra modulets deployment descriptor).- java:comp – Dette namespace var også tilgængeligt for Java EE 5 applikationer. Det er et per-komponent namespace. Eksempelvis kan alle instanser af én EJB se samme namespace – men én EJB kan ikke se en andens namespace. Af historiske årsager afviger Web moduler dog fra dette – her deler alle Web komponenter samme namespace.
- java:module – Dette namespace deles af alle komponenter i same modul. Eksempelvis kan alle EJB’ere i samme EJB-JAR modul se samme namespace – men EJB’ere i et modul kan ikke se en anden EJB-JARs module namespace. Bemærk, at for Web moduler refererer java:module namespacet til det samme namespace som java:comp.
- java:app – Dette namespace deles af alle komponenter i samme applikation. En applikation kan være en EAR fil eller et standalone modul som eksempelvis en WAR eller EJB-JAR. Eksempelvis kan EJB’ere fra en EJB-JAR i en EAR fil se samme namespace som Servlets fra en WAR i samme EAR fil – men EJB’ere fra en EAR fil kan ikke se et namespace tilhørende en anden EAR fil.
- java:global – Dette namespace deles af alle applikationer i en applikationsserver. En applikationserver kan være en enkelt server, et cluster af applikationsservere, et administrativt domæne af mange applikationsservere, eller mere – faktisk er scopet af java:global produktspecifikt.
public DataSource getMyDataSource() throws NamingException {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup(”java:app/env/jdbc/MyDataSource”)
}
Ovenstående funktionalitet kan man, som i Java EE 5, naturligvis også gøre en smule mere elegant ved hjælp af @Resource annotationen! I tillæg til de nye namespaces har annotationerne @Resource og @EJB også fået en ny attribut: lookup. Argumenter til denne attribut kan antage samme værdier som strenge til javax.naming.Context.lookup() metoden. Følgende eksempel demonstrerer en EJB, BusinessServiceImpl, der anvender dependency injection af en DataSource med applikations scope:
@Stateless
public class BusinessServiceImpl implements BusinessService{
@Resource(lookup=”java:app/env/jdbc/MyDataSource”)
private DataSource ds;
}
Bemærk at der i vanlig tråd med Java EE platformens konfigurationsstruktur, også er tilført et tilsvarende <lookup-name> element som kan anvendes i de respektive modulers deployment descriptorer til at supplere eller overskrive annotationskonfigurationen.
Udover de namespace entries, som applikationerne selv registrerer (DataSources, JMS- ConnectionFactories og destinationer, osv), registreres som noget nyt også følgende:
- Alle EJB’ere bliver registreret i hvert af de tre nye namespaces.
- Indeværende moduls navn under java:module/ModuleName. Et moduls navn kan valgfrit angives i modulets respektive deployment descriptor (eksempelvis ejb-jar.xml og web.xml). Hvis det ikke er angivet anvendes modulets filnavn uden ”.jar/.war”.
- Indeværende applikations navn under java:app/AppName. En applikations navn kan valgfrit angives i EAR filens deployment descriptor, application.xml. Hvis det ikke er angivet anvendes filnavnet uden ”.ear”.
@Stateless
public class BusinessServiceImpl implements BusinessService{
@Resource(lookup=”java:module/ModuleName”)
private String appName;
}
….EJB-JAR modulets deployment descriptor (ejb-jar.xml):
<ejb-jar …>
<module-name>My EJB JAR module</module-name>
</ejb-jar>
Som en sidste lille finesse er muligheden for type angivelse i konfigurations variable (simple environment entries) blevet udvidet. Tidligere kunne man anvende følgende typer: String, Character, Byte, Short, Integer, Long, Boolean, Double, og Float. Med til nyhederne hører, at de nu også kan være af typerne: Class og vilkårlige subklasser af Enum. Følgende eksempel viser en servlet, der anvender dependency injection af en konfigurations variabel med component scope. Her injectes en enum constant.
public class MyServlet implements HttpServlet {
@Resource(lookup=”java:comp/env/MyTimeUnit”)
private TimeUnit unit;
}
….Web modulets deployment descriptor (web.xml):
<web-app …>
<env-entry>
<env-entry-name>MyTimeUnit</env-entry-name>
<env-entry-type>java.util.concurrent.TimeUnit</env-entry-type>
<env-entry-value>MILLISECONDS </env-entry-value>
</env-entry>
</web-app>
Det var en hel del nyheder i forbindelse med applikationskomponenternes naming environment! Der er vist ingen tvivl om at den helt store nyhed her er introduktionen af de nye namespaces - især java:global namespacet. Med sidstnævnte namespace har Java EE platformen omsider inkorporeret en standardog dermed portabel måde at referere globale JNDI resurser som EJB'ere og DataSources på!
DataSource definitioner
Med denne feature kan man lave en Java EE 6 applikation som bundler sin egen DataSource. Den bagvedliggende ide er faktisk ikke så ny endda: eksempelvis har IBM's WebSphere Application Server igennem flere generationer understøttet samme funktionalitet i de såkaldte enhanced EAR files. Men med Java EE 6 kan vi nu gøre dette på en standardiseret og portabel måde på tværs af alle server produkter. DataSources kan defineres, så de er tilgængelige i hver af de fire JNDI scopes:- java:comp – DataSources placeret her kan kun anvendes af en enkelt komponent
- java:module – DataSources placeret her kan anvendes af alle komponenter i et modul
- java:app – DataSources placeret her kan anvendes af alle komponenter i alle moduler i en applikation
- java:global – DataSources placeret her kan anvendes af alle komponenter i alle applikationer i applikationsserveren
@DataSourceDefinition(name="java:global/MyApp/MyDataSource",
className="com.foobar.MyDataSource",
portNumber=6689,
serverName="myserver.com",
user="lance",
password="secret"
)
@Stateless
public class DataSourceBean {
}
Denne DataSource kan anvendes på helt normal vis i éns applikation - eller rettere: i enhver applikation på Java EE serveren! Herunder ses en no-interface view EJB, der anvender dependency injection vha @Resource annotationen for at kunne tilgå ovenstående DataSource:
@Stateless
public class UserDaoBean {
@Resource(lookup=” java:global/MyApp/MyDataSource”)
private DataSource ds;
}
Som alternativ til @DataSourceDefinition annotationen kan man også anvende <data-source> elementet i en deployment descriptor – det kan erklæres i ejb-jar.xml, web.xml, application-client.xml og ikke mindst application.xml. Herunder ses en ejb-jar.xml deployment descriptor, der erklærer en DataSource på server niveau - det resulterer i samme DataSource definition som ovenstående eksempel:
<ejb-jar ...>
<data-source>
<name>java:global/MyApp/MyDataSource</name>
<class-name>com.foo.MyDataSoure</class-name>
<server-name>myserver.com</server-name>
<port-number>6689</port-number>
<user>lance</user>
<password>secret</password>
</data-source>
</ejb-jar>
- Hvis man kombinerer de to muligheder så er det deployment descriptoren der får det sidste ord. Det er nemlig sådan, som med alle andre annotationer/XML konfiguration i Java EE platformen, at deployment descriptor indstillinger altid overskriver annotationer.
En typisk anvendelse af den nye DataSource funktionalitet kunne være:
- Under udviklingen af Java EE 6 applikationer har man muligheden for at komme hurtigt udover stepperne ved at anvende annotationer til at angive DataSources. I denne process hardkoder man hostnavne/ipaddresser, porte, brugernavne, passwords mv.
- Under deployment til en aktuel produktions server kan man så overskrive de hardkodede konfigurationer ved at anvende <data-source> i relevante deployment descriptor.
- Der udvikles miljø-specifikke binære distributioner af applikationen (EAR fil, eksempelvis). For hver distribution anvendes en miljø-specifik deployment descriptor til konfigurere DataSourcen.
- Man laver en en enkelt binær distribution og lader deployeren overskrive DataSource konfigurationen hver gang applikationen deployes.