答案:
顶层接口
(顶层即无父接口)主要职责就是生产Bean
工厂的设计模式
,即通过调用getBean传入标识来生产一个
Bean实现类
,每个工厂都有不同的职责(单一职责功能),最强大的是DefaultListableBeanFactory
,Spring底层就是使用该实现工厂来生产Bean的答案:
它主要负责存储Bean的定义信息
,决定Bean的生产方式。如spring.xml:
<bean class="com.llg.User " id="user" scope="singleton" lazy="false" abstract="false" autowire="none" >
<property name="username" value="9527">
bean>
把以上Bean的这些定义信息,拿到并赋值给BeanDefinition(的实现类)的属性,然后交给BeanFactory来生产:
以汽车为例来对比:
答案:
ApplicationContext即Spring的上下文,其实现了BeanFactory接口。
FactoryBean的getBean方法用于生产Bean,但ApplicationContext不生产Bean,而是通知FactoryBean来干活儿(即调用)
,它的getBean方法其实是个门面方法,底层在调BeanFactory的getBean方法
它们都可以做为Spring容器,因为它们都可以来管理Bean的声明周期
ApplicationContext在开发中打交道最多,是因为它做了更多的事情,如自动把我们配置的Bean(如@Component)注册进来、加载环境变量、实现事件监听等
ApplicationContext和BeanFactory,就像4S店和汽车厂的关系
,它虽然不造车,从车厂拿车,但它会做销售、保养、上牌等一系列事儿
答案:
BeanFactory是一个工厂,也是一个容器,用来管理和生产Bean的
FactoryBean则只是一个Bean,特殊的Bean
,所以也是由BeanFactory来管理的
FactoryBean是一个接口,必须被另一个Bean去实现,此时这个被寄生的Bean则不再是是它自身,而是FactoryBean接口中getObject方法返回的那个Bean
,getObject方法返回的这个Bean,可以是被寄生的Bean的子类,也可以是和被寄生的Bean的这个类毫无关系的类
如果想获得原来的Bean实例,可加&
FactoryBean创建Bean的方式是懒加载的,使用Bean的时候才会调用getObject方法并把对象添加到容器
代码演示:
@Component
public class UserMapper{
public UserMapper(){
System.out.println("UerMapper对象加载");
}
public void query(){
System.out.println("query");
}
}
@Configuration
@ComponentScan //扫不到时自己调整包路径
public class MainConfig{
}
public class Run{
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
UserMapper userMapper = (USerMapper) context.getBean("userMapper");
userMapper.query();
}
}
此时运行一切正常:
UserMapper再去实现FactoryBean这个接口,此时getBean得到的userMapper对象就是重写的getObject方法返回的对象。
@Component
public class UserMapper implements FactoryBean{
public UserMapper(){
System.out.println("UerMapper对象加载");
}
public void query(){
System.out.println("query");
}
@Override
public Object getObject() throws Exception{
return "code9527"; //直接返回一个不相干的String对象
}
@Override
public Class<?> getObjectType(){
return String.class;
}
}
此时,getBean得到的userMapper就是一个String对象,那自然会类转换异常:
想获得原Bean,则加&:
UserMapper userMapper = (USerMapper) context.getBean("userMapper");
且此时创建Bean的方式是懒加载的
,使用Bean的时候才会调用getObject方法并把对象添加到容器。修改下getObject:
此时断点,执行完new AnnotationConfigApplication(),即容器创建完成、Bean加载完成,控制台仍未输出"getObject调用===",即并未执行getObject()方法,直到getBean时才输出:
图片链接:https://www.processon.com/view/link/5f15341b07912906d9ae8642
答案:
对照上图:
概念态的Bea
n)(定义态的Bean)
(纯净态的Bean)
成熟态的Bean
)问题分析:
扩展点,即Spring Ioc在加载的过程中,其底层会对外提供很多的扩展接口或者一些钩子方法,当我们自己去实现这些接口时,Spring就会在特定的点,帮我们调用钩子方法,从而实现对Spring底层的扩展。
Spring有非常多的扩展接口,重点有:
A1: 执行BeanFactoryPostProcessor的postProcessBeanFactory方法
Spring提供了对BeanFactory进行操作的处理器BeanFactoryProcessor,简单来说就是获取容器BeanFactory,这样就可以在真正初始化bean之前对bean做一些处理操作。bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。
简单来说就是在工厂里所有的bean被加载进来后但是还没初始化前,对所有bean的属性进行修改也可以add属性值。
/**
* 作用: 在注册BeanDefinition的可以对beanFactory进行扩展
* 调用时机: Ioc加载时注册BeanDefinition的时候会调用
* 看接口的参数,看它把啥给你了,比如这里给了BeanFactory对象
*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postprocessBeanFactory(ConfigurableListableBeanFactory beanFactor) throws BeansException {
}
}
A2: BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
/**
* 作用:动态注册BeanDefinition
* 调用时机: Ioc加载时注册BeanDefinition 的时候会调用
*/
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException (
RootBeanDefinition beanDefinition = new RootBeanDefinition(Car.class);
registry.registerBeanDefinition("car",beanDefinition);
}
A3: Bean生命周期的回调方法:初始化和销毁
InitializingBean接口
为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
实现DisposableBean接口
,在这个Bean生命周期结束前调用destory()方法做一些收尾工作
public interface DisposableBean {
void destroy() throws Exception;
}