默认情况下,Spring容器中的注解配置是没有开启的。因此,在我们可以使用基于注解的配置之前,我们需要在Spring配置文件中启用它。因此,如果您想在Spring应用程序中使用任何注解,请考虑以下配置文件。@Required注解是方法级别的注解,适用于Bean的setter方法。此注解仅指示setter方法必须在配置时配置为具有依赖注入值。@Component@ComponentpublicclassSimpleMovieLister{privateMovieFindermovieFinder;@RequiredpublicvoidsetMovieFinder(MovieFindermovieFinder){this.movi??eFinder=movieFinder;}//...}属性movieFinder必须存在。如果注入时为null,将抛出NullPointerException。@Autowired我们可以使用@Autowired来标记Spring将解析和注入的依赖项。我们可以在构造函数、setter或字段注入中使用此注解。构造函数注入类Car{privateEngine引擎;@AutowiredCar(Engineengine){this.engine=engine;}}Setter注入类Car{privateEngine引擎;@AutowiredvoidsetEngine(Engineengine){this.engine=engine;}}FieldinjectionclassCar{@AutowiredprivateEngineengine;}@Primary当有多个相同类型的bean时,使用@Primary给一个Bean更高的优先级。为什么需要@Primary?在某些情况下,我们需要注册多个相同类型的Bean。在这个例子中,我们有Connection类型的bean,带有mySQLConnection()和oracleConnection()。@ConfigurationpublicclassConfig{@BeanpublicConnectionmySQLConnection(){returnnewMySQLConnection();}@BeanpublicConnectionoracleConnection(){返回新的OracleConnection();如果我们运行应用程序,Spring会抛出NoUniqueBeanDefinitionException。为了访问相同类型的bean,我们通常使用@Qualifier("beanName")注解,与@Autowired一起应用。在我们的例子中,我们在配置阶段配置bean,所以@Qualifier不能在这里应用。关于@Qualifier,本章后面会提到。为了解决这个问题,Spring提供了@Primary注解。以下示例显示如何在Spring应用程序中使用@Primary注释。@Primary注解可用于直接或间接使用@Component注解的任何类或使用@Bean注解的工厂方法。在这个例子中,我们将使用@Primary注解和@Component注解。packagecom.demo.spring.primary;publicinterfaceMessageService{publicvoidsendMsg();}packagecom.demo.spring.primary;importorg.springframework.stereotype.Component;@ComponentpublicclassFacebookMes??sageServiceimplementsMessageService{@OverridepublicvoidsendMsg(){System.out.println("FacebookMes??sageServiceimplementationhere");}}packagecom.demo.spring.primary;importorg.springframework.stereotype.Component;@ComponentpublicclassEmailMessageServiceimplementsMessageService{@OverridepublicvoidsendMsg(){System.out.println("EmailMessageServiceImplementationhere");}}packagecom.demo.spring.primary;importorg.springframework.context.annotation.Primary;importorg.springframework.stereotype.Component;@Primary@ComponentpublicclassTwitterMessageServiceimplementsMessageService{@OverridepublicvoidsendMsg(){System.out.println("TwitterMessageService实现在这里");}}请注意,在上面的TwitterMessageService类中,我们添加了@Primary和@Component注解包com.demo.spring.primary;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;@Configuration@ComponentScan(basePackages="com.demo.spring.primary")publicclassAppConfig{}publicclassApplication{publicstaticvoidmain(String[]args){AnnotationConfigApplicationContextcontext=newAnnotationConfigApplicationContext(AppConfig.class);MessageServicemessageService=context.getBean(MessageService.class);消息服务.sendMsg();上下文.close();}}输出:TwitterMessageService在这里实现@Qualifier当我们创建多个相同类型的bean,但只想将其中一个与一个属性关联起来。可以使用@Qualifier注解和@Autowired注解进行控制。@Qualifier用于解决不明确的依赖关系,即帮助@Autowired注解选择其中一个依赖关系。如果一个接口有多个实现,那么我们可以在运行时使用@Qualifier来选择想要的实现。publicinterfaceMessageService{publicvoidsendMsg(Stringmessage);}publicclassEmailServiceimplementsMessageService{publicvoidsendMsg(Stringmessage){System.out.println(message);}}公共类TwitterService实现MessageService{publicvoidsendMsg(Stringmessage){System.out.println(message);}}公共类SMSService实现MessageService{publicvoidsendMsg(Stringmessage){System.out.println(message);}}publicinterfaceMessageProcessor{publicvoidprocessMsg(Stringmessage);}publicclassMessageProcessorImplimplementsMessageProcessor{privateMessageServicemessageService;//基于DI@Autowired@Qualifier("TwitterService")publicvoidsetMessageService(MessageServicemessageService){this.messageService=messageService;}//基于DI的构造函数@AutowiredpublicMessageProcessorImpl(@Qualifier("TwitterService")MessageServicemessageService){this.messageService=messageService;}publicvoidprocessMsg(Stringmessage){messageService.sendMsg(message);}}@Configuration@ComponentScan("com.demo.springframework.di")publicclassAppConfiguration{@Bean(name="emailService")publicMessageServiceemailService(){returnnewEmailService();}@Bean(name="twitterService")publicMessageServicetwitterService(){returnnewTwitterService();}@Bean(name="smsService")publicMessageServicesmsService(){returnnewSMSService();}@BeanpublicMessageProcessormessageProcessor(){返回新的MessageProcessorImpl(twitterService());}}publicclassTestApplication{publicstaticvoidmain(String[]args){ApplicationContextapplicationContext=newAnnotationConfigApplicationContext(AppConfiguration.class);MessageProcessoruserService=applicationContext.getBean(Mess年龄处理器.class);userService.processMsg("推特消息发送");}}输出:twitter消息发送@ResourceSpring支持通过@Resource(javax.annotation.Resource)注入,可以添加到字段或setter方法中,@Resource有name属性。如果不指定名称,默认为字段或setter方法名称publicclassSimpleMovieLister{privateMovieFindermovieFinder;@Resource(name="myMovieFinder")publicvoidsetMovieFinder(MovieFindermovieFinder){this.movi??eFinder=movieFinder;}}publicclassSimpleMovieLister{privateMovieFindermovieFinder;@ResourcepublicvoidsetMovieFinder(MovieFindermovieFinder){this.movi??eFinder=movieFinder;}}@Value这个注解可以用来给Spring管理的bean中的字段注入值,可以应用于字段或者构造函数/方法参数级别。我们需要一个属性文件来定义我们要用@Value注解注入的值。因此,我们首先需要在我们的配置类中定义一个@PropertySource-属性文件名。value.from.file=Valuegotfromthefilepriority=highlistOfValues=A,B,C注意:SpringBoot默认配置了一个PropertySourcesPlaceholderConfigurerBean,它会从application.properties和application.yml文件中获取属性。@Value("${value.from.file}")privateStringvalueFromFile;有时,我们需要注入一堆值。将它们定义为属性文件中单个属性的逗号分隔值,或作为系统属性并注入一个数组。例如,listOfValues中定义了逗号分隔值,因此数组的值将是["A","B","C"]。@Value("${listOfValues}")privateString[]valuesArray;使用SpEL表达式使用SpEL表达式获取配置文件中的优先级值。@Value("#{systemProperties['priority']}")privateStringspelValue;如果property文件中没有定义property,会报nullvalue异常。为了防止这种情况,我们可以在SpEL表达式中提供一个默认值。如果未定义该属性,我们会为该字段设置一个默认值。@Value("#{systemProperties['unknown']?:'somedefault'}")privateStringspelSomeDefault;我们还可以使用其他bean属性值:@Value("#{someBean.someValue}")privateIntegersomeBeanValue;从属性配置中获取List列表:@Value("#{'${listOfValues}'.split(',')}")私有列表valuesList;在Map中注入@Value,并添加到propeties文件中,如下key:valuesMap={key1:'1',key2:'2',key3:'3'}注意Map中的values必须在单引号。@Value("#{${valuesMap}}")privateMapvaluesMap;如果要获取map中指定的key:@Value("#{${valuesMap}.key1}")privateIntegervaluesMapKey1;如果我们不确定这个key是否包含在Map中,我们可以使用一个安全的表达式让它不会抛出异常并将value设置为null:@Value("#{${valuesMap}['unknownKey']}")privateIntegerunknownMapKey;为属性设置默认值:@Value("#{${unknownMap:{key1:'1',key2:'2'}}}")privateMapunknownMap;@Value("#{${valuesMap}['unknownKey']?:5}")privateIntegerunknownMapKeyWithDefaultValue;注入前过滤掉不需要的值:@Value("#{${valuesMap}.?[value>'1']}")privateMapvaluesMapFiltered;注入构造函数@Component@PropertySource("classpath:application.properties")publicclassPriorityProvider{privateStringpriority;@AutowiredpublicPriorityProvider(@Value("${priority:normal}")Stringpriority){this.priority=priority;}//标准getter}注意:如果默认配置文件是application.properties或application.yaml,则不需要@PropertySource注解。用Setter注入@Component@PropertySource("classpath:values.properties")publicclassCollectionProvider{privateListvalues=newArrayList<>();@AutowiredpublicvoidsetValues(@Value("#{'${listOfValues}'.split(',')}")Listvalues){this.values.addAll(values);}//标准getter}@PostConstruct和@PreDestroy我们可以自定义Bean附加动作的创建和销毁。我们可以通过实现InitializingBean和DisposableBean接口来实现。我们也可以使用@PostConstruct和@PreDestroy注解来实现。@PostConstructSpring只在bean属性初始化之后调用一次用@PostConstruct注释的方法。请记住,即使不需要初始化,这些方法也会运行。用@PostConstruct注解的方法不能是静态的。@ComponentpublicclassDbInit{@AutowiredprivateUserRepositoryuserRepository;@PostConstructprivatevoidpostConstruct(){Useradmin=newUser("admin","adminpassword");UsernormalUser=newUser("用户","用户密码");userRepository.save(admin,normalUser);}}@PreDestroy用@PreDestroy注释的方法只运行一次,就在Spring从容器中移除我们的bean之前。用@PreDestroy注释的方法不能是静态的。@ComponentpublicclassUserRepository{privateDbConnectiondbConnection;@PreDestroypublicvoidpreDestroy(){dbConnection.close();}}