本次记录的笔记是为了复习巩固Spring注解的知识,主要目的是记录复习了哪些知识点,故较基础的内容将只会简单列出,笔者使用较少或不太熟悉的将会详细讨论。

环境搭建:

  1. <!-- 导入Spring依赖-->
  2. <dependencies>
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-context</artifactId>
  6. <version>4.3.12.RELEASE</version>
  7. </dependency>
  8. </dependencies>
  9. <build>
  10. <plugins>
  11. <!-- java编译插件 -->
  12. <plugin>
  13. <groupId>org.apache.maven.plugins</groupId>
  14. <artifactId>maven-compiler-plugin</artifactId>
  15. <version>3.5.1</version>
  16. <configuration>
  17. <source>1.8</source>
  18. <target>1.8</target>
  19. <encoding>UTF-8</encoding>
  20. </configuration>
  21. </plugin>
  22. </plugins>
  23. </build>

1.使用@Configuration和@Bean给容器注册组件

image.png

2.使用@ComponentScan自动扫描组件并指定扫描规则

3.自定义TypeFilter指定@ComponentScan注解的过滤规则

4.使用@Scope注解设置组件的作用域

image.png

5.使用@Lazy实现默认创建单实例时的懒加载

6.使用@Conditional按条件向Spring容器中注册Bean

image.png

7.使用@Import注解快速导入一个组件

  1. 包扫描+给组件标注注解(@Controller、@Servcie、@Repository、@Component),但这种方式比较有局限性,局限于我们自己写的类
  2. @Bean注解,通常用于导入第三方包中的组件
  3. @Import注解,快速向Spring容器中导入一个组件

@Import注解的三种用法主要包括:

  1. 直接填写class数组的方式
  2. ImportSelector接口的方式,即批量导入,这是重点
  3. ImportBeanDefinitionRegistrar接口方式,即手工注册bean到容器中

8.使用FactoryBean向Spring容器中注册bean

9.使用@Bean指定初始化和销毁的方法

bean的生命周期: 通常意义上讲的bean的生命周期,指的是bean从创建到初始化,经过一系列的流程,最终销毁的过程。只不过,在Spring中,bean的生命周期是由Spring容器来管理的。在Spring中,我们可以自己来指定bean的初始化和销毁的方法。我们指定了bean的初始化和销毁方法之后,当容器在bean进行到当前生命周期的阶段时,会自动调用我们自定义的初始化和销毁方法。

10.使用InitializingBean和DisposbleBean来管理bean的生命周期

根据InitializingBean接口中提供的afterPropertiesSet()方法的名字不难推断出,afterPropertiesSet()方法是在属性赋好值之后调用的。

Spring为bean提供了两种初始化的方式,实现InitializingBean接口(也就是要实现该接口中的afterPropertiesSet方法),或者在配置文件或@Bean注解中通过init-method来指定,两种方式可以同时使用。

实现InitializingBean接口是直接调用afterPropertiesSet()方法,与通过反射调用init-method指定的方法相比,效率相对来说要高点。但是init-method方式消除了对Spring的依赖。

如果调用afterPropertiesSet方法时出错,那么就不会调用init-method指定的方法了。

