
這是我遷移到痞客邦後第一篇Blog,沒想到對岸朋友還是無法分享。
在新的PC試玩Android,結果明明有裝JDK,Path和JAVA_HOME都有設置,結果安裝Android SDK Tool的installer執行檔回應:JDK not found。
經Google大師裁示,目前Android SDK只支援32 bit,而我是安裝64bit,所以得安裝32 bit的JDK
Jemmy 發表在 痞客邦 留言(0) 人氣(227)
Guice使用annotation進行DI,在和使用XML配置相較之下,就每次變動都要改Java程式再編譯,而XML也許不需要。用於商業版,這個缺點也許反而是優點。Guice還提annotation與Provider來進行DI,這裡講用annotation。 第一例:用annotation來配置DI,即自訂一個annotation,姑名為@Blue。怎麼自訂請參考上一篇:
annotation usage。 所以@Blue的內容如下:
| @Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR}) @Retention ( RetentionPolicy.RUNTIME ) @Documented @BindingAnnotation // import com.google.inject.BindingAnnotation public @interface Blue {} |
可以在再被Inject的目標這麼設定,如下:
| @Inject @Blue private IFoo foo; |
感覺像Spring對field變數做@Autowired,而使用它(IFoo)的method的類別不能在建構函數裡使用,看來尚未被注入。 最後在繼承或實作Guice Module,做如下的bind :
| bind(IFoo.class).annotatedWith(Blue.class).to(FooImpl.class); |
當然每次都要自訂annotation也煩,何況可能有同annotation但賦值不同的需求。所以可以用@Named: 第二例:用annotation賦值來配置DI。這時不用再自訂annotation,而是用@Named,有點像Spring的@Value。
在Module的設定: bind(IFoo.class).annotatedWith(Names.named("A")).to(FooImpl.class); bind(IFoo.class).annotatedWith(Names.named("B")).to(BarImpl.class); |
使用@Named來Inject: @Inject @Named(value="A") private IFoo foo; @Inject @Named(value="B") private IFoo bar; |
用@Named的好處可以不用自訂annotation,其作用和bind toInstance也有點異曲同工之妙。而且常用於常數初始化設定,可以讀properties檔作為@Named的賦值,其Module配置DI方式如下:
| public class MyModule extends AbstractModule { @Override protected void configure() { this.loadProperties(super.binder()); } private void loadProperties(Binder binder) { InputStream stream = MyModule.class.getResourceAsStream("./app.properties"); Properties appProperties = new Properties(); try { appProperties.load(stream); Names.bindProperties(binder, appProperties); } catch (IOException e) { binder.addError(e); } } } |
其使用方式如下,value="LicenseKey"即是properties檔裡的key值:
| @Inject @Named(value="LicenseKey") private String key; |
Jemmy 發表在 痞客邦 留言(0) 人氣(207)
有論壇說,Java頂多是個語言,而稱不上平台(platform),真正的平台是Spring。而Spring現在觸角深入太多層面了,早把EJB幹掉成為J2EE的正宗了。會不會有一朝,Spring也像JBoss一樣,把Hibernate免費版本凍結到3.2.6.ga,之後都是商業版(金庸都可以改版賣錢,王語嫣陪慕容復做皇帝夢)。而還有誰能成替代Spring的IoC container的角色呢?除了Eclipse.org發行的Enquinox之外,就是Google出品的Guice了。Guice也真的只有DI的功用而已,不似Spring已經無所不能,而且備受撻伐的是,Guice全然委給annotation處理,這樣入侵程式碼太過嚴重,有違鬆耦合的原則。不過見仁見智,JDK 5.0推出annotation時也是飽受質疑。 不過Guice感覺上真的有比Spring好用些,除了我上篇初體驗之外,還學到以下幾種用法:
以下Module配接方式是相等的: | public class MyModule extends AbstractModule { @Override protected void configure() { MyService myService = new MyServiceImpl(); bind(MyService.class).toInstance(myService); } } | public class MyModuleImpl implements Module { @Override public void configure(Binder binder) { binder.bind(MyService.class) .to(MyServiceImpl.class); } } |
用到同一個instance的方式:上面左邊程式粉紅字片段。 設定Singleton方式:在class name上加個@Singleton就行。不過看來和Spring有個不同:Spring的Singleton是在context的唯一instance,而Guice的Singleton似乎是指JVM上…,或是該說同一個預設Class Loader上的唯一instance。 甚至為了單元測試,@ImplementedBy(MyServiceImpl.class)可以替代Guice.createInjector和@Inject使用,但interface適用class就被綁死了。
一個想闖出名堂的core framework,至少Servlet和JDBC要能相當支持。Guice可能不會在普遍的系統專案領域和Spring爭,而是在Google力推的Moible platform:Android和Cloud platform的GAE打開藍海疆界。以下參考
http://www.imxylz.info/p/211.html來自己實作的飯粒,Guice預設MVC是Struts2,從Struts2的支援上看,顯示它也未必非Spring不可。這裡先用基礎的Servlet:
web.xml設定:設定Filter及Listener,由Listener做Module配接初始化 | <web-app> <display-name>Archetype Created Web Application</display-name> <filter> <filter-name>GuiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>GuiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class> com.foo.web.GuiceServletContextListener </listener-class> </listener> </web-app> |
Context Listener:用法和Java Main一樣,要單元測試應該更方便了。 | public class GuiceServletContextListener extends com.google.inject.servlet.GuiceServletContextListener { @Override protected Injector getInjector() { return Guice.createInjector(new ServletModuleImpl()); } } |
Servlet Module:ServletModule是繼承AbstractModule,用serve(url-pattern).with(Servlet.class)替代bind(interface).to(implementation.class)配接。而Servlet的class可以設成@Singleton。 | public class ServletModuleImpl extends ServletModule { @Override protected void configureServlets() { serve("/echo").with(EchoServlet.class); } } |
Guice也涉足到Scala語言,也可和AOP產品搭配。感覺比Spring for web.xml設定更單純。
Jemmy 發表在 痞客邦 留言(0) 人氣(129)
大年初一上完廟拜完年後,繼續未完的Guice研究。它是藉由
起風前的相遇Blog看到的,是Google出品的有別於Spring的一個輕型的IoC container。而我正是因為報名了OSDC 2010,其Semilar主要內容是Google的Android,經Google才藉由該Blog得知Guice。經練習後,發現也不難用,過程也發生一個小問題得已解決。 不脫一個介面再對映一個實作,然後藉由一個媒介對映陳年飯粒,而必須用JDK 5.0來煮,因為Guice多以Annotation為主: Interface:
public interface MyService { public String getServiceName(); } |
Implement:
public class MyServiceImpl implements MyService { @Inject public MyServiceImpl() { } public String getServiceName() { return "Happy New Year!"; } } |
本例是不需要建構子,是為之後講@Inject所需。接著是寫一個繼承AbstractModule的類別,作用相當於Spring的ApplicationContext.xml為介面和實作做mapping。
| public class MyModule extends AbstractModule{ @Override protected void configure() { bind(MyService.class).to( MyServiceImpl.class ); } } |
Override configure這method,使用bind(介面).to(實作)綁定。完全免使用configuration file。使用方式如下:
| Injector injector = Guice.createInjector(new MyModule()); MyService myService = injector.getInstance(MyService.class ); System.out.println(myService.getServiceName()); |
藉由Guice的createInjector取得Injector,而其傳入的參數需繼承AbstractModule,因此可以依需求實作不同的Module。而Injector的角色就如同Spring的Context物件了。目前Spring 3據稱也有類似Guice的作法。另外,Spring裡的bean配置需要get/set進行DI,而在Guice則是透過方才說的@Inject取得,也可透過同一個AbstractModule去做bind to,以下是摘自Google的飯粒:
private final CreditCardProcessor processor; private final TransactionLog transactionLog; @Inject public MyServiceImpl(CreditCardProcessor processor, TransactionLog transactionLog) { this.processor = processor; this.transactionLog = transactionLog; } |
在Implement的Construction進行DI。
public class MyModule extends AbstractModule { @Override protected void configure() { bind(TransactionLog.class).to(DatabaseTransactionLog.class); bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class); bind(MyService.class).to(MyServiceImpl.class); } } |
在Guice的createInjector,就對Implement class進行Inject,因此configure method裡,先注入的要先bind to。
我使用Maven去建構Guice,結果出現一個Exception如下:
| Exception in thread "main" java.lang.NoClassDefFoundError:[Lorg/aopalliance/intercept/MethodInterceptor; |
經追查,Guice和Spring一樣都有引用aopalliance這個jar檔。是故其depency設定如下:
| <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> |
而Guice在Maven預設repository雖然有設,其artifactID為com.google.inject,版本為2.0。而Google的repository顯然較新,版本為2.0.1,其repository為:
| <repository> <id>guice-maven</id> <name>guice-maven</name> <url>http://guice-maven.googlecode.com/svn/trunk</url> </repository> |
所需要的jar按
http://code.google.com/p/google-guice/的建議,其dependency設定如下:
| <dependency> <groupId>com.google.code.guice</groupId> <artifactId>guice</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>com.google.code.guice</groupId> <artifactId>guice-struts</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>com.google.code.guice</groupId> <artifactId>guice-servlet</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>com.jteigen.scalatest</groupId> <artifactId>junit4runner</artifactId> <version>1.0</version> <scope>test</scope> </dependency> |
其中ScalaTest似乎一款針對Guice的JUnit的Runner,這有待研究。
Jemmy 發表在 痞客邦 留言(0) 人氣(191)
Google於去年底Release google-collections v1.0版,感覺和Apache的commons-collection差不多。好用就拿來用,反正免錢。有幾個工具如下,前提需import com.google.common.collect.*以及可能需要import java.util.*: 1.Collection Class有工廠類別產出,不再用new,例: HashSet<String> hashSet = Sets.newHashSet();
LinkedHashSet<String> linkedHashSet = Sets.newLinkedHashSet();
ArrayList<String> arrayList = Lists.newArrayList();
LinkedList<String> linkedList = Lists.newLinkedList(); 2.提供不可變(Immutable)的Collection Class,例: ImmutableSet<Integer> immutableSet = ImmutableSet.of(1, 2, 3, 4, 5); immutableSet.add( 99 ) 或 immutableSet.set( 1, 99 )都會丟出java.lang.UnsupportedOperationException 3.提供Muilt collection class,例: Multimap<String, String> multiMap = new ArrayListMultimap.create(); // 遵照第一條不用new。 multiMap.put("Jemmy", "Brother"); multiMap.put("Jemmy", "Employee"); // Jemmy具兩種角色 Collection<String> roles = multiMap.get("Jemmy"); // 取回不是String, 而是個集合 4.Concurrent開頭的類別名具有並行功能,替代舊的Vector、Hashtable類別,例:ConcurrentHashMultiset。 以上舉例,均取自
http://www.infoq.com/cn/news/2010/01/google_collections_10 其Maven設定如下: <dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
Jemmy 發表在 痞客邦 留言(0) 人氣(79)
Cloud Computing近年是自SOA之後所提的一個技術概念。而目前發布Cloud Computing的平台的廠商有Salesforce的Force.com、Google的GAE和Amazon的EC2,大概兩週前踹了GAE,後因手機是PHS無法收到Google認證簡訊,最後終於藉由主管手機取得認證簡訊完成最後一道Deploy程序。 Google有提供中文化的指南如左:
http://code.google.com/intl/zh-TW/appengine/docs/java/gettingstarted/。我使用Eclipse開發在Local測試沒有問題,但在佈署有以下的問題: 第一、 An internal error occurred during: "Deploying GuestBook to Google". Received IOException parsing the input stream for C:/Project/GuestBook/war\WEB-INF/web.xml。 解法:由於Eclipse會自己generate web.xml,所以後來找到web.xml的根標籤應該設成如下才過關: <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> 但是還有一個問題,就是war和WEB-INF目錄為何會是\斜線。(目前不可考) 第二、 An internal error occurred during: "Deploying GuestBook to Google". Received SAXException parsing the input stream for C:/Project/GuestBook/war\WEB-INF/datastore-indexes.xml 解法:在本機運行該app後,會在專案目錄war\WEB-INF下生成一個叫appengine-generated的目錄,裏面保存的自然是index檔啦; 如果你的app不需要配置index,在上傳時需要刪除該檔夾。 第三、 使用Eclipse的[Deploy App Engine Project]失敗,訊息是Unable to upload app: Software caused connection abort: recv failed。 解法:目前還不知怎麼解。但是以命令列切到war目錄,執行appcfg.cmd update war就可以佈上Google了。其URL為 http://
application-id.appspot.com/,如我的URL是
http://tsai-jemmy.appspot.com/,這application id在Google需獨一無二。 其次,佈到Google需有GMail帳號,Google對每個帳號都分配佈署十支App的配額。
Jemmy 發表在 痞客邦 留言(0) 人氣(197)