Spring注解 – 生命周期、属性赋值、自动装配
- 2020 年 3 月 18 日
- 筆記
一、Bean的生命周期
流程
Bean创建 —— 初始化 —— 销毁
创建:
- 单实例:在容器启动时创建对象
- 多实例:每次调用时创建对象
初始化:
- 都是在对象创建完成后,调用初始化方法
销毁:
- 单实例:容器关闭时,调用销毁方法
- 多实例:容器不会管理这个bean,只能手动调用销毁方法
实现方式
-
在 @Bean 注解上指定初始化(initMethod)、销毁方法(destroyMethod)
@Bean(initMethod = "init", destroyMethod = "destroy") public Car car(){ return new Car(); }
-
让Bean实现 InitializingBean 和 DisposableBean 接口,重写它们的方法
public class Cat implements InitializingBean, DisposableBean { public Cat() { System.out.println("Cat...Construct..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("Cat...init..."); } @Override public void destroy() throws Exception { System.out.println("Cat...destroy..."); } }
-
使用 JSR250 中的 @PostConstruct 和 @PreDestroy 注解标注初始化、销毁方法
public class Dog { public Dog() { System.out.println("Dog...Construct..."); } @PostConstruct public void init(){ System.out.println("Dog...init..."); } @PreDestroy public void destroy(){ System.out.println("Dog...destroy..."); } }
-
实现BeanPostProcessor接口,重写
postProcessBeforeInitialization(在初始化之前工作)
postProcessAfterInitialization(在初始化之后工作)
public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization" + beanName); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization" + beanName); return bean; } }
二、属性赋值相关注解
@Value
作用:
添加在字段上,用于给属性赋值
属性:
- value:指定要传入的值
用法:
public class Person { @Value("张三") //普通方式赋值 private String name; @Value("#{20 - 1}") //使用SpEL表达式 private Integer age; @Value("${person.nickName}") //使用 ${} 读取配置文件内容 private String nickName; //省略getter setter toString方法 }
上述第三种方式显然是不能读取到的,我们需要配置一下配置文件的位置,使用到下面这个注解
@PropertySource
作用:
读取指定的外部配置文件,将K/V键值对保存到运行的环境变量中,用 ${} 来获取
属性:
- name:给属性源指定一个名称
- value:要加载的配置文件的路径,可以指定多个
- ignoreResourceNotFound:是否忽略资源未找到的情况,默认false
- encoding:给定资源的特定字符编码,例如 “UTF-8”
- factory:指定一个自定义属性源工厂,默认使用 PropertySourceFactory
用法:
在 resources 目录下创建一个 properties 文件,内容如下
person.nickName=小张
然后在配置类上标注 @PropertySource("classpath:person.properties")
即可
可以直接在@Value注解中获取,也可以通过 ioc 容器对象获取
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration4.class); String nickName = context.getEnvironment().getProperty("person.nickName"); System.out.println(nickName);
三、自动装配相关注解
Spring 利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
@Autowired
-
默认按照类型去容器中寻找对应的组件,如果只有一个就赋值
- 如果找到多个相同类型的组件,再按照属性名寻找
- 有一个required属性,默认是true;
-
可以写在构造器、方法、参数、属性上
@Qualifier
- 一般配合 @Autowired 使用,指定需要装配的组件的id,@Autowired 就直接按照id注入。
- 如果 id 对应的组件不存在,并且没有指定 required = false,则会报错
@Primary
- 让Spring进行自动装配的时候,首先选择标注了@Primary的组件
- 如果已经使用 @Qualifier 指明了要装配的组件,则不生效
? 不常用的两个自动注入注解:
@Resource(JSR250)
- java规范里的注解,和@Autowired一样可以实现自动装配
- 默认使用变量名作为 id,不能配合@Qualifier @Primary使用
@Inject(JSR330)
和@Autowired一样,但是没有required属性,需要导入 javax.inject 的 jar 包
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
@Profile
-
指定组件在哪个环境下才被注册到容器中,不指定则在哪个环境都注册
- 可以指定多个环境,default为默认环境
-
可以写在配置类上
还可以用代码的方式指定环境
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration5.class); applicationContext.getEnvironment().setActiveProfiles("prod");
四、使用 Spring 容器底层组件
对于自定义组件,如果想要使用Spring容器底层组件,可以实现Aware接口的子接口(xxxAware),如下图所示
@Component public class TestAware implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的IOC容器:" + applicationContext); this.applicationContext = applicationContext; } }
这些 xxxAware 的功能都是通过 ApplicationContextAwareProcessor 来处理的
class ApplicationContextAwareProcessor implements BeanPostProcessor { private final ConfigurableApplicationContext applicationContext; private final StringValueResolver embeddedValueResolver; /** * Create a new ApplicationContextAwareProcessor for the given context. */ public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory()); } @Override @Nullable public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareInterfaces(bean); return null; }, acc); } else { invokeAwareInterfaces(bean); } return bean; } //根据传入bean的类型来为bean注入不同的组件 private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { return bean; } }