一、前言
最近發現自己太喪了,因為是考試周,但是感覺考試及格就好,所以也無心復習,又因為馬上要放暑假了,歸心似箭啊,感覺有點厭學。這幾天都在看《士兵突擊》,挺勵志的一個電視劇,感覺還是不能就這樣喪下去,希望接下來的幾天加油吧。
二、@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
的實現類,這些類大多是給組件做了某種增強。