源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

Spring Java-based容器配置详解

  • 时间:2020-12-10 12:05 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:Spring Java-based容器配置详解
装Java-based的配置 使用 @Import [url=http://www.1sucai.cn/article/124275.htm]注解[/url] 跟在Spring XML文件中使用<import>元素添加模块化的配置类似,@Import注解允许你加载其他配置类中的@Bean定义:
@Configuration
public class ConfigA {
 @Bean
   public A a() {
  return new A();
 }
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
 @Bean
   public B b() {
  return new B();
 }
}
组现在,当实例化上下文时,你只需要显式的指定ConfigB,而不需要既提供ConfigA.class,又提供ConfigB.class:
public static void main(String[] args) {
 ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
 // now both beans A and B will be available...
 A a = ctx.getBean(A.class);
 B b = ctx.getBean(B.class);
}
这种方式简化了容器的初始化,因为只需要处理一个类,而不是让开发者记住构造期间的大量@Configuration类。 导入[b][url=http://www.1sucai.cn/article/124326.htm]@Bean[/url][/b]的依赖注入 上面的示例可以工作,但太简单。在大多数实际的场景中,beans会依赖另一个跨配置类的bean。当使用XML时,这不是问题,因为不涉及到编译,其中一个bean只需要声明ref="someBean",剩下的交给Spring在容器初始化期间处理即可。当然,当使用@Configuration类时,Java编译器对配置模式产生一些限制,对其他beans的引用必须是合法的java语法。 幸运的是,解决该问题是很容易的。正如我们[url=https://docs.spring.io/spring/docs/4.2.0.RC1/spring-framework-reference/htmlsingle/#beans-java-dependencies]已经讨论[/url]的,@Bean可以有任意多个用来描述bean依赖的参数。让我们探讨一个更现实的场景,在这里将使用一些彼此依赖的[b]@Configuration[/b]类:
@Configuration
public class ServiceConfig {
 @Bean
   public TransferService transferService(AccountRepository accountRepository) {
  return new TransferServiceImpl(accountRepository);
 }
}
@Configuration
public class RepositoryConfig {
 @Bean
   public AccountRepository accountRepository(DataSource dataSource) {
  return new JdbcAccountRepository(dataSource);
 }
}
@Configuration
@Import({
 ServiceConfig.class, RepositoryConfig.class
}
)
public class SystemTestConfig {
 @Bean
   public DataSource dataSource() {
  // return new DataSource
 }
}
public static void main(String[] args) {
 ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
 // everything wires up across configuration classes...
 TransferService transferService = ctx.getBean(TransferService.class);
 transferService.transfer(100.00, "A123", "C456");
}
这里有另外的方法可以达到相同的效果。记住,@Configuration根本上只是容器中的另一个bean-这意味着它们可以像其他bean那样充分利用@Autowired注入元数据。 注: 确保以这种方式注入的都是简单类型的。@Configuration类在容器初始化时被处理的相当早,用这种方式强制注入依赖可能导致无法预料地过早初始化问题。只要有可能就采用上面示例中基于参数的注入方式。
@Configuration
public class ServiceConfig {
 @Autowired
   private AccountRepository accountRepository;
 @Bean
   public TransferService transferService() {
  return new TransferServiceImpl(accountRepository);
 }
}
@Configuration
public class RepositoryConfig {
 @Autowired
   private DataSource dataSource;
 @Bean
   public AccountRepository accountRepository() {
  return new JdbcAccountRepository(dataSource);
 }
}
@Configuration
@Import({
 ServiceConfig.class, RepositoryConfig.class
}
)
public class SystemTestConfig {
 @Bean
   public DataSource dataSource() {
  // return new DataSource
 }
}
public static void main(String[] args) {
 ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
 // everything wires up across configuration classes...
 TransferService transferService = ctx.getBean(TransferService.class);
 transferService.transfer(100.00, "A123", "C456");
}
在上面的示例中,使用@Autowired工作的很好,并且提供了想要的模块化,但要确切地指明自动注入的bean定义在哪声明依旧有点模糊。例如,一个开发者正在查看ServiceConfig,那你怎么准确地知道@Autowired AccountRepository bean在哪声明的?在代码中并不明确,不过有时候这样就行。记着[url=https://spring.io/tools/sts]Spring Tool Suite[/url]可以提供渲染图的工具,这些图展示了Spring Bean之间是怎么连起来的-这可能是你需要的。同时,你的Java IDE可以轻松的找到所有声明和使用AccountRepository类型的bean,并为你快速展现返回该类型的@Bean方法位置。 如果你不能接受这种模糊性,并希望在你的IDE中可以从一个@Configuration类导航到另一个,那就考虑注入配置类本身:
@Configuration
public class ServiceConfig {
 @Autowired
   private RepositoryConfig repositoryConfig;
 @Bean
   public TransferService transferService() {
  // navigate 'through' the config class to the @Bean method!
  return new TransferServiceImpl(repositoryConfig.accountRepository());
 }
}
在上面的解决方案中,我们可以很明确地知道AccountRepository定义的地方。然而,ServiceConfig现在紧紧地跟RepositoryConfig耦合了。这就是权衡。紧耦合在某种程度上可以通过使用基于接口或抽象类的@Configuration类来减轻。考虑以下内容:
@Configuration
public class ServiceConfig {
 @Autowired
   private RepositoryConfig repositoryConfig;
 @Bean
   public TransferService transferService() {
  return new TransferServiceImpl(repositoryConfig.accountRepository());
 }
}
@Configuration
public interface RepositoryConfig {
 @Bean
   AccountRepository accountRepository();
}
@Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {
 @Bean
   public AccountRepository accountRepository() {
  return new JdbcAccountRepository(...);
 }
}
@Configuration
@Import({
 ServiceConfig.class, DefaultRepositoryConfig.class
}
) // import the concrete config!
public class SystemTestConfig {
 @Bean
   public DataSource dataSource() {
  // return 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和它们的依赖就变得跟平常处理基于接口的代码导航没区别了。 [b]有条件的包含@Configuration类或@Beans[/b] 基于任意的系统状态,有条件地禁用一个完整的@Configuration类,甚至单独的@Bean方法通常是很有用的。一个常见的示例是,当一个特定的profile在Spring Environment中启用时,使用@Profile注解激活beans。 @Profile注解实际上实现了一个非常灵活的注解[url=https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Conditional.html]:@Conditional[/url]。@Conditional注解意味着在注册@Bean之前,必须先咨询指定的org.springframework.context.annotation.Condition实现。 Condition接口的实现者只需简单地提供一个返回true或false的matches(…​)方法。例如,下面是@Profile注解采用的Condition实现:
@Override
public Boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
 if (context.getEnvironment() != null) {
  // Read the @Profile annotation attributes
  MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
  if (attrs != null) {
   for (Object value : attrs.get("value")) {
    if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
     return true;
    }
   }
   return false;
  }
 }
 return true;
}
具体参考[url=https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Conditional.html]@Conditional javadocs[/url]。 结合Java和XML配置 Spring @Configuration类支持目的不是想要100%的替换Spring XML。一些设施,比如Spring XML命名空间仍旧是配置容器的完美方式。在XML很方便或必须的情况下,你有个选择:采用”XML为中心”的方式实例化容器,比如ClassPathXmlApplicationContext,或使用AnnotationConfigApplicationContext以”Java为中心”的方式,并使用@ImportResource注解导入需要的XML。 在以”XML为中心”的情况下使用@Configuration类 从XML启动Spring容器,以特设模式包含@Configuration类可能是个更可选的方式。例如,在一个已经存在的使用Spring XML的大型代码库中,遵循按需原则创建@Configuration,并从现有的XML文件中包括它们是非常容易的。下面你将找到在这样的”XML为中心”的解决方案中使用@Configuration类的可选项。 记着@Configuration类本质上只是容器中的bean定义。在下面的示例中,我们创建了一个名称为AppConfig的@Configuration类,并将它作为<bean/>定义包含到system-test-config.xml中。因为<context:annotation-config/>是开启的,容器将会识别@Configuration注解,并正确地处理AppConfig中声明的@Bean方法。
@Configuration
public class AppConfig {
 @Autowired
   private DataSource dataSource;
 @Bean
   public AccountRepository accountRepository() {
  return new JdbcAccountRepository(dataSource);
 }
 @Bean
   public TransferService transferService() {
  return new TransferService(accountRepository());
 }
}
[b]ystem-test-config.xml[/b]如下:
<beans>
  <!-- enable processing of annotations such as @Autowired and @Configuration -->
  <context:annotation-config/>
  <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
  <bean class="com.acme.AppConfig"/>
  <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
  </bean>
</beans>
[b]jdbc.properties[/b]如下:
jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
[b]main[/b]方法如下:
public static void main(String[] args) {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
  TransferService transferService = ctx.getBean(TransferService.class);
  // ...
}
[b]注[/b]: 在上面的system-test-config.xml中,AppConfig<bean/>没有声明一个id元素。如果没有bean引用它,那就没有必要指定id元素,否则就要通过name从容器获取bean(name对应bean定义中声明的id)。DataSource也一样-它只是通过类型自动注入(autowired by type),所以并不需要显式的分配一个bean id。 由于@Configuration被@Component元注解了(被注解注解,很拗口),所以被@Configuration注解的类自动成为组件扫描(component scanning)的候选者。同样使用上面的场景,我们可以重新定义system-test-config.xml来充分利用组件扫描。注意在这个示例中,我们不需要明确声明<context:annotation-config/>,因为<context:component-scan/>启用了同样的功能。 [b]system-test-config.xml[/b]如下:
<beans>
  <!-- picks up and registers AppConfig as a bean definition -->
  <context:component-scan base-package="com.acme"/>
  <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>


  <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
  </bean>
</beans>
在@Configuration”类为中心”的情况下使用@ImportResourcedaoru导入XML 在将@Configuration类作为配置容器的主要机制的应用中,仍旧存在对XML的需求。在那些场景中,可以使用@ImportResource,并定义所需的XML。这样做可以实现以”Java为中心”的方式配置容器,并保留最低限度的XML。
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
 @Value("${jdbc.url}")
   private String url;
 @Value("${jdbc.username}")
   private String username;
 @Value("${jdbc.password}")
   private String password;
 @Bean
   public 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=
main方法如下:
public static void main(String[] args) {
  ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
  TransferService transferService = ctx.getBean(TransferService.class);
  // ...
}
[b]总结[/b] 以上就是本文关于Spring Java-based容器配置详解的全部内容,感兴趣的朋友可以继续参阅:[url=http://www.1sucai.cn/article/124326.htm]Java之Spring注解配置bean实例代码解析[/url]、[url=http://www.1sucai.cn/article/124275.htm]浅谈Java注解和动态代理[/url]等,希望对大家有所帮助。有不足之处,欢迎留言指正。感谢朋友们对编程素材网网站的支持!
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部