默认情况下,框架Spring容器中的于注注解配置没有被打开。因此,容器在我们使用基于注解的配置配置之前,我们需要在Spring配置文件中启用它。框架因此,于注如果你想在你的容器Spring应用程序中使用任何注解,请考虑以下配置文件。配置 @Required注解是框架方法级注解,适用于Bean的于注setter方法。这个注解简单地表明setter方法必须在配置时被配置为具有依赖注入的容器值。 @Component@Component public class SimpleMovieLister { private MovieFinder movieFinder; @Required public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // ... 属性movieFinder必须存在,配置若注入时为null,框架会抛NullPointerException异常。于注 我们可以使用@Autowired来标记Spring将要解析和注入的容器依赖关系。我们可以在构造函数、Setter或字段注入中使用这个注解。 构造函数注入class Car { private Engine engine; @Autowired Car(Engine engine) { this.engine = engine; } }Setter 注入class Car { private Engine engine; @Autowired void setEngine(Engine engine) { this.engine = engine; } }字段注入class Car { @Autowired private Engine engine; 当有多个相同类型的Bean时,使用@Primary来给一个Bean更高的优先权。 为什么需要@Primary?在某些情况下,我们需要注册超过一个相同类型的Bean。在这个例子中,我们有mySQLConnection()和oracleConnection()的Connection类型的源码下载bean。 @Configuration public class Config { @Bean public Connection mySQLConnection() { return new MySQLConnection(); } @Bean public Connection oracleConnection() { return new OracleConnection(); } 如果我们运行该应用程序,Spring会抛出NoUniqueBeanDefinitionException。为了访问具有相同类型的Bean,我们通常使用@Qualifier("beanName")注解,和@Autowired一起应用。在我们的案例中,我们在配置阶段配置Bean,所以@Qualifier不能在这里应用。关于@Qualifier会在本章后面讲到。 为了解决这个问题,Spring提供了@Primary注解。下面的例子展示了如何在一个Spring应用程序中使用@Primary注解。 @Primary注解可用于任何直接或间接用@Component注解的类或用@Bean注解的工厂方法。在这个例子中,我们将使用@Primary注解和@Component注解。 package com.demo.spring.primary; public interface MessageService { public void sendMsg(); }package com.demo.spring.primary; import org.springframework.stereotype.Component; @Component public class FacebookMessageService implements MessageService { @Override public void sendMsg() { System.out.println("FacebookMessageService implementation here"); } }package com.demo.spring.primary; import org.springframework.stereotype.Component; @Component public class EmailMessageService implements MessageService { @Override public void sendMsg() { System.out.println("EmailMessageService Implementation here"); } }package com.demo.spring.primary; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; @Primary @Component public class TwitterMessageService implements MessageService { @Override public void sendMsg() { System.out.println("TwitterMessageService Implementation here"); } 请注意,在上述TwitterMessageService类中,我们添加了@Primary与@Component注解。 package com.demo.spring.primary; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = "com.demo.spring.primary") public class AppConfig { }public class Application { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); MessageService messageService = context.getBean(MessageService.class); messageService.sendMsg(); context.close(); } 当我们创建了多个相同类型的Bean,但只想将其中一个与某个属性关联。可以使用@Qualifier注解和@Autowired注解来控制。 @Qualifier用于解决模糊的依赖关系,也就是说,它帮助@Autowired注解选择其中一个依赖关系。云南idc服务商如果一个接口有多种实现,那么我们可以在运行时使用@Qualifier来选择所需的实现。 public interface MessageService { public void sendMsg(String message); }public class EmailService implements MessageService{ public void sendMsg(String message) { System.out.println(message); } }public class TwitterService implements MessageService{ public void sendMsg(String message) { System.out.println(message); } }public class SMSService implements MessageService{ public void sendMsg(String message) { System.out.println(message); } }public interface MessageProcessor { public void processMsg(String message); } public class MessageProcessorImpl implements MessageProcessor { private MessageService messageService; // setter based DI @Autowired @Qualifier("TwitterService") public void setMessageService(MessageService messageService) { this.messageService = messageService; } // constructor based DI @Autowired public MessageProcessorImpl(@Qualifier("TwitterService") MessageService messageService) { this.messageService = messageService; } public void processMsg(String message) { messageService.sendMsg(message); } }@Configuration @ComponentScan("com.demo.springframework.di") public class AppConfiguration { @Bean(name="emailService") public MessageService emailService(){ return new EmailService(); } @Bean(name="twitterService") public MessageService twitterService(){ return new TwitterService(); } @Bean(name="smsService") public MessageService smsService(){ return new SMSService(); } @Bean public MessageProcessor messageProcessor(){ return new MessageProcessorImpl(twitterService()); } }public class TestApplication { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfiguration.class); MessageProcessor userService = applicationContext.getBean(MessageProcessor.class); userService.processMsg("twitter message sending "); } Spring支持通过@Resource(javax.annotation.Resource)方式注入,可以在字段或setter方法上加该注解,@Resource有一个name属性,如果不指定name,默认就是字段或setter方法名称。 public class SimpleMovieLister { private MovieFinder movieFinder; @Resource(name="myMovieFinder") public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }public class SimpleMovieLister { private MovieFinder movieFinder; @Resource public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } 该注解可用于向Spring管理的Bean中的字段注入值,它可以应用于字段或构造函数/方法参数级别。 我们需要一个属性文件来定义我们想用@Value注解注入的值。因此,我们首先需要在我们的配置类中定义一个@PropertySource--带有属性文件名。 value.from.file=Value got from the file priority=high 注意:Spring Boot默认配置了一个PropertySourcesPlaceholderConfigurer的Bean,它将从application.properties和application.yml文件中获取属性。 @Value("${ value.from.file}") 有时,我们需要注入一堆值。将它们定义为属性文件中单个属性用逗号分隔的值,或定义为系统属性并注入一个数组。例如listOfValues中定义了逗号分隔的值,所以数组的值将是["A","B", "C"]。 @Value("${ listOfValues}") 使用SpEL表达式获取配置文件中priority的值。站群服务器 @Value("#{ systemProperties[priority]}") 如果在property文件中没有定义属性,就会报nullvalue异常。为了防止这种情况,我们可以在SpEL表达式中提供一个默认值。如果属性没有定义,我们就为该字段设置默认值。 @Value("#{ systemProperties[unknown] ?: some default}") 我们也可以用其它bean的属性值: @Value("#{ someBean.someValue}") 从属性配置中获取List列表: @Value("#{ ${ listOfValues}.split(,)}") 把@Value注入到Map加入propeties文件中有如下key: 注意,Map中的值必须是单引号。 @Value("#{ ${ valuesMap}}") 如果要获取map中指定的key: @Value("#{ ${ valuesMap}.key1}") 如果不确定Map中是否包含key,我们可以使用一个安全的表达式,使其不会抛出异常,并且设置值为null: @Value("#{ ${ valuesMap}[unknownKey]}") 为属性设置默认值: @Value("#{ ${ unknownMap : { key1: 1, key2: 2}}}") private Map @Value("#{ ${ valuesMap}[unknownKey] ?: 5}") 注入前过滤不需要的值: @Value("#{ ${ valuesMap}.?[value>1]}") private Map @PropertySource("classpath:application.properties") public class PriorityProvider { private String priority; @Autowired public PriorityProvider(@Value("${ priority:normal}") String priority) { this.priority = priority; } // standard getter 注意:默认配置文件是application.properties或application.yaml则不需要@PropertySource注解。 与Setter一起注入@Component @PropertySource("classpath:values.properties") public class CollectionProvider { private List @Autowired public void setValues(@Value("#{ ${ listOfValues}.split(,)}") List this.values.addAll(values); } // standard getter 我们可以自定义Bean的创建和销毁附动作。我们可以通过实现InitializingBean和DisposableBean接口来实现它。我们也可以用@PostConstruct和@PreDestroy注解来实现。 Spring只调用一次用@PostConstruct注释的方法,就在Bean属性初始化之后。请记住,即使没有任何东西需要初始化,这些方法也会运行。带有@PostConstruct注释的方法不能是静态的。 @Component public class DbInit { @Autowired private UserRepository userRepository; @PostConstruct private void postConstruct() { User admin = new User("admin", "admin password"); User normalUser = new User("user", "user password"); userRepository.save(admin, normalUser); } 带有@PreDestroy注解的方法只运行一次,就在Spring将我们的Bean从容器中移除之前。带有@PreDestroy注解的方法不能是静态的。 @Component public class UserRepository { private DbConnection dbConnection; @PreDestroy public void preDestroy() { dbConnection.close(); }