注释是否比配置Spring的XML更好?
基于注释的配置的引入引发了这种方法是否比XML“更好”的问题。答案是每种方法都有其优点和缺点,通常,由开发人员决定哪种策略更适合他们。由于它们的定义方式,注释在其声明中提供了大量上下文,从而导致更短更简洁的配置。但是,XML擅长在不触及源代码或重新编译它们的情况下连接组件。一些开发人员更喜欢将布线靠近源,而另一些开发人员则认为注释类不再是POJO,而且配置变得分散且难以控制。
无论选择如何,Spring都可以兼顾两种风格,甚至可以将它们混合在一起。
注意:
1 注释注入在XML注入之前执行。因此,XML配置会覆盖通过这两种方法连接的属性的注释。
Spring开启注释
1、<context:annotation-config> :是用于激活那些已经在spring容器里注册过的bean(无论是通过xml的方式还是通过package sanning的方式)上面的注解。
2、<context:component-scan>:除了具有<context:annotation-config>的功能之外,<context:component-scan>还可以在指定的package下扫描以及注册javabean 。
Spring常用注释
@Required
@Required注释适用于bean属性setter方法,此批注指示必须在配置时通过bean定义中的显式属性值或通过自动装配填充受影响的bean属性。如果尚未填充受影响的bean属性,则容器将引发异常。
1 public class SimpleMovieLister { 2 3 private MovieFinder movieFinder; 4 5 @Required 6 public void setMovieFinder(MovieFinder movieFinder) { 7 this.movieFinder = movieFinder; 8 } 9 10 // ... 11 }
@Autowired
可以将@Autowired注释应用于构造函数,还可以将@Autowired注释应用于“传统”setter方法,还可以将注释应用于具有任意名称和多个参数的方法
1 public class MovieRecommender { 2 3 private final CustomerPreferenceDao customerPreferenceDao; 4 5 @Autowired 6 private MovieCatalog movieCatalog; 7 8 @Autowired 9 public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { 10 this.customerPreferenceDao = customerPreferenceDao; 11 } 12 13 @Autowired(required = false) 14 public void setMovieFinder(MovieCatalog movieCatalog) { 15 this.movieCatalog = movieCatalog; 16 } 17 18 // ... 19 }
@Primary
由于按类型自动装配可能会导致多个候选人,因此通常需要对选择过程进行更多控制。实现这一目标的一种方法是使用Spring的@Primary
注释。@Primary
表示当多个bean可以自动装配到单值依赖项时,应该优先选择特定的bean。如果候选者中只存在一个主bean,则它将成为自动装配的值。
1 @Configuration 2 public class MovieConfiguration { 3 4 @Bean 5 @Primary 6 public MovieCatalog firstMovieCatalog() { ... } 7 8 @Bean 9 public MovieCatalog secondMovieCatalog() { ... } 10 11 // ... 12 }
@Resource
@Resource采用名称属性。默认情况下,Spring将该值解释为要注入的bean名称。换句话说,它遵循按名称语义,如以下示例所示:
如果未明确指定名称,则默认名称是从字段名称或setter方法派生的。如果是字段,则采用字段名称。在setter方法的情况下,它采用bean属性名称
1 public class SimpleMovieLister { 2 3 private MovieFinder movieFinder; 4 5 @Resource(name="myMovieFinder") 6 public void setMovieFinder(MovieFinder movieFinder) { 7 this.movieFinder = movieFinder; 8 } 9 }
@PostConstruct 和 @PreDestroy
一个bean进行初始化时,回调@PostConstruct注释的方法
一个bean进行销毁时,回调@PreDestroy注释的方法
1 public class CachingMovieLister { 2 3 @PostConstruct 4 public void populateMovieCache() { 5 // populates the movie cache upon initialization... 6 } 7 8 @PreDestroy 9 public void clearMovieCache() { 10 // clears the movie cache upon destruction... 11 } 12 }
@Component
表示一个带注释的类是一个“组件”,成为Spring管理的Bean。当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时
@Component是任何Spring管理组件的通用构造型。@Repository,@Service和,@Controller是@Component更具体的用例的专业化(分别在持久性,服务和表示层)。因此,您可以来注解你的组件类有 @Component,但是,通过与注解它们@Repository,@Service或者@Controller ,你的类能更好地被工具处理,或与切面进行关联。
1 package com.test.spring.beanannotation; 2 3 import org.springframework.context.annotation.Scope; 4 import org.springframework.stereotype.Component; 5 6 // @Component("beanAnno") 7 @Component 8 // @Scope("prototype") 9 @Scope 10 public class BeanAnnotation { 11 12 public void say(String arg) { 13 System.out.println("BeanAnnotation:" + arg); 14 } 15 16 public void myHashCode() { 17 System.out.println("BeanAnnotation:" + this.hashCode()); 18 } 19 20 }
@Component还是一个元注解。
1 @Target(ElementType.TYPE) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Component 5 public @interface Service { 6 7 // .... 8 }
@Configuration
声明当前类是一个配置类(相当于一个Spring配置的xml文件)
@ComponentScan
自动扫描指定包
1 @Configuration 2 @ComponentScan(basePackages = "org.example") 3 public class AppConfig { 4 ... 5 }
简洁起见,前面的示例可能使用value了注释的属性(即@ComponentScan("org.example"))
替代方法使用XML:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 https://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <context:component-scan base-package="org.example"/> 11 12 </beans>
@Bean 和 @Configuration
Spring的新Java配置支持中的中心工件是 @Configuration注释类和@Bean注释方法。
该@Bean注释被用于指示一个方法实例,配置和初始化为通过Spring IoC容器进行管理的新对象。对于那些熟悉Spring的<beans/>XML配置的人来说,@Bean注释与<bean/>元素扮演的角色相同。你可以@Bean在任何Spring中使用-annotated方法 @Component。但是,它们最常用于@Configuration豆类。
对类进行注释@Configuration表明其主要目的是作为bean定义的来源。此外,@Configuration类允许通过调用@Bean同一类中的其他方法来定义bean间依赖关系。最简单的@Configuration类如下:
1 @Configuration 2 public class AppConfig { 3 4 @Bean 5 public MyService myService() { 6 return new MyServiceImpl(); 7 } 8 }
上面的AppConfig类等效于以下Spring <beans/>XML:
<beans> <bean id="myService" class="com.acme.services.MyServiceImpl"/> </beans>
还可以@Bean
使用接口(或基类)返回类型声明您的方法
@Bean
注释支持指定任意初始化和销毁回调方法
1 public class BeanOne { 2 3 public void init() { 4 // initialization logic 5 } 6 } 7 8 public class BeanTwo { 9 10 public void cleanup() { 11 // destruction logic 12 } 13 } 14 15 @Configuration 16 public class AppConfig { 17 18 @Bean(initMethod = "init") 19 public BeanOne beanOne() { 20 return new BeanOne(); 21 } 22 23 @Bean(destroyMethod = "cleanup") 24 public BeanTwo beanTwo() { 25 return new BeanTwo(); 26 } 27 }
@ImportResource
虽然Spring提倡零配置,但是还是提供了对xml文件的支持,这个注解就是用来加载xml配置的。例:@ImportResource({"classpath"})
@Value
值得注入。经常与Sping EL表达式语言一起使用,注入普通字符,系统属性,表达式运算结果,其他Bean的属性,文件内容,网址请求内容,配置文件属性值等等
1 package com.test.spring.beanannotation.javabased; 2 3 import org.springframework.beans.factory.annotation.Value; 4 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.context.annotation.ImportResource; 7 8 @Configuration 9 @ImportResource("classpath:config.xml") 10 public class StoreConfig { 11 12 @Value("${jdbc.url}") 13 private String url; 14 @Value("${jdbc.password}") 15 private String password; 16 @Value("${jdbc.username}") 17 private String username; 18 19 @Bean 20 public MyDriverManager myDriverManager() { 21 return new MyDriverManager(url, username, password); 22 } 23 24 }
@Profile
通过@Profile 注释,您可以指示当一个或多个指定的配置文件处于活动状态时,组件符合注册条件。使用前面的示例,按如下方式重写配置:
1 @Configuration 2 @Profile("development") 3 public class StandaloneDataConfig { 4 5 @Bean 6 public DataSource dataSource() { 7 return new EmbeddedDatabaseBuilder() 8 .setType(EmbeddedDatabaseType.HSQL) 9 .addScript("classpath:com/bank/config/sql/schema.sql") 10 .addScript("classpath:com/bank/config/sql/test-data.sql") 11 .build(); 12 } 13 }
如果@Configuration标记了类,则除非一个或多个指定的配置文件处于活动状态,否则将绕过与该类关联的@Profile所有@Bean方法和 @Import注释。如果a @Component或@Configurationclass被标记@Profile({"p1", "p2"}),则除非已激活配置文件'p1'或'p2',否则不会注册或处理该类。如果给定的配置文件以NOT运算符(!)作为前缀,则仅在配置文件未激活时才注册带注释的元素。例如,@Profile({"p1", "!p2"})如果配置文件“p1”处于活动状态或配置文件“p2”未激活,则会发生注册