实现org.springframework.beans.factory.DisposableBean接口的bean在销毁前,Spring将会调用DisposableBean接口的destroy()方法。也就是说我们可以实现DisposableBean这个接口来定义咱们这个销毁的逻辑。[

](https://blog.csdn.net/yerenyuan_pku/article/details/110405034)

在多实例bean情况下,Spring不会自动调用bean的销毁方法。

11.@PostConstruct注解和@PreDestroy注解

通常我们是会在Spring框架中使用到@PostConstruct注解的,该注解的方法在整个bean初始化中的执行顺序如下: Constructor(构造方法)→@Autowired(依赖注入)→@PostConstruct(注释的方法)

被@PreDestroy注解修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy注解修饰的方法会在destroy()方法之后,Servlet被彻底卸载之前执行。执行顺序如下所示: 调用destroy()方法→@PreDestroy→destroy()方法→bean销毁

12.关于BeanPostProcessor后置处理器

后置处理器可用于bean对象初始化前后进行逻辑增强。 BeanPostProcessor是一个接口,其中有两个方法,即postProcessBeforeInitialization和postProcessAfterInitialization这两个方法,这两个方法分别是在Spring容器中的bean初始化前后执行,所以Spring容器中的每一个bean对象初始化前后,都会执行BeanPostProcessor接口的实现类中的这两个方法。 也就是说,postProcessBeforeInitialization方法会在bean实例化和属性设置之后,自定义初始化方法之前被调用,而postProcessAfterInitialization方法会在自定义初始化方法之后被调用。当容器中存在多个BeanPostProcessor的实现类时,会按照它们在容器中注册的顺序执行。对于自定义的BeanPostProcessor实现类,还可以让其实现Ordered接口自定义排序。 bean的初始化和销毁 我们知道BeanPostProcessor的postProcessBeforeInitialization()方法是在bean的初始化之前被调用;而postProcessAfterInitialization()方法是在bean初始化的之后被调用。并且bean的初始化和销毁方法我们可以通过如下方式进行指定:

(一)通过@Bean指定init-method和destroy-method

  1. @Bean(initMethod="init", destroyMethod="destroy")
  2. public Car car() {
  3. return new Car();
  4. }

(二)通过让bean实现InitializingBean和DisposableBean这俩接口

  1. package com.meimeixia.bean;
  2. import org.springframework.beans.factory.DisposableBean;
  3. import org.springframework.beans.factory.InitializingBean;
  4. import org.springframework.context.annotation.Scope;
  5. import org.springframework.stereotype.Component;
  6. @Component
  7. public class Cat implements InitializingBean, DisposableBean {
  8. public Cat() {
  9. System.out.println("cat constructor...");
  10. }
  11. /**
  12. * 会在容器关闭的时候进行调用
  13. */
  14. @Override
  15. public void destroy() throws Exception {
  16. // TODO Auto-generated method stub
  17. System.out.println("cat destroy...");
  18. }
  19. /**
  20. * 会在bean创建完成,并且属性都赋好值以后进行调用
  21. */
  22. @Override
  23. public void afterPropertiesSet() throws Exception {
  24. // TODO Auto-generated method stub
  25. System.out.println("cat afterPropertiesSet...");
  26. }
  27. }

(三)使用JSR-250规范里面定义的@PostConstruct和@PreDestroy这俩注解

  1. package com.meimeixia.bean;
  2. import javax.annotation.PostConstruct;
  3. import javax.annotation.PreDestroy;
  4. import org.springframework.stereotype.Component;
  5. /**
  6. *
  7. * @author liayun
  8. *
  9. */
  10. @Component
  11. public class Dog {
  12. public Dog() {
  13. System.out.println("dog constructor...");
  14. }
  15. // 在对象创建完成并且属性赋值完成之后调用
  16. @PostConstruct
  17. public void init() {
  18. System.out.println("dog...@PostConstruct...");
  19. }
  20. // 在容器销毁(移除)对象之前调用
  21. @PreDestroy
  22. public void destory() {
  23. System.out.println("dog...@PreDestroy...");
  24. }
  25. }

(四)通过让bean实现BeanPostProcessor接口

  1. package com.meimeixia.bean;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanPostProcessor;
  4. import org.springframework.core.Ordered;
  5. import org.springframework.stereotype.Component;
  6. /**
  7. * 后置处理器,在初始化前后进行处理工作
  8. * @author liayun
  9. *
  10. */
  11. @Component // 将后置处理器加入到容器中,这样的话,Spring就能让它工作了
  12. public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
  13. @Override
  14. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  15. // TODO Auto-generated method stub
  16. System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
  17. return bean;
  18. }
  19. @Override
  20. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  21. // TODO Auto-generated method stub
  22. System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
  23. return bean;
  24. }
  25. @Override
  26. public int getOrder() {
  27. // TODO Auto-generated method stub
  28. return 3;
  29. }
  30. }

所以,通过上述四种方式,我们可以控制Spring中bean的整个生命周期。

13.使用@Value注解为bean的属性赋值

  • 注入普通字符串

@Value(“李阿昀”)
private String name;// 注入普通字符串

  • 注入操作系统属性

