IoC容器9——基於註解的容器配置

基於註解的容器配置

註解比XML更適合配置Spring嗎?java

引入基於註解的配置提出了這種方法是否比XML更好的問題。簡短的回答是視狀況而定。詳細的回答是每一個方法都有它的優缺點,而且一般由開發者來決定哪一種策略更適合他們。因爲其定義的方式,註解在其聲明中提供了大量的上下文,這使得配置更短、更簡潔。然而,XML的優點是裝配組件的時候並不接觸它們的源碼或者從新編譯它們。一些開發者喜歡裝配更靠近源碼,而另外一些開發者認爲註解的類再也不是POJO而且所以配置變得分散、難以控制。算法

不管如何選擇,Spring均可以容納兩種風格甚至混合使用它們。值得指出的是經過Java配置,Spring容許以非侵入的方式使用註解,而不須要觸碰目標組件源代碼。spring

替代XML的基於註解的配置依靠字節碼元數據裝配組件來替代尖括號聲明。開發者經過使用相關類、方法或字段聲明上的註解將配置移動到組件類自己。正如在「示例:RequiredAnnotationBeanPostProcessor」一節中所提到的,使用BeanPostProcessor結合註釋是擴展Spring IoC容器的經常使用手段。例如,Spring 2.0引入了使用@Required註解強制須要屬性的可能性。Spring 2.5使得遵循相同的方法來驅動Spring依賴注入成爲可能。本質上,@Autowired註解提供了與自動裝配中所述相同的功能,可是具備更細粒度的控制和更普遍的適用性。Spring 2.5還加入了對於JSR-250註解的支持例如@PostConstruct和@PreDestory。Spring 3.0 加入了對JSR-330(Java的依賴注入)註解包括javax.inject包中@Injec和@Name的支持。數組

註解注入先於XML注入進行,所以使用兩種方式裝配屬性後者會覆蓋前者。緩存

能夠註冊它們爲單獨的bean定義,但也能夠經過在基於XML的Spring配置中包含如下標籤來隱式註冊(注意要包含context命名空間):app

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

(隱式註冊的後處理器包括AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor和上文說起的RequiredAnnotationBeanPostProcessor。)函數

context:annotation-config/僅在與其定義相同的應用程序上下文中的bean上查找註釋。這意味着若是將context:annotation-config/放入DispathcerServlet中的WebApplicationContext,它僅僅檢查controller中的@Autowired bean,而不堅持service。ui

1 @Required

使用@Required註解應用於bean屬性的setter方法,例以下面的例子:this

public class SimpleMovieLister {
	private MovieFinder movieFinder;

	@Required
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}

	// ...
}

這個註解只是簡單的表示受影響的bean屬性必須在配置時經過bean定義或者自動裝配中的顯示屬性值來填充。若是未注入受影響的bean屬性,容器將拋出異常。這能夠產生當即和明確的錯誤,從而在後面避免NullPointerException異常等。仍然建議將斷言放入bean類自己,例如將其放入init方法中。這樣作即便在容器以外使用類時也會執行這些必須的引用。spa

2 @Autowired

JSR 330 的@Inject註解能夠用來替代下面例子中的Spring @Autowired註解。

能夠將@Autowired註解應用於構造函數:

public class MovieRecommender {
	private final CustomerPreferenceDao customerPreferenceDao;

	@Autowired
	public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
		this.customerPreferenceDao = customerPreferenceDao;
	}
}

從Spring Framework 4.3開始,若是目標bean只定義了一個構造函數,@Autowired再也不必須。若是有多個構造函數,至少其中一個必須被註解爲了告訴容器它要使用哪一個。

也能夠將@Autowired註解應用於傳統的setter方法:

public class SimpleMovieLister {
	private MovieFinder movieFinder;

	@Autowired
	public void setMovieFinder(MovieFinder movieFinder) {
		this.movieFinder = movieFinder;
	}
}

還能夠應用註解到任意方法名和/或多個參數的方法:

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

能夠混合應用@Autowired於字段和構造函數:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

還能夠經過將註解添加到數組字段或方法上來注入容器中特定類型的全部bean。

public class MovieRecommender {
	
	@Autowired
	private MovieCatalog[] movieCatalogs;

}

一樣適用於集合類型:

public class MovieRecommender {
	private Set<MovieCatalog> movieCatalogs;

