一、前言
最近发现自己太丧了,因为是考试周,但是感觉考试及格就好,所以也无心复习,又因为马上要放暑假了,归心似箭啊,感觉有点厌学。这几天都在看《士兵突击》,挺励志的一个电视剧,感觉还是不能就这样丧下去,希望接下来的几天加油吧。
二、@Conditional
@Conditional
注解的作用是:按照一定的条件进行判断,满足条件后才在中容器中注入该组件。这个注解在SpringBoot
的底层实现中大量的使用,学习一下有助于将来学习SpringBoot
,我们先来看一下配置类:
@Configuration
public class MainConfig2 {
@Conditional({WindowsCondition.class})
@Bean("windows")
public Person person01() {
return new Person("windows", 22);
}
@Conditional({LinuxCondition.class})
@Bean("linux")
public Person person02() {
return new Person("linux", 26);
}
}
我用@Conditional
注解标注了两个方法,这两个方法都是向容器中注入组件的方法,我们看一下@Conditional
注解中的参数:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition}s that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class extends Condition>[] value();
}
我们可以看到参数是Condition
的子类,上面已经实现了两个,分别是:
WindowsCondition
public class WindowsCondition implements Condition {
/**
*
* @param context 判断条件能使用的上下文环境
* @param metadata 注解信息
* @return
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1、获取ioc使用的BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、获取类的加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前的运行时环境,不如当前的操作系统
Environment environment = context.getEnvironment();
//4、获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
//获取当前的运行环境
String property = environment.getProperty("os.name");
if(property.contains("Windows")) {
return true;
}
return false;
}
}
LinuxCondition
public class LinuxCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//3、获取当前的运行时环境,不如当前的操作系统
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("linux")) {
return true;
}
return false;
}
}
这两个类是判断当前的操作系统的,综合配置类来看,就是如果当前操作系统为windows,就把名字为“windows”的组件放入容器,如果是linux系统,就把名字为“linux”的组件放入容器。然后我们就来看一下测试的结果吧:
我们可以看到容器中有windows组件,我们也可以同过虚拟机参数:
-Dos.name=linux
来测试一下linux的情况。这里只是简单的@Conditional
注解的用法,这个注解也可以作用与类上,说明只有满足条件,这个类中的所有的组件注册才能生效,在SpringBoot
的自动配置类中大量的使用了这个注解,有兴趣的可以自己研究一下。
三、生命周期
组件的生命周期是指:组件的创建,组件初始化,组件的销毁。
这里组件的销毁仅指在容器中单例的的组件,如果是多例的组件那么销毁和容器是没有关系的。
我在 细说Spring——IoC详解(Bean的生命周期中讲解过组件的生命周期,我们可以在XML中指定init-method和destory-method的方法来控制组件的生命周期,我们现在来学习一下使用注解的方法怎么控制组件的生命周期。
1、我们先来看第一种方法:
组件Car类
@Component
public class Car {
public Car() {
System.out.println("car constructor.....");
}
public void init() {
System.out.println("car init......");
}
public void destory() {
System.out.println("car destory......");
}
}
配置类:
@Configuration
@ComponentScan("com.jiayifan.bean")
//@Import(value = Cat.class)
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init", destroyMethod = "destory")
public Car car() {
return new Car();
}
}
我们可以在组件类中写一个初始化方法和销毁方法,然后在配置类中使用@Bean
的initMethod
和destroyMethod
来指定相应的方法。
然后我们测试一下:
public class IOCTest_lifeCycle {
@Test
public void test01() {
//1、创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
//关闭容器
applicationContext.close();
}
}
我们可以看到先调用了Car的构造器,然后调用了Car的初始化方法,最后在容器关闭前调用了Car的销毁方法。
2、通过让组件实现InitializingBean接口实现初始化,通过实现DisposableBean接口实现销毁
组件Cat类
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("cat constructor.....");
}
//销毁方法
public void destroy() throws Exception {
System.out.println("cat destory......");
}
//初始化方法
public void afterPropertiesSet() throws Exception {
System.out.println("cat afterPropertiesSet......");
}
}
配置类不变,测试类不变,看一下测试结果:
3、可以使用JSR250中定义的两个注解:@PostConstruct 实现初始化、@PreDestroy 实现销毁
组件Dog类
public class Dog {
public Dog() {
System.out.println("dog constructor.....");
}
//在Construct之后执行
@PostConstruct
public void init() {
System.out.println("dog @PostConstruct .......");
}
//在destory执行之前
@PreDestroy
private void destoyr() {
System.out.println("dog @PreDestroy.......");
}
}
配置类和测试类不变,测试结果:
4、BeanPostProcessor接口
还记得我在:细说Spring——IoC详解(深入IoC实现)中说过的BeanPostProcessor
吗,其实它也可以用来控制生命周期。不过这个接口并只涉及到组件初始化,我们可以通过实现这个接口来在组件初始化前对组件做一些增强,下面我们来看一下怎么使用:
组件MyBeanPostProcessor类
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization...." + beanName + "=>" + bean);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization...." + beanName + "=>" + bean);
return bean;
}
}
在所有组件的初始化前后进行一些处理工作,包含两个方法:
-
postProcessBeforeInitialization
:在初始化之前工作 -
postProcessAfterInitialization
:在初始化之后工作
配置类不变
测试类:
public class IOCTest_lifeCycle {
@Test
public void test01() {
//1、创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
printBeans();
//关闭容器
applicationContext.close();
}
private void printBeans() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
测试结果:
我们可以看到,我们的Car组件在初始化前调用了我们的MyBeanPostProcessor
中的postProcessBeforeInitialization
方法,在初始化后调用了postProcessAfterInitialization
方法。我们可以在Spring中发现很多BeanPostProcessor
的实现类,这些类大多是给组件做了某种增强。