@Value(“#{systemProperties[‘os.name’]}”)
private String systemPropertiesName;// 注入操作系统属性

  • 注入SpEL表达式结果

@Value(“#{ T(java.lang.Math).random() * 100.0 }”)
privatedouble randomNumber;//注入SpEL表达式结果

  • 注入其他bean中属性的值

@Value(“#{person.name}”)
private String username;// 注入其他bean中属性的值,即注入person对象的name属性中的值

  • 注入文件资源

@Value(“classpath:/config.properties”)
private Resource resourceFile;// 注入文件资源

  • 注入URL资源

@Value(“http://www.baidu.com“)
private Resource url;// 注入URL资源

${···}的用法
{}里面的内容必须符合SpEL表达式,通过@Value(“${spelDefault.value}”)我们可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,那么就会报错。不过,我们可以通过赋予默认值来解决这个问题,如下所示:
@Value(“${author.name:meimeixia}”)
private String name;
#{···}的用法
{}里面的内容同样也是必须符合SpEL表达式。例如:
// SpEL:调用字符串Hello World的concat方法
@Value(“#{‘Hello World’.concat(‘!’)}”)
private String helloWorld;
// SpEL:调用字符串的getBytes方法,然后再调用其length属性
@Value(“#{‘Hello World’.bytes.length}”)
private String helloWorldBytes;
${···}和#{···}的混合使用
${···}和#{···}可以混合使用,例如:
// SpEL:传入一个字符串,根据”,”切分后插入列表中, #{}和${}配合使用时,注意不能反过来${}在外面,而#{}在里面
@Value(“#{‘${server.name}’.split(‘,’)}”)
private List severs;

14.@PropertySource和@PropertySources注解

我们可以通过@PropertySource注解指定多个properties文件,使用的形式如下所示:
@PropertySource(value={“classpath:/person.properties”,”classpath:/car.properties”})
@PropertySources注解的源码比较简单,只有一个PropertySource[]数组类型的value属性,那我们如何使用@PropertySources注解指定配置文件呢?其实也很简单,使用如下所示的方式就可以了:
@PropertySources(value={
@PropertySource(value={“classpath:/person.properties”}),
@PropertySource(value={“classpath:/car.properties”}),
})

15.使用@Autowired、@Qualifier、@Primary自动装配组件

@Autowired注解:

  1. @Autowired注解默认是优先按照类型去容器中找对应的组件,相当于是调用了如下这个方法:applicationContext.getBean(类名.class); 若找到则就赋值。

  2. 如果找到多个相同类型的组件,那么是将属性名称作为组件的id,到IOC容器中进行查找,这时就相当于是调用了如下这个方法:applicationContext.getBean(“组件的id”);

@Qualifier注解
@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,那么就需要配合@Qualifier注解来使用了。
@Primary注解
在Spring中使用注解时,常常会使用到@Autowired这个注解,它默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口而言,可能会有几种不同的实现类,而在默认只会采取其中一种实现的情况下,就可以使用@Primary注解来标注优先使用哪一个实现类。
自动装配
我们先知道什么是Spring组件的自动装配。Spring组件的自动装配就是Spring利用依赖注入,也就是我们通常所说的DI,完成对IOC容器中各个组件的依赖关系赋值。

16.使用@Resource和@Inject注解

@Resource注解
@Resource注解是Java规范里面的,也可以说它是JSR250规范里面定义的一个注解。该注解默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,那么默认取字段名将其作为组件的名称在IOC容器中进行查找,如果注解写在setter方法上,那么默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的一点是,如果name属性一旦指定,那么就只会按照名称进行装配。
@Inject注解
@Inject注解也是Java规范里面的,也可以说它是JSR330规范里面定义的一个注解。该注解默认是根据参数名去寻找bean注入,支持Spring的@Primary注解优先注入,@Inject注解还可以增加@Named注解指定要注入的bean。

@Resource注解和@Autowired注解的功能是一样的,都能实现自动装配,只不过@Resource注解默认是按照组件名称(即属性的名称)进行装配的。虽然@Resource注解具备自动装配这一功能,但是它是不支持@Primary注解优先注入的功能的,而且也不能像@Autowired注解一样能添加required=false属性。 @Inject注解和@Autowired注解的功能是一样的,都能实现自动装配,而且它俩都支持@Primary注解优先注入的功能。只不过,@Inject注解不能像@Autowired注解一样能添加required=false属性,因为它里面没啥属性。

@Resource和@Inject这俩注解与@Autowired注解的区别

不同点 @Autowired是Spring中的专有注解,而@Resource是Java中JSR250规范里面定义的一个注解,@Inject是Java中JSR330规范里面定义的一个注解 @Autowired支持参数required=false,而@Resource和@Inject都不支持 @Autowired和@Inject支持@Primary注解优先注入,而@Resource不支持 @Autowired通过@Qualifier指定注入特定bean,@Resource可以通过参数name指定注入bean,而@Inject需要通过@Named注解指定注入bean 相同点 三种注解都可以实现bean的自动装配。

17.使用@Profile注解实现开发、测试和生产环境的配置和切换

@Profile注解概述
在容器中如果存在同一类型的多个组件,那么可以使用@Profile注解标识要获取的是哪一个bean。也可以说@Profile注解是Spring为我们提供的可以根据当前环境,动态地激活和切换一系列组件的功能。这个功能在不同的环境使用不同的变量的情景下特别有用,例如,开发环境、测试环境、生产环境使用不同的数据源,在不改变代码的情况下,可以使用这个注解来动态地切换要连接的数据库。

  1. @Profile注解不仅可以标注在方法上,也可以标注在配置类上。
  2. 如果@Profile注解标注在配置类上,那么只有是在指定的环境的时候,整个配置类里面的所有配置才会生效。
  3. 如果一个bean上没有使用@Profile注解进行标注,那么这个bean在任何环境下都会被注册到IOC容器中,当然了,前提是在整个配置类生效的情况下。

[

](https://blog.csdn.net/yerenyuan_pku/article/details/110914746)