	@Autowired
	public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs){
		this.movieCatalogs = movieCatalogs;
	}
}

若是須要將數組和列表中的元素按指定的順序排序,能夠實現org.springframework.core.Ordered接口或者使用@Order或標準的@Priority註解。

甚至Map類型也能夠被自動裝配,只要key的類型是String。Map的值包含全部指望類型的bean,而且key包含相關bean的名字:

public class MovieRecommender {
	private Map<String, MovieCatalog> movieCatalogs;

	@Autowired
	public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
		this.movieCatalogs = movieCatalogs;
	}
}

默認的,若是沒有有效的候選bean,自動裝配會失敗;默認行爲是將註釋的方法、構造函數和字段視爲必須的依賴關係。這個行爲能夠以下修改:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...

}

每一個class只有一個註解構造函數能夠被標記爲required,可是能夠標記多個no-required構造函數。在這種狀況下,每一個構造函數都被認爲是候選者而且Spring使用最可靠的構造函數,其依賴性能夠被知足,也就是具備最多參數的構造函數。

推薦使用@Autowired的required屬性而不是@Required註解。required屬性表示了屬性對於自動裝配目的不是必須的,若是它不能被自動裝配,那麼屬性就會忽略了(???)。另外一方面,@Required更健壯一些,它強制了由容器支持的各類方式的屬性設置。若是沒有注入任何值,就會拋出對應的異常。

還能夠在衆所周知的可解析依賴關係的接口上使用@Autowired註解:BeanFactory、ApplicationContext、Environment、ResourceLoader、APplicationEventPublisher和MessageSource。這些接口和它們的子接口,例如ConfigurableApplicationContext或者ResourcePatternResolver,會自動解析,不用特殊的設置。

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

@Autowired、@Inject、@Resource和@Value註解被Spring的BeanPostProcessor實現處理,這意味着不能將這些註解應用於本身的BeanPostProcessor或者BeanFactoryPostProcessor類型。這些類型必須經過XML或者Spring @Bean 方法自動裝配。

3 使用@Primary微調基於註解的自動裝配

因爲經過類型的自動裝配可能會致使多個候選者,因此常常須要對選擇處理作更多的控制。一種方法是使用Spring的@Primary註解。@Primary註解表示當多個bean是自動裝配單一依賴項的候選者時,應給予指定的bean更高的優先級。若是在候選者中有一個「primary」 bean,它將是自動裝配的值。

假設有以下的配置定義了firstMovieCatalog爲優先的MovieCatalog。

@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...

}

使用這個配置,下面的MovieRecommender將會自動裝配爲firstMovieCatalog。

public class MovieRecommender {
	@Autowired
	private MovieCatalog movieCatalog;

}

相應的XML bean定義配置以下:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog" primary="true">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

4 使用qualifiers微調基於註解的自動裝配

在經過類型自動裝配時,@Primary是一種有效的方式從許多實例中決定一個主要的候選者。當選擇處理須要更多的控制時,可使用Spring的@Qualifier註解。能夠將限定值和指定的參數關聯起來,縮小匹配的範圍來爲每一個參數選擇指定的bean。在最簡單的例子中,這能夠是文本描述的值:

public class MovieRecommender {
	@Autowired
	@Qualifier("main")
	private MovieCatalog movieCatalog;

}

@Qualifier註解也能夠用於單個構造函數參數或者方法參數:

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...

}

相應的bean定義以下。具備限定值「main」的bean被注入到具備相同值的構造函數參數。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

對於回退匹配(???),bean的名字被認爲是默認的限定值。所以能夠將bean的id定義爲main取代相關的限定元素,能夠達成相同的匹配結果。然而儘管可使用此約定經過名稱來引用指定的bean,@Autowired註解基本上是類型驅動注入和可選語言限定值的。這意味着限定值加上bean名字回退,老是縮小類型匹配的範圍,它們不意味着表示一個指向惟一bean的引用。好的限定值是"main"或者"EMEA"或者"persistent",它們表達指定組件的特徵,而不依賴於bean的id,bean的id在匿名bean定義的狀況下也許是自動建立的(???)。

限定值也應用於集合類型,例如Set<MovieCatalog>。在這種狀況下,全部與聲明的限定值匹配的bean被注入到集合中。這意味着限定值沒必要惟一;它們僅僅構成過濾標準。例如,能夠定義多個MovieCatalog bean使用相同的限定值"action",全部這些bean都會被注入到標註了@Qualifier("action")註解的Set<MovieCatalog>中。

