- 环境搭建:
- 1.使用@Configuration和@Bean给容器注册组件
- 2.使用@ComponentScan自动扫描组件并指定扫描规则
- 3.自定义TypeFilter指定@ComponentScan注解的过滤规则
- 4.使用@Scope注解设置组件的作用域
- 5.使用@Lazy实现默认创建单实例时的懒加载
- 6.使用@Conditional按条件向Spring容器中注册Bean
- 7.使用@Import注解快速导入一个组件
- 8.使用FactoryBean向Spring容器中注册bean
- 9.使用@Bean指定初始化和销毁的方法
- 10.使用InitializingBean和DisposbleBean来管理bean的生命周期
- 11.@PostConstruct注解和@PreDestroy注解
- 12.关于BeanPostProcessor后置处理器
- 13.使用@Value注解为bean的属性赋值
- 14.@PropertySource和@PropertySources注解
- 15.使用@Autowired、@Qualifier、@Primary自动装配组件
- 16.使用@Resource和@Inject注解
- 17.使用@Profile注解实现开发、测试和生产环境的配置和切换
本次记录的笔记是为了复习巩固Spring注解的知识,主要目的是记录复习了哪些知识点,故较基础的内容将只会简单列出,笔者使用较少或不太熟悉的将会详细讨论。
环境搭建:
<!-- 导入Spring依赖-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
1.使用@Configuration和@Bean给容器注册组件
2.使用@ComponentScan自动扫描组件并指定扫描规则
3.自定义TypeFilter指定@ComponentScan注解的过滤规则
4.使用@Scope注解设置组件的作用域
5.使用@Lazy实现默认创建单实例时的懒加载
6.使用@Conditional按条件向Spring容器中注册Bean
7.使用@Import注解快速导入一个组件
- 包扫描+给组件标注注解(@Controller、@Servcie、@Repository、@Component),但这种方式比较有局限性,局限于我们自己写的类
- @Bean注解,通常用于导入第三方包中的组件
- @Import注解,快速向Spring容器中导入一个组件
@Import注解的三种用法主要包括:
- 直接填写class数组的方式
- ImportSelector接口的方式,即批量导入,这是重点
- 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
@Bean(initMethod="init", destroyMethod="destroy")
public Car car() {
return new Car();
}
(二)通过让bean实现InitializingBean和DisposableBean这俩接口
package com.meimeixia.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("cat constructor...");
}
/**
* 会在容器关闭的时候进行调用
*/
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat destroy...");
}
/**
* 会在bean创建完成,并且属性都赋好值以后进行调用
*/
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat afterPropertiesSet...");
}
}
(三)使用JSR-250规范里面定义的@PostConstruct和@PreDestroy这俩注解
package com.meimeixia.bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;
/**
*
* @author liayun
*
*/
@Component
public class Dog {
public Dog() {
System.out.println("dog constructor...");
}
// 在对象创建完成并且属性赋值完成之后调用
@PostConstruct
public void init() {
System.out.println("dog...@PostConstruct...");
}
// 在容器销毁(移除)对象之前调用
@PreDestroy
public void destory() {
System.out.println("dog...@PreDestroy...");
}
}
(四)通过让bean实现BeanPostProcessor接口
package com.meimeixia.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
/**
* 后置处理器,在初始化前后进行处理工作
* @author liayun
*
*/
@Component // 将后置处理器加入到容器中,这样的话,Spring就能让它工作了
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
return bean;
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 3;
}
}
所以,通过上述四种方式,我们可以控制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
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注解:
@Autowired注解默认是优先按照类型去容器中找对应的组件,相当于是调用了如下这个方法:applicationContext.getBean(类名.class); 若找到则就赋值。
如果找到多个相同类型的组件,那么是将属性名称作为组件的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为我们提供的可以根据当前环境,动态地激活和切换一系列组件的功能。这个功能在不同的环境使用不同的变量的情景下特别有用,例如,开发环境、测试环境、生产环境使用不同的数据源,在不改变代码的情况下,可以使用这个注解来动态地切换要连接的数据库。
- @Profile注解不仅可以标注在方法上,也可以标注在配置类上。
- 如果@Profile注解标注在配置类上,那么只有是在指定的环境的时候,整个配置类里面的所有配置才会生效。
- 如果一个bean上没有使用@Profile注解进行标注,那么这个bean在任何环境下都会被注册到IOC容器中,当然了,前提是在整个配置类生效的情况下。
[
](https://blog.csdn.net/yerenyuan_pku/article/details/110914746)