Spring-Bean总结

143 阅读5分钟

前置问题:
1、Spring的IOC是什么?DI是什么?
IOC是指spring的控制反转,是指创建对象的工作由开发者本身反转到spring容器上。DI:依赖注入是指bean之间的依赖关系由容器主动注入

2、什么是控制反转?反转的是什么?
控制反转指的是:控制对象创建的动作原本由业务程序反转到了SpringIOC容器
反转的是:组件对象之间的依赖关系由容器进行主动注入

3、什么是BeanFactory?
BeanFactory是bean工厂,主要用来实例化对象和获取对象

4、IOC容器有哪些类型?

5、如何获取BeanFactory、如何获取ApplicationContext?
Resource = xml/注解
BeanFactory factory = new BeanFactory(resource);

ApplicationContext appContext = new ClassPathXmlApplication("")  
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); 

6、BeanFactory和ApplicationContext有什么区别?
beanFactory是bean的创建工厂,context也可以创建工厂,但是里面包含的功能更多

7、Spring创建bean的过程?
加载 -> 解析 -> 实例化 —> 初始化 -> 获取
① 启动后加载classes下的class信息
② 读取class的注解和定义并解析出BeanDefinition
③ 通过反射将BeanDefinition实例化为bean对象
初始化bean的属性和方法
》》设置bean的属性
》》检查Aware接口方法并设置相关依赖
》》检查并执行BeanPostProcessor接口中的postProcessorBeforeInitialization方法
》》 检查配置文件中是否有init-method方法并执行【包含不限于AOP、动态代理、jdk/cglib】
》》检查并执行BeanPostProcessor接口中的postProcessorAfterInitialization方法
⑤ 得到完整的bean对象

8、BeanFactoryPostProcessor的作用是什么?
可以支持自定义修改BeanDefinition的定义

9、BeanPostProcessor的作用是什么?
》》支持自定义修改新的bean实例。
》》postProcessBeforeInitialization在bean初始化回调init-method的时候执行,前置增强
》》postProcessorAfterInitialization在bean初始化执行完init-method之后调用

10、Aware有什么作用?
用来获取在Bean创建过程中容器的内部对象。获取beanfactory对象,beanClassLoader对象、beanName等等
用来设置beanDefinition的一些信息,实现aware接口来自定义设置对应的字段内容,重设classname、beanfactory

11、BeanDefinition是什么?有什么作用?
是将定义的一个bean转换成一个数据结构,包含bean的作用域、属性、类名、加载工厂等信息

12、MyBatis中XXXMapper是怎么自动生成的Bean,放置在Spring容器中的?


Spring中bean和对象之间的关系
所有的对象都是bean?No
bean都是对象?Yes

手动new出来的对象和bean之间的区别?
1、bean生成的对象里面包含的变量也都是有值的
2、手动new出来的对象,属性都是默认值:null

Spring创建bean包含两部分:
1、实例化一个对象
2、填充对象的属性【自动装配:填充组件之间的依赖关系】

Bean的生命周期:狭义的
class -> 基于 BeanDefinition 进行实例化 -> ? -> 填充属性 -> Aware回调 -> 初始化 -> AOP -> 单例池
根据class定义解析成BeanDefinition

BeanDefinition ------BeanFactoryPostProcessor-------> 实例化对象 beanClass scope lazyInit

BeanDefinition:是一个接口

BeanFactory:bean工厂,生产bean,获取bean。在获取到beadDefinition的Map之后就组建完成
BeanFactoryPostProcessor:bean工厂后置处理器,在beanFactory组建完成后才会工作
作用:可以get到beanDefinition、get到bean的className、同时也可以修改beanClass,影响生成
实例对象的类型
让编程人员操作beanFactory

BeanPostProcessor 作用:主要用于实例化对象之后的组件填充

BeanNameAware、BeanFactoryAware、ApplicationContextAware
使用方式:
// 获取beanName的方式

AClass implements BeanNameAware {
   void setBeanName(String var1) {
      this.beanName = var1;
   }
}

初始化: 实现InitializingBean接口;
@PostConstruct;
xml中定义的init-method的方法

@Service
public class UserService implements BeanNameAware, BeanFactoryAware, InitializingBean {
    @Autowired
    private User user;

    private String beanName;

    private BeanFactory createBeanFactory;

    @Override
    public void setBeanName(String s) {
        beanName = s;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        createBeanFactory = beanFactory;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 创建实例化之后,实现业务自定义的初始化动作
    }
}

AOP:动态代理
AOP:@Aspectj、@Component

单例池:ConcurrentHashMap<beanName, AOP之后的代理对象>

Bean的生命周期:广义的
BeanDefinition:Bean的定义,是一个接口。里面包含很多属性:beanClass、lazyInit、scope

Spring整合MyBatis

解决问题:12、MyBatis中XXXMapper是怎么自动生成的Bean,放置在Spring容器中的?

MyBatis通过generatorConfig.xml生成的XXXMapper接口,MyBatis会生成接口对应的bean,放到Spring容器中管理;MyBatis是生成一个代理对象,使用到了FactoryBean,放到了Spring容器中,容器中的bean可以注入到其他组件中

生成代理对象并将bean交给FactoryBean的过程:
1、直接将一个对象放到Spring容器中:beanFactory.registerSingleton("xxx", new Xxx());
2、通过FactoryBean生成一个代理对象,context加载时XXXFactoryBean实际会生成一个代理对象
beanClass是:com.pl.processor.TestFactoryBean,实际生成的是XXXMapper的代理对象,调用代理对象的任何方法时都会执行一遍invoke()方法

@Component
public class TestFactoryBean implements FactoryBean {

    private Class mapper;

    public TestFactoryBean(Class input) {
        this.mapper = input;
    }

    // OrderMapper ------->new TestFactoryBean(OrderMapper.class)------>OrderMapper的代理对象
    // bean的name是testFactoryBean,生成的对象是代理对象UserMapper
    @Override
    public Object getObject() throws Exception {
        Object o = Proxy.newProxyInstance(mapper.getClassLoader(), new Class[]{mapper}, new InvocationHandler() {
            // 调用代理对象的方法时都会调用invoke
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method.getName());
                return null;
            }
        });
        return o;
    }

    @Override
    public Class<?> getObjectType() {
        return mapper;
    }

    // 可以不实现,default方法,默认返回true
    @Override
    public boolean isSingleton() {
        return true;
    }
}

3、依赖FactoryBean,在生成Bean的前置阶段:Class解析BeanDefinition的时候,批量的生成多个代理类;
解决方案:
① 自定义BeanDefinitionRegister实现ImportBeanDefinitionRegistrar,在registerBeanDefinitions方法中注册新的BeanDefinition
② 将修改后的BeanDefinition然后导入到BeanFactory中的BeanDefinitionMap:
③ 将该动作引入到Bean初始化的方式:
@Import(TestBeanDefinitionRegister.class)

public class TestBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        // ① beanDefinitionRegistry注册表
        List<Class> mappers = new ArrayList<Class>();
        mappers.add(UserMapper.class);
        mappers.add(OrderMapper.class);
        
        // ② 优化方式:新增一个Mapper之后如何处理?如何实现自动导入
        
        
        for (Class mapper : mappers) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
            AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

            // 设置BeanDefinition对应的beanClass,改Class专门用来生产代理对象
            beanDefinition.setBeanClass(TestFactoryBean.class);
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(mapper);
            beanDefinitionRegistry.registerBeanDefinition(mapper.getSimpleName(), beanDefinition);
        }
    }
}