Bean创建流程:
spring的一大优点就是扩展性很强,比如,在spring bean 的生命周期中,给我们预留了很多参与bean 的生命周期的方法。
大致梳理一下,有以下几种:
- 自定义 org.springframework.beans.factory.config.BeanPostProcessor ,来让 spring 回调我们的方法来参与 bean的生命周期。
- 在指定方法上加上@PostConstruct 或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用;
- 通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;
- 通过 元素的 init-method/destroy-method属性指定初始化之后 /销毁之前调用的操作方法;
具体流程如下:
- 实例化:利用构造方法来实例化得到一个对象(但是如何一个类中有多个构造方法,Spring则会进行选择,这个叫做推断构造方法);
- 依赖注入:实例化后,Spring会判断该对象中是否存在被@Autowired注解了的属性,把这些属性找出来并由Spring进行依赖注入;
- Aware回调:如果实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware等接口,则执行相应的重写方法;
- 执行BeanPostProcessor.postProcessBeforeInitialization()进行初始化前操作;
- 执行@PostConstruct注解对应的方法进行初始化;
- 执行重写的InitializingBean接口的afterPropertiesSet()方法进行初始化;
- 执行BeanPostProcessor.postProcessAfterInitialization()进行初始化后操作(Spring的AOP在此方法内实现);
如果不用进行AOP,那么该Bean就是此类的构造方法所得到的对象。
如果需要进行AOP,那么该Bean就是通过动态代理生成一个代理对象,而不是该类本身所得到的对象。- 执行@PreDestroy注解对应的方法进行销毁前操作;
- 执行重写的DisposableBean接口的destroy()方法进行销毁操作;
/**
* @author Herbert
*/
@Component
public class DemoController implements InitializingBean,DisposableBean {
@Autowired
private DemoService demoService;
private String name = "Herbert";
public DemoController() {
System.out.println();
System.out.println("constructor ");
System.out.println( "name:" + name);
System.out.println( "demoService:" + demoService);
System.out.println();
}
@PostConstruct
public void postConstruct(){
System.out.println();
System.out.println("@PostConstrut");
System.out.println( "name:" + name);
System.out.println( "demoService:" + demoService);
System.out.println();
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println();
System.out.println("afterPropertiesSet");
System.out.println( "name:" + name);
System.out.println( "demoService:" + demoService);
System.out.println();
}
@PreDestroy
public void preDestroy(){
System.out.println();
System.out.println("@PreDestroy");
System.out.println( "name:" + name);
System.out.println( "demoService:" + demoService);
System.out.println();
}
@Override
public void destroy() throws Exception {
System.out.println();
System.out.println("destroy");
System.out.println( "name:" + name);
System.out.println( "demoService:" + demoService);
System.out.println();
}
public void init(){
System.out.println();
System.out.println("init-method by xml 配置文件");
System.out.println( "name:" + name);
System.out.println( "demoService:" + demoService);
System.out.println();
}
public void cleanUp(){
System.out.println();
System.out.println("destroy-method by xml 配置文件");
System.out.println( "name:" + name);
System.out.println( "demoService:" + demoService);
System.out.println();
}
}
/**
* @author Herbert
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DemoController){
System.out.println();
System.out.println("BeanPostProcessor:" + "postProcessBeforeInitialization");
Field field = null;
try {
field = bean.getClass().getDeclaredField("demoService");
field.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Object o = field.get(bean);
System.out.println( "demoService已注入:" + o);
System.out.println();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DemoController){
System.out.println();
System.out.println("BeanPostProcessor:" + "postProcessAfterInitialization");
Field field = null;
try {
field = bean.getClass().getDeclaredField("demoService");
field.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Object o = field.get(bean);
System.out.println( "demoService已注入:" + o);
System.out.println();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return bean;
}
}
/**
* @author Herbert
*/
@Component
public class DemoService {
}
/**
* @author Herbert
*/
@SpringBootApplication
public class SpringBeanTest {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringBeanTest.class, args);
applicationContext.close();
}
}
执行结果:
代码下载地址:springbeanDomo.rar
推断构造方法:
- 如果只有一个构造方法,用这个构造方法;
- 如果存在多个构造方法,用无参的构造方法,若不存在无参的构造方法,那么Spring就会报错;
- 如果某个构造方法上加了@Autowired注解,Spring就会用这个加了@Autowired注解的构造方法;
需要重视的是,如果Spring选择了一个有参的构造方法,Spring在调用这个有参构造方法时,需要传入参数,那这个参数是怎么来的呢?
Spring会根据入参的类型和入参的名字去Spring中找Bean对象(以单例Bean为例,Spring会从单例池那个Map中去找):
- 先根据入参类型找,如果只找到一个,那就直接用来作为入参;
- 如果根据类型找到多个,则再根据入参名字来确定唯一一个;
- 最终如果没有找到,则会报错,无法创建当前Bean对象。
AOP的大致流程(cglib):
- 生成代理类UserServiceProxy,代理类继承UserService;
- 代理类中重写了父类的方法,比如UserService中的test()方法;
- 代理类中还会有一个target属性,该属性的值为被代理对象(也就是通过UserService类推断构造方法实例化出来的对象,进行了依赖注入、初始化等步骤的对象)
- 当我们从Spring容器得到UserService的Bean对象时,拿到的就是UserServiceProxy所生成的对象,也就是代理对象。
代码下载地址:springbeanDomo.rar