若是打算使用按類型的註解驅動注入,請勿使用@Autowired,即便使用@Qualifier的值引用一個bean的名字在技術上是可行的。做爲替代,使用JSR-250的@Resource註解,它在語義上經過惟一的名字定義了一個指定的目標組件,聲明的類型與匹配過程無關。@Autowired擁有許多不一樣的語義:在經過類型選擇協做bean以後,指定的字符串限定值將盡在這些經過類型選出的候選者中被考慮,例如將「account」限定值與標記有相同限定值標籤的bean相匹配。

對於bean自身被定義爲集合/映射或者數組類型,@Resource經過惟一的名字指定特殊的集合或者數組bean是一個好的解決方案。即在4.3中,集合/映射或者數組類型也能夠經過Spring的@Autowired的類型匹配算法進行匹配,只要元素的類型信息被@Bean方法的返回類型簽名或者集合繼承關係提供。在這種狀況下,限定值能夠被用於從相同類型集合中選擇,像上文所述。

在4.3版本,@Autowired也將自身引用歸入注入範圍,即引用回目前注入的bean。注意自身注入是一種回退;正規的其它組件的依賴老是優先的。在這種意義下,自引用不參加常規候選的選擇而且所以從不是優先的;另外一方面,它們老是有最低的優先級。在事件中,只能使用自引用做爲最後的手段,即經過bean的事務代理在統一實例上調用其餘方法:在這種狀況下,考慮將受影響的方法分解爲單獨的委託bean(???)。另外,使用@Resource能夠經過惟一的名字獲得當前bean的代理。@Autowired應用與字段、構造函數和多參數方法,容許在參數級別經過限定值縮小範圍。相比之下,@Resource僅僅支持字段和單一參數的bean屬性setter方法。所以,若是注入目標是構造函數或多參數方法請使用限定值。

能夠定義本身的限定值註解。定義一個註解並將其用@Qualifier標準便可。

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {

    String value();
}

而後能夠在須要自動裝配的字段和參數上使用自定義的限定值註解。

public class MovieRecommender {

    @Autowired
    @Genre("Action")
    private MovieCatalog actionCatalog;
    private MovieCatalog comedyCatalog;

    @Autowired
    public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
        this.comedyCatalog = comedyCatalog;
    }

    // ...

}

下一步,提供協做bean定義的信息。可使用<qualifier/>標籤做爲<bean/>的子標籤,而後指定type屬性和value屬性來匹配自定義的限定值註解。type匹配註解的徹底限定類名。或者,爲了方便,在沒有名稱衝突的狀況可使用短類名。兩種方法都在下面例子中展現:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="Genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="example.Genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

在某些狀況下,使用沒有值的註解可能就足夠了。當註釋提供更通用的目的而且應用於跨不一樣類型的依賴性時,這多是有用的。例如,可能會提供一個離線目錄,當沒有Internet鏈接可用時將被搜索。首先定義一個簡單的註解:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {

}

而後用註解註釋那些要自動裝配的字段或者屬性:

public class MovieRecommender {

    @Autowired
    @Offline
    private MovieCatalog offlineCatalog;

    // ...

}

如今bean定義僅僅須要一個限定值類型:

<bean class="example.SimpleMovieCatalog">
    <qualifier type="Offline"/>
    <!-- inject any dependencies required by this bean -->
</bean>

還能夠建立自定義的限定值註解,接受額外的name屬性或者用name屬性替代value屬性。若是多個屬性值限定了將要自動裝配的字段或者參數,匹配全部屬性值的bean定義纔會成爲候選者。做爲例子,考慮下面的註解定義:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {

    String genre();

    Format format();

}

在這個例子中Format是一個枚舉類型:

public enum Format {
    VHS, DVD, BLURAY
}

要自動裝配的字段用自定義的限定註解註釋幷包含genre和format兩個屬性。

public class MovieRecommender {

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Action")
    private MovieCatalog actionVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Comedy")
    private MovieCatalog comedyVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.DVD, genre="Action")
    private MovieCatalog actionDvdCatalog;

    @Autowired
    @MovieQualifier(format=Format.BLURAY, genre="Comedy")
    private MovieCatalog comedyBluRayCatalog;

    // ...

}

