注解配置和XML配置实现的功能是一样的,只是实现方式不同而已。并且,注解配置在XML配置之前执行。
首先通过在XML中通过配置可以隐式的注册一些组件,当然你也可以显式的定义bean。(注意引入context命名空间)
<context:annotation-config/>隐式注册包含的组件有:AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor和RequiredAnnotationBeanPostProcessor。
使用@Autowired实现注解式自动装配。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { //指定此依赖性是否为非必须,默认true。 boolean required() default true; }通常作用在变量上或方法上,首先按照byType注入,只要容器中有唯一的bean对象类型相匹配,则注入成功,若无匹配,则报错,若匹配多个,则在其中再按照byName注入,若无匹配,则报错。此时set方法不是必须的了,见上文可知。
四种形式案例:
作用在构造方法上
public class UserServie { private UserDao userDao; @Autowired public UserServie(UserDao userDao) { this.userDao = userDao; } }在单一构造方法场景下,即使不使用@Autowired注解,也会被用来进行自动装配。
在单一构造方法场景下,使用@Autowired注入存在着特殊规则,如多元素注入(数组、集合、Map等),在没有匹配bean时允许为空解析。
在多个构造方法场景下,所有构造方法的@Autowired必须设置required为false,以便其都作为自动装配的候选,自动装配会选择Spring容器匹配bean可以满足最大数量依赖项的构造方法,若无匹配,则选择主选项或默认项构造方法。
作用在set方法上
public class UserServie { private UserDao userDao; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } }作用在多个参数方法上
public class UserServie { private UserDao userDao; private ClubDao clubDao; @Autowired public void prepare(UserDao userDao, ClubDao clubDao) { this.userDao = userDao; this.clubDao = clubDao; } }作用在字段上
public class UserServie { @Autowired private UserDao userDao; //@Autowired 也可以和构造方法混用 public UserServie(UserDao userDao) { this.userDao = userDao; } }在XML配置的自动装配中,属性是通过set方法进行set注入的,而在注解注入中注解作用在字段上则可以不需要set方法。其原因是:@autowired注解关闭了访问控制权限,不再需要通过set注入了,直接通过已开放的属性通过Java反射机制进行注入(即使它是私有的)。
你还可以为复杂/集合类型进行注解注入,前提该类型bean以配置在容器中(建议在注入集合类型bean时,使用XML配置方式和注解配置方式混用)
Spring5版本中,你还可以在方法形参上使用@Nullable注解来使这个参数允许为空。
你也可以使用@Autowired注入一些可解析的依赖项:BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher和MessageSource,或是其扩展接口ConfigurableApplicationContext 、 ResourcePatternResolver。
通过@Order注解使用在不同地方拥有不同的功能,数字越小优先级越高:
使用在@Bean方法或组件类上时,可以在注入时调整其优先级顺序。(如对数组/集合类型进行注入时,集合项中的顺序由@Order决定)使用在配置类中,可以调整这些配置类容器的初始化顺序。注意:@Order并不会影响Bean的单例启动顺序(加载顺序)。
由于byType方式自动装配可能会匹配多个候选对象,因此我们通常对于选择需要更多的控制,我们可以使用@Primary实现候选优先权,当多个bean成为候选对象时,应优先考虑@Primary标记的bean。
//这是基于Java的容器配置方式 @Configuration public class MovieConfiguration { @Bean @Primary public MovieCatalog firstMovieCatalog() { ... } @Bean public MovieCatalog secondMovieCatalog() { ... } // ... } //这是基于注解的容器配置方式 @Primary @Component public class FirstMovieCatalog implements MovieCatalog{ // ... }当然,你也可以在XML中进行配置,见上文。
通过@Qualifier搭配@Autowired组合实现byName方式自动装配。(不能单独使用)
作用在字段上:
public class UserServie { @Autowired @Qualifier("userDao") private ParentDao parentDao; }作用在方法参数上:
public class UserServie { private ParentDao parentDao; @Autowired public void setUserDao(@Qualifier("userDao") ParentDao parentDao) { this.parentDao = parentDao; } }使用@Qualifier并不意味着与byType无关,自动装配其实还是先通过byType筛选出候选对象,再通过指定的限定符(@Qualifier值)找出指定对象的。如果要避开类型匹配的过程,可以使用@Resource注解,后续会讲解。
如果你尝试将来自@Bean方法的返回结果注入到同一配置类中,建议将要注入bean的@Bean方法设置为静态方法,将其与配置类实例和生命周期解耦合。原因是自动装配会优先选择其他配置类的候选对象,而本配置类的候选对象会放在最后选择。
同时,你还可以通过泛型作为隐式的限定符来代替@Qualifier。
@Autowired private Store<String> s1; @Autowired private Store<Integer> s2;此外,你还可以自定义@Qualifier注解,详见官方文档
Spring也支持JSR-250中的@Resource注解进行自动装配。它可以看作是byName形式的自动装配,通过其属性name来指定限定符。与@Autowired相比,它并没有类型匹配的过程,完全通过限定符进行匹配。
public class UserServie { @Resource(name="userDao") private ParentDao parentDao; public void setUserDao(ParentDao parentDao) { this.parentDao = parentDao; } }若你没有写name属性,它默认的会按照字段名或set方法名进行匹配。
你可以通过@Value注解进行基本类型、String类型的注入。此外,它还支持${}和SpEL表达式。
注入字面量:
public class User{ @Value("张三") private String name; @Value("aa,bb,cc,dd") private String[] alias; //... }Spring提供的内置转换器支持简单类型和String类型的类型转换,多个逗号分隔可以自动转换为数组。
注入属性文件的属性值:
public class User{ @Value("${userconfig.name}") private String name; //... }注入SpEL表达式:
public class User{ @Value("#{10+2}") private int age; //... }你可以通过JSR-250生命周期的@PostConstruct和@PreDestroy来实现创建和销毁时的回调方法。
@Resource、@PostConstruct和@PreDestroy注解都是由CommonAnnotationBeanPostProcessorBean识别的,而这个Bean一般通过隐式的注册,也就是<context:annotation-config/>完成的。
需要注意的是,在JDK9中,整个javax.annotation注解包从Java源码模块分离出来,而在JDK11中完全移除,需要Maven进行依赖加入才能使用(wdnmd),同时JSR-330也是需要依赖加入才能使用的。