一:前言

在Spring项目中,通常配置Spring都是使用XML的形式进行配置,配置bean是通过<bean></bean>标签将bean加入IOC容器中,但在Spring注解版中,可以通过Java代码进行配置,即创建一个java类在其类头上标注@Configuration注解即表示当前类为一个配置类,作用相当于之前的.xml配置文件,那如何将bean加入到IOC容器中呢,下面通过一小段代码了解一下。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

import com.peng.demo.bean.ColorFactoryBean;
import com.peng.demo.bean.Person;
import com.peng.demo.service.BookService;

/**  
* @ComponentScan value指定要扫描的包
* @ComponentScan excludeFilters排除某些组件
* @ComponentScan includeFilters只需要包含某些组件
* @ComponentScan useDefaultFilters禁用默认规则
* 	FilterType.ANNOTATION按照注解
* 	FilterType.ASSIGNABLE_TYPE按照给定的类型
* 	FilterType.ASPECTJ按照ASPECTJ表达式的方式
* 	FilterType.REGEX正则表达式
* 	FilterType.CUSTOM自定义规则
* 
*/
@Configuration
@ComponentScans(
	@ComponentScan(value="com.peng",
		/*excludeFilters= {
			@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
		},*/
        //useDefaultFilters 属性的默认值为 true,即使用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描
		useDefaultFilters=false,
		includeFilters= {
                @Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
		/*@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {BookService.class}),
                @Filter(type=FilterType.CUSTOM,classes= {MyTypeFilter.class})*/
				
		}
		
	)
)
public class MainConfig {
//	@Bean(name="person1")//配置bean名称
	@Bean
        @Scope("singleton")
	public Person person() {
		return new Person("张三", 22);
	}
	

}

注:@Configuration标注MainConfig为一个配置类,@ComponentScan标注基本包扫描相当于以前的<context:component-scan base-package=""></context:component-scan>,@ComponentScans内可以配置多个@ComponentScan。excludeFilters排除某些组件,includeFilters只需要包含某些组件,useDefaultFilters禁用默认规则。@Bean相当于之前的<bean></bean>标签,默认bean的id为方法名,@Scope("singleton")可以指定bean为单例或多实例。这里就不做过多的赘述了,读者可以根据xml配置,在配置类中一一尝试。

测试可见,person已经加入IOC容器中

public class TestMain {
	
	public static void main(String[] args) {
		ApplicationContext context=new AnnotationConfigApplicationContext(MainConfig.class);
		Person person = context.getBean(Person.class);
		System.out.println(person);
		
		String[] beanNamesForType = context.getBeanNamesForType(Person.class);
		for (String name : beanNamesForType) {
			System.out.println(name);
		}
	}

}

二:bean的生命周期

bean的生命周期主要包括bean的创建,初始化,销毁

1.通过注解指定bean的初始化及销毁方法,在xml配置文件中可以通过init-method和destroy-method来配置bean的初始化及销毁方法:<bean id="" class="" init-method=""  destroy-method=""></bean>,那么在注解中怎么使用呢?

@Bean注解提供initMethod和destroyMethod来指定bean的初始化和销毁方法。

创建一个类

public class Car {
	
	public Car() {
		System.out.println("Car创建啦!!!!!!!!!!!!!!!!!!!!");
	}
	
	public void init(){
		System.out.println("Car init!!!!!!!!!!!!!!!!!");
	}
	
	public void destory(){
		System.out.println("Car destory!!!!!!!!!!");
	}

}

创建配置类

@Configuration
public class MainConfigOfLifeCycle {
	
	@Bean(initMethod="init",destroyMethod="destory")
	public Car car(){
		return new Car();
	}

}

编写测试代码

@Test
	public void test1() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
		String[] beanNamesForType = context.getBeanDefinitionNames();
		for (String name : beanNamesForType) {
			System.out.println(name);
		}
		context.close();
	}

可以看见已经调用初始化及销毁方法

2.通过让bean实现InitializingBean接口定义初始化,实现DisposableBean定义销毁

创建类

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class Cat implements InitializingBean,DisposableBean{

	/**
	 * 初始化方法
	 */
	public void afterPropertiesSet() throws Exception {
		System.out.println("Cat Init!!!!!!!!!!!!!!!");
	}
	
	/**
	 * 销毁方法
	 */
	public void destroy() throws Exception {
		System.out.println("Cat destroy!!!!!!!!!!!!!!!");
		
	}
}

注:这里使用@Component注解,所以需要在配置类上加@ComponentScan("com.peng.demo.bean")注解进行包扫描

测试发现Cat的初始化及销毁方法也调用了

3.使用JSR250的@PostConstruct注解标注在方法上,当bean创建完成并且赋值完成来初始化,@PreDestroy 当bean从容器移除之前,通知进行销毁

创建一个类

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.stereotype.Component;

@Component
public class Dog {
	
	public Dog() {
		System.out.println("Dog 创建!!!!!!!!!!!!!!!!!");
	}
	
	/**
	 * 
	 * @Description 对象创建并赋值之后调用
	 */
	@PostConstruct
	public void postConstruct(){
		System.out.println("Dog PostConstruct!!!!!!!!!!!!");
	}
	
	/**
	 * 
	 * @Description 当bean从IOC容器移除前调用
	 */
	@PreDestroy
	public void destory(){
		System.out.println("Dog PreDestroy!!!!!!!!!!!!");
	}

}

测试发现Dog的初始化及销毁方法也调用了

4.通过BeanPostProcessor后置处理器,在bean初始化前后进行处理工作, postProcessBeforeInitialization()在初始化之前调用,postProcessAfterInitialization()在初始化之后调用

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@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;
	}	
}

运行测试发现在每个bean的初始化的前后都会调用相应的方法

三:后置处理器(BeanPostProcessor)源码分析

当我们自己定义一个类实现BeanPostProcessor接口后,将其加入到IOC容器中,后置处理器中的postProcessBeforeInitialization()和postProcessAfterInitialization()方法就会在bean的初始化方法的前后调用,通过debug就可以看到。在MyBeanPostProcessor的postProcessBeforeInitialization()方法上加一个断点,以debug运行测试方法就会发现

通过方法调用栈可以发现,首先进入refresh();方法,这里在刷新IOC容器

接着进入refresh()方法会看到调用了finishBeanFactoryInitialization()方法

接着跟进,底层在创建bean并返回

接着,底层就调用了initializeBean()方法,在调用initializeBean()之前会调用populateBean()这是在为bean的属性赋值,在initializeBean(0方法中,出现了最重要的三步

第一步,调用applyBeanPostProcessorsBeforeInitialization(),循环调用所有的后置处理器的postProcessBeforeInitialization()方法,一旦方法返回null就跳出循环

第二步,调用bean的初始化方法invokeInitMethods()。

第三步,调用applyBeanPostProcessorsAfterInitialization(),循环调用后置处理器的postProcessAfterInitialization()方法。

注:上述三步均是在populateBean()调用之后执行,也就是后置处理器及bean的初始化方法均是在bean赋值之后执行。

四:总结

至此整个bean的生命周期就完了,我们可以在bean的构造方法编写构造器的逻辑,然后到bean的初始化方法,在bean的初始化前后还有后置处理器的前后拦截方法,最后又bean的销毁方法,这就是spring为我们提供的bean控制的所有方法。

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