一、Spring中的Bean的生命周期详解
整体概要流程:
Class--->创建对象--->依赖注入(属性赋值)--->init初始化(before,after)--->awre--->bean--->SpringContext(容器).
1、第一阶段:Class--->创建对象(也就是怎么通过类来创建对象的)?
class---->先扫描---->得到BeanDefinition----->创建对象
1、BeanDefinition:bean的定义,在我们通过一个普通类需要创建对象之前要做的事情,就是怎么定义我们的类,这里面就设计到很多的模块方法,比如:要设置创建是一个单实例的对象还是要创建一个多实例的对象呢?等。
那BeanDefinition是怎么生成的呢,生成的方式有多种,比如@Bean或者利用xml的方式来生成,还有通过包扫描的方式找到,项目在启动的时候会加载我们配置文件,配置文件中就有各种包扫描的路径等。
如图:bean的定义BeanDefinition模块图
2、类的定义好后,将定义的好的信息放入到我们bean工厂里面去也就是我们的BeanFactory。
ApplicationContextapplicationContext=newAnnotationConfigApplicationContext(MainConfig.class); User user = applicationContext.getBean(User.class);
通过我们getBean跟踪进去,会有多种的bean工厂接口,默认会到我们DefaultListableBeanFactory工厂里面,这里面定义了一个BeanDefinitionMap对象也就是这个ConcurrentHashMap这个map对象
/** Map from serialized id to factory instance:从序列化ID映射到工厂实例 */ private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories = new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);
ConcurrentHashMap的key就是beanName(bean的名字); value就是我们类定义的信息也就是我们的 BeanDefinition ,这个地方是记录了下当前工厂里面有哪些bean,这个阶段bean还没有生成。
3、拿到BeanDefinition,通过构造方法来实现bean的创建,bean创建完后会放到singletonObjects(ConcurrentHashMap)中来。
4、创建完bean后,创建完怎么去处理这个bean呢?通过我们bean的后置处理器(beanPostProcessor)来处理(如:给bean赋值,依赖注入,bean的初始化等操作)。bean工厂里面有很多的后置处理器,也可以自定义后置处理器。
bean的后置处理器的定义:生成对象之后所调用的逻辑,执行顺序是先有了工厂-->然后去执行工厂的后置处理器---bean,后置处理器相当于去修改我们的工厂的bean.
模块图:
细化后的执行流程:
Class--->BeanDefinition->BeanFactory--->BeanFactoryProcessor---->创建对象--->依赖注入(属性赋值)--->init初始化(before,after)--->awre--->bean--->SpringContext(容器).
beanFactory和ApplicationContext这个工厂的区别:
他们两是父子关系,ApplicationContext继承了ListableBeanFactory,ListableBeanFactory继承了beanFactory,而且在ApplicationContext在继承拥有所有beanFactory功能后还继承了其他的组件,如下图分析:
二、Spring整合Mybatis底层原理详解
mybatis和Spring整合的目标就是怎么将Dao层的接口注册到Spring容器成为一个bean的问题,从上面的分析要将一个对象注册到spring容器中,必须是类.class才行,很显然Dao层是一个接口,没办法new,肯定不能直接注入进去的,那怎么解决呢这个问题?
1、怎么将一个对象放入到我们的容器中,有多种方式,有@bean、@Import、 xml等方式,还有一种就是通过实现FactoryBean接口的方式去注入bean的,这种就是我们自定义的方式,我们的spring与mybatis的整合就是用这种方式来注册bean的。
实例分析:
package com.tan.util;
import com.tan.bean.Dog;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
//自定实现bean的注册的另一种方式
@Component
public class DemoFactoryBean implements FactoryBean{
//通过这个方法就可以将一个类放入到我们工厂里面去了
public Object getObject() throws Exception {
return new Dog();
}
public Class<?> getObjectType() {
return Dog.class;
}
public boolean isSingleton() {
return false;
}
}
通过断点调试看bean工厂怎么拿到实现FactoryBean的类的,这个是比较特殊的拿法,一般是到singletonObjects中取拿的,但是这种先从singletonObjects去拿,如果没有再去我们的factoryBeanObjectCache对象中去拿,如下图所示:
这里的FactoryBean与前面说的BeanFactory的区别是什么:
FactoryBean是一个小的工厂,他一次只能生成一个对象,而BeanFactory是一个大的工厂。
因为上面的DemoFactoryBean类通过getObject方法返回的是静态写死的对象,那怎么写活呢?那就通过JDK的代理模式生成一个代理类,实例代码如下:
//自定实现bean的注册的另一种方式
@Component
public class DemoFactoryBean implements FactoryBean{
private Class mappers;
public DemoFactoryBean(Class mappers) {
this.mappers = mappers;
}
//通过这个方法就可以将一个类放入到我们工厂里面去了
//UserDao代理对象--->bean
public Object getObject() throws Exception {
Object o = Proxy.newProxyInstance(DemoFactoryBean.class.getClassLoader(), new Class[]{mappers}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
return o;
}
public Class<?> getObjectType() {
return mappers;
}
public boolean isSingleton() {
return false;
}
}
上面的构造函数的Class mappers是怎么传进来的呢,也就是怎么扫描dao层的接口,然后将其变成class对象的。。
第一步:
//通过自定义的包扫描直接将bean的定义信息注册到工厂里面去
public class DemoBeanDefinitionRegistarar implements ImportBeanDefinitionRegistrar{
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//这个地方就是获取我们自定义注解的名字
MultiValueMap<String, Object> allAnnotationAttributes = importingClassMetadata.getAllAnnotationAttributes(DemoScan.class.getName());
//获取注解中的value值
Object o = allAnnotationAttributes.get("value");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanDefinition.setBeanClass(DemoFactoryBean.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(o);
registry.registerBeanDefinition(DemoScan.class.getName(), beanDefinition);
}
}
第二步:自定义注解:
@Import(DemoBeanDefinitionRegistarar.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface DemoScan {
String value() default "";
}
第三步:全局配置文件中使用自定义的注解进行包扫描
@DemoScan("com.tan.dao")
public class MainConfig {