最終,bean定義包含匹配的限定值。這個例子也展現bean meta標籤能夠替代<qualifier/>子元素。若是可用<qualifier/>及其屬性優先,可是若是沒有這樣的限定值,則自動裝配機制落在<meta/>元素上,如如下例子中的最後兩個bean定義。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Action"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Comedy"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="DVD"/>
        <meta key="genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="BLURAY"/>
        <meta key="genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

</beans>

5 使用範型做爲自動裝配的限定值

除了@Qualifier註釋值爲,還可使用Java範型做爲隱式的限定值。例如,假設有下面的配置:

@Configuration
public class MyConfiguration {

    @Bean
    public StringStore stringStore() {
        return new StringStore();
    }

    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore();
    }

}

假設上面的bean實現了一個範型接口,即Store<String>和Store<Integer>,可使用使用@Autowired註釋Store接口而且範型會被用做限定值:

@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean

@Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean

範型限定值也應用於自動裝配列表、映射和數組:

// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;

6 CustomAutowireConfigurer

CustomAutowireConfigurer是一個BeanFactoryPostProcessor,它可使你註冊本身定義的限定註解類型,甚至它們能夠不被Spring的@Qualifier註解註釋。

<bean id="CustomAutowireConfigurer"
		class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
		<property name="customQualifierTypes">
			<set>
				<value>example.CustomerQualifier</value>
			</set>
		</property>
</bean>

AutowireCandidateResolver經過如下信息決定自動裝配候選者:

  • 每一個bean定義中autowire-candidate的值;
  • <bean/>元素中任何可用的default-autowire-candidates模式;
  • @Qualifier註解和任何使用CustomAutowireConfigurer註冊的用戶自定義的註解。

若是多個bean被限定爲自動裝配候選者,優先者按以下選出:若是其中一個bean定義將primary屬性設置爲true,則它將被選中。

7 @Resource

Spring也支持使用JSR-250的@Resource註解註釋字段或者bean屬性的setter方法進行注入。這是Java EE 5和6中的常見方式,例如在JSF1.2中管理的bean和JAX-WS 2.0端點。Spring也Spring管理的對象支持這種模式。

@Resource有一個name屬性,而且默認的將這個值解釋爲被注入bean的名字。換句話說,它符合by-name場景,正以下面的例子所示:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder")
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

若是沒有明確的指定name,將從字段名或者setter方法派生出默認的名字。在字段狀況下,將使用字段名;在setter方法的狀況下,使用bean屬性名。因此下面的例子將會把名爲"movieFinder"的bean注入setter方法中:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

註解提供的名字是經過ApplicationConext的CommonAnnotationBeanPostProcessor解析的。能夠經過JNDI解析名字,若是明確的配置了Spring的SimpleJndiBeanFactory。然而,建議依賴默認的行爲而且簡單的使用Spring的JNDI查找能力來保持解耦。

在沒有明確指定名稱的@Resource狀況下,相似於@Autowired,@Resource查找優先級類型匹配取代一個指定名字的bean而且解析衆所周知的可解析依賴關係:BeanFactory,ApplicationContext,ResourceLoader,ApplicationEventPublisher和MessageSource接口(就是說使用@Resource容器也會自動裝配這些接口)。

所以在下面的例子中,customerPreferenceDao字段首先查找一個名爲customerPreferenceDao的bean,而後回退到CutomerPreferenceDao的優先級類型匹配。「context」字段被注入基於已知的可解析依賴關係類型ApplicationContext。

public class MovieRecommender {

    @Resource
    private CustomerPreferenceDao customerPreferenceDao;

    @Resource
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

8 @PostConstruct 和 @PreDestory

CommonAnnotationBeanPostProcessor不只識別@Resource註解也識別JSR-250的聲明週期註解。這是在Spring2.5中引入的,對這些註釋的支持爲初始化回調和銷燬回調中描述方法的提供了另外一種替代。只要CommonAnnotationBeanPostProcessor在Spring ApplicationContext中註冊,被其中一個註解註釋的方法在生命週期的於相應的Spring生命週期接口方法或明確聲明的回調函數在相同點被調用。在下面的例子中,緩存將在初始化時預先填充,並在銷燬前清除。

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }

    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }

}
相關文章
相關標籤/搜索