<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 4.12 基于 Java 的容器配置 ### 4.12.1 基本概念:@Configuration 和@Bean Spring 中新的 Java 配置支持的核心就是@Configuration 注解的類。這些類主要包括 @Bean 注解的方法來為 Spring 的 IoC 容器管理的對象定義實例,配置和初始化邏輯。 使用@Configuration 來注解類表示類可以被 Spring 的 IoC 容器所使用,作為 bean 定義的資源。最簡單的@Configuration 類可以是這樣的: ``` @Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } } ``` 這和 Spring 的 XML 文件中的`<beans/>`非常類似,上面的 AppConfig 類和下面的代碼是等同的: ``` <beans> <bean id="myService" class="com.acme.services.MyServiceImpl"/> </beans> ``` 正如你看到的,@Bean 注解扮演了和`<bean/>`元素相同的角色。@Bean 注解會在下面 的章節中詳細地討論。首先,我們要來看看使用基于 Java 的配置創建 Spring 容器的各種方 式。 ### 4.12.2 使用 AnnotationConfigApplicationContext 實例化 Spring 容器 下面的章節說明了 Spring 的 AnnotationConfigApplicationContext,在 Spring 3.0 中 是 新加 入 的 。這 個 全 能的 ApplicationContext 實 現 類 可 以 接 受不 僅 僅 是 @Configuration 類作為輸入,也可以是普通的@Component 類,還有使用 JSR-330 元數 據注解的類。 當@Configuration 類作為輸入時,@Configuration 類本身作為 bean 被注冊了, 并且類內所有聲明的@Bean 方法也被作為 bean 注冊了。 當@Component 和 JSR-330 類 作為輸 入時, 它們 被注冊 為 bea n,并 且被 假設如 @Autowired 或@Inject 的 DI 元數據在類中需要的地方使用。 #### 4.12.2.1 簡單構造 當實例化 ClassPathXmlApplicationContext 時,以大致相同的方式,當實例化 AnnotationConfigApplicationContext 時,@Configuration 類可能被作為輸入。這 就允許在 Spring 容器中完全可以不使用 XML: ``` public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig. class); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); } ``` 正如上面所提到的,AnnotationConfigApplicationContext 不僅僅局限于和 @Configuration 類合作。任意@Component 或 JSR-330 注解的類都可以作為構造方法的輸入。比如: ``` public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.MyService myService = ctx.getBean(MyService.class); myService.doStuff(); } ``` 上面假設 MyServiceImpl,Dependency1 和 Dependency2 使用了 Spring 依賴注 入注解,比如@Autowired。 #### 4.12.2.2 使用 `register(Class<?>...)`來編程構建容器 AnnotationConfigApplicationContext 可以使用無參構造方法來實例化,之后使 用 register() 方 法 來 配 置 。 這 個 方 法 當 編 程 構 建 AnnotationConfigApplicationContext 時尤其有用。 ``` public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AppConfig.class, OtherConfig.class); ctx.register(AdditionalConfig.class); ctx.refresh(); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); } ``` #### 4.12.2.3 使用 scan(String..)開啟組件掃描 有經驗的 Spring 用戶肯定會熟悉下面這個 Spring 的 context:命名空間中的常用 XML 聲明 ``` <beans> <context:component-scan base-package="com.acme"/> </beans> ``` 在上面的示例中,com.acme 包就會被掃描,去查找任意@Component 注解的類,那些 類就會被注冊為 Spring 容器中的 bean。AnnotationConfigApplicationContext 暴露 出 scan(String ...)方法,允許相同的組件掃描功能: ``` public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.scan("com.acme"); ctx.refresh(); MyService myService = ctx.getBean(MyService.class); } ``` > ![](img/note.gif) > 注意 > 記得@Configuration 類是使用@Component 進行元數據注釋的,所以它們是組件掃 描的候選者!在上面的示例中,假設 AppConfig 是聲明在 com.acme 包(或是其中的子 包)中的,那么會在調用 scan()方法時被找到,在調用 refresh()方法時,所有它的@Bean 方法就會被處理并注冊為容器中的 bean。 #### 4.12.2.4 支 持 Web 應 用 的 AnnotationConfigWebApplicationContext WebApplicationContext 是 AnnotationConfigApplicationContext 的變種, 適用于 AnnotationConfigWebApplicationContext。當配置 Spring 的 Servlet 監聽器 ContextLoaderListener,Spring MVC 的 DispatcherServlet 等時,這個實現類就 可能被用到了。下面的代碼是在 web.xml 中的片段,配置了典型的 Spring MVC 的 Web 應用 程序。注意 contextClass 上下文參數和初始化參數的使用: ``` <web-app> <!-- 配置ContextLoaderListener使用 AnnotationConfigWebApplicationContext來代替默認的 XmlWebApplicationContext --> <context-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationCon figWebApplicationContext </param-value> </context-param> <!-- 配置位置必須包含一個或多個逗號或空格分隔的完全限定 @Configuration類。完全限定包也可以指定于組件掃描 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>com.acme.AppConfig</param-value> </context-param> <!-- 普通方式啟動根應用上下文的ContextLoaderListener --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- 普通方式聲明 Spring MVC 的 DispatcherServlet --> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <!-- 配置DispatcherServlet使用 AnnotationConfigWebApplicationContext來代替默認的 XmlWebApplicationContext --> <init-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.Annotation ConfigWebApplicationContext </param-value> </init-param> <!--配置位置必須包含一個或多個逗號或空格分隔的完全限定 @Configuration類--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>com.acme.web.MvcConfig</param-value> </init-param> </servlet> <!-- 映射所有的請求到/main/*中來派發servlet --> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/main/*</url-pattern> </servlet-mapping> </web-app> ``` ### 4.12.3 構成基于 Java 的配置 #### 4.12.3.1 使用@Import 注解 就像 Spring 的 XML 文件中使用的`<import/>`元素幫助模塊化配置一樣,@Import 注 解允許從其它配置類中加載@Bean 的配置: ``` @Configuration public class ConfigA { public @Bean A a() { return new A(); } } @Configuration @Import(ConfigA.class) public class ConfigB { public @Bean B b() { return new B(); } } ``` 現在,當實例化上下文時,不需要指定 ConfigA.class 和 ConfigB.class 了,僅 僅 ConfigB 需要被顯式提供: ``` public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class); // 現在bean A 和bean B都會是可用的... A a = ctx.getBean(A.class); B b = ctx.getBean(B.class); } ``` 這種方式簡化了容器的實例化,僅僅是一個類需要被處理,而不是需要開發人員在構造 時記住很多大量的@Configuration 類。 在引入的@Bean 定義中注入依賴 上面的示例是可行的,但是很簡單。在很多實際場景中,bean 會有依賴其它配置的類的依賴。當使用 XML 時,這本身不是什么問題,因為沒有調用編譯器,而且我們可以僅僅 聲明 ref="someBean" 并且相信 Spring 在 容 器 初 始化 時 可以 完 成。 當 然 ,當 使 用 @Configuration 的類時,Java 編譯器在配置模型上放置約束,對其它 bean 的引用必須 是符合 Java 語法的。 幸運的是,解決這個問題分層簡單。記得@Configuration 類最終是容器中的 bean- 這就是說它們可以像其它 bean 那樣利用@Autowired 注入元數據! 我們來看一個更加真實的語義,有幾個@Configuration 類,每個都依賴聲明在其它類中的 bean: ``` @Configuration public class ServiceConfig { private @Autowired AccountRepository accountRepository; public @Bean TransferService transferService() { return new TransferServiceImpl(accountRepository); } } @Configuration public class RepositoryConfig { private @Autowired DataSource dataSource; public @Bean AccountRepository accountRepository() { return new JdbcAccountRepository(dataSource); } } @Configuration @Import({ServiceConfig.class, RepositoryConfig.class}) public class SystemTestConfig { public @Bean DataSource dataSource() { /* 返回新的數據源 */ } } public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class); // 所有的裝配都使用配置的類... TransferService transferService = ctx.getBean(TransferService.class); transferService.transfer(100.00, "A123", "C456"); } ``` 完全限定引入的 bean 便于導航 在上面的場景中,使用@Autowired 工作正常,提供所需的模塊化,但是準確地決定 在哪兒聲明自動裝配的 bean 還是有些含糊。比如,作為開發者來看待 ServiceConfig, 你如何準確知道@Autowired AccountRepository 在哪里聲明的?它沒有顯式地出現 在代碼中,這可能很不錯。要記得 [SpringSource Tool Suite](http://www.springsource.com/products/sts) 提供工具可以生成展示所有對象是 如何裝配起來的圖片-那可能就是你所需要的。而且,你的 Java IDE 可以很容器發現所有的聲明,還有使用的 AccountRepository 類型,也會很快地給你展示出@Bean 方法的位置 和返回的類型。 在這種歧義不被接受和你想有直接從 IDE 中從一個@Configuration 類到另一個導航 的情景中,要考慮自動裝配配置類的本身: ``` @Configuration public class ServiceConfig { private @Autowired RepositoryConfig repositoryConfig; public @Bean TransferService transferService() { // 通過配置類到@Bean方法的導航! return new TransferServiceImpl(repositoryConfig.accountRepository()); } } ``` 在上面的情形中,定義 AccountRepository 是完全明確的。而 ServiceConfig 卻緊緊耦合到 RepositoryConfig 中了;這就需要我們來權衡了。這種緊耦合可以使用 基于接口或抽象基類的@Configuration 類來減輕。考慮下面的代碼: ``` @Configuration public class ServiceConfig { private @Autowired RepositoryConfig repositoryConfig; public @Bean TransferService transferService() { return new TransferServiceImpl(repositoryConfig.accountRepository()); } } @Configuration public interface RepositoryConfig { @Bean AccountRepository accountRepository(); } @Configuration public class DefaultRepositoryConfig implements RepositoryConfig { public @Bean AccountRepository accountRepository() { return new JdbcAccountRepository(...); } } @Configuration @Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // 導入具體的配置! public class SystemTestConfig { public @Bean DataSource dataSource() { /* 返回數據源 */ } } public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class); TransferService transferService = ctx.getBean(TransferService.class); transferService.transfer(100.00, "A123", "C456"); } ``` 現在 ServiceConfig 和 DefaultRepositoryConfig 的耦合就比較松了,并且內 建的 IDE 工具也一直有效:對于開發人員來說會更加簡單地獲取 RepositoryConfig 實現 類的類型層次。以這種方式,導航@Configuration 類和它們的依賴就和普通的基于接口 代碼的導航過程沒有任何區別了。 #### 4.12.3.2 結合 Java 和 XML 配置 Spring 的@Configuration 類并不是完全 100%地支持 Spring XML 替換的。一些基本特 性,比如 Spring XML 的命名空間會保持在一個理想的方式下去配置容器。在 XML 便于使用 或是必須要使用的情況下,你也有另外一個選擇:以“XML 為中心”的方式來實例化容器, 比如,ClassPathXmlApplicationContext,或者以“ Java 為中心”的方式,使用 AnnotationConfigurationApplicationContext 和@ImportResource 注解來引 入需要的 XML。 以“XML 為中心”使用@Configuration 類從一種特定的方式的包含@Configuration 類的 XML 文件啟動 Spring 容器是不錯的。 比如,在使用了 Spring XML 的大型的代碼庫中,根據需要并從已有的 XML 文件中創建 @Configuration 類是很簡單的。在下面,你會發現在這種“XML 為中心”情形下,使用 @Configuration 類的選擇。 以普通的 Spring `<bean/>`元素聲明@Configuration 類 要記得@Configuration 的類最終僅僅是容器中的 bean。在這個示例中,我們創建了 名為 AppConfig 的@Configuration 類,并且將它包含在 system-test-config.xml 文件中作為`<bean/>`的定義。因為開啟了`<context:annotation-config/>`配置,容器 會識別@Configuration 注解,以合適的方式處理聲明在 AppConfig 中@Bean 方法。 ``` @Configuration public class AppConfig { private @Autowired DataSource dataSource; public @Bean AccountRepository accountRepository() { return new JdbcAccountRepository(dataSource); } public @Bean TransferService transferService() { return new TransferService(accountRepository()); } } system-test-config.xml <beans> <!-- 開啟處理注解功能,比如@Autowired和@Configuration --> <context:annotation-config/> <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> <bean class="com.acme.AppConfig"/> <bean class="org.springframework.jdbc.datasource.DriverManagerData Source"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans> jdbc.properties jdbc.url=jdbc:hsqldb:hsql://localhost/xdb jdbc.username=sa jdbc.password= public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-t est-config.xml"); TransferService transferService = ctx.getBean(TransferService.class); // ... } ``` > ![](img/note.gif) > 注意 > 在上面的 system-test-config.xml 文件中,AppConfig 的`<bean/>`定義沒有聲明 id 元素。這么做也是可以接受的,就不必讓其它 bean 去引用它了。同時也就不可能從 容器中通過明確的名稱來獲取它了。同樣地,DataSource bean,通過類型自動裝配,那么明確的 bean id 就不嚴格要求了。 使用`<context:component-scan/>`來檢索@Configuration 類 因為@Configuration 是使用@Component 來元數據注解的,被@Configuration 注解的類是自動作為組件掃描的候選者的。使用上面相同的語義,我們可以重新來定義 system-test-config.xml 文件來利用組件掃描的優點。注意這種情況下,我們不需要 明確地聲明`<context:annotation-config/>`,因為`<context:component-scan/>` 開啟了相同的功能。 ``` system-test-config.xml <beans> <!-- 選擇并注冊AppConfig作為bean --> <context:component-scan base-package="com.acme"/> <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> <bean class="org.springframework.jdbc.datasource.DriverManagerData Source"> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans> ``` 使用了@ImportResource 導入 XML 的@Configuration 類為中心在@Configuration 類作為配置容器主要機制的應用程序中,使用一些 XML 還是必要的。 在這些情況中,僅僅使用@ImportResource 來定義 XML 就可以了。這么來做就實現了“Java 為中心”的方式來配置容器并保持 XML 在最低限度。 ``` @Configuration @ImportResource("classpath:/com/acme/properties-config.xml") public class AppConfig { private @Value("${jdbc.url}") String url; private @Value("${jdbc.username}") String username; private @Value("${jdbc.password}") String password; public @Bean DataSource dataSource() { return new DriverManagerDataSource(url, username, password); } } properties-config.xml <beans> <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/> </beans> jdbc.properties jdbc.url=jdbc:hsqldb:hsql://localhost/xdb jdbc.username=sa jdbc.password= public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig. class); TransferService transferService = ctx.getBean(TransferService.class); // ... } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看