Spring、MyBatis

78 阅读8分钟

前置问题: 1、Spring的IOC是什么?DI是什么? 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有什么区别?

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的作用是什么?还会执行AOP----postProcessAfterInitialization 支持自定义修改新的bean实例。 postProcessBeforeInitialization在bean初始化回调init-method的时候执行,前置增强 postProcessorAfterInitialization在bean初始化执行完init-method之后调用 10、Aware有什么作用? 用来获取在Bean创建过程中容器的内部对象。获取beanfactory对象,beanClassLoader对象、beanName等等

11、BeanDefinition是什么?有什么作用?

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的方法

BeanFactory:bean工厂:用来创建bean

@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

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

1、什么是循环依赖?

指的是A类里面的属性用到了B类,B类中属性也用到了A

2、循环依赖为什么不能彻底解决,非构造方法注入也不能,为什么?

3、二级缓存如何解决循环依赖

4、Spring为什么用三级缓存去解决循环依赖

5、三级缓存的精妙之处

一个缓存Map

单例池是二级缓存

一开始注入给B的A对象(原始对象)和加工之后的A对象有可能不一样吗?动态代理

SpringAOP的动态代理。单例池中的是代理对象

代理对象和原始对象是不同的

使用了AOP的bean,其实是会生成动态代理对象,这个时候循环依赖就会有问题

Spring无法解决循环依赖中因为使用BeanPostProcessor自定义改变bean 的循环依赖问题

Spring只解决了AOP带来的循环依赖问题

三级缓存:

map:<beanName, ObjectFactory>

createBean:创建一个bean的过程:

1、建一个原始对象

2、singletonFactories.put(beanName, objectFactory) () -> getEarlyBeanReference(beanName, mbd, bean原始对象)

3、填充属性 -------> getSingleton(beanName)-------singletonFactories从这个map查找AService

4、AOP代理---------> 非循环依赖的场景时会新生成一个代理对象,循环依赖的时候这里不会再次生成代理对象,返回的是原始对象

5、加入单例池

getSingleton(beanName)的实现:

先从二级缓存singleObjects里面查找

没有的话从三级缓存,singletonFactories里面走getObject方法

getEarlyBeanReference(beanName, mbd, bean原始对象):----> earlyProxyReferences ---> 代理对象(提前生成)

注入给BService中的属性A也是代理对象

AOP代理对象内部是包括原始对象

Bean的生命周期:

① 扫描类 ----->BeanDefinition

② 生成一个原始对象:aService = new AService() ,生成完原始对象之后会调用表达式放入到三级缓存中

() -> getEarlyBeanReference(beanName, mbd, bean原始对象) ----> 三级缓存

③ aService 填充对象的属性 -----> bService的Bean ---->

先去构造一个BService的bean ---> getSingleton(AService)

④ Aware、init方法

⑤ BeanPostProcessor:bean的后置处理器,前面生成的对象进行加工 进行AOP--->生成代理对象 自定义BeanPostProcessor

⑥ 从二级缓存中拿AOP代理对象

⑦ bean放到单例池中-----singleObjects:concurrentHashMap(beanName, bean对象)

BService:

① 扫描类 ----->BeanDefinition

② 生成一个原始对象:bService = new BService() ,生成完原始对象之后会调用表达式放入到三级缓存中

() -> getEarlyBeanReference(beanName, mbd, bean原始对象) ----> 三级缓存

③ bService 填充对象的属性 -----> aService的Bean ----> 三级缓存中找AService ---> lambda ---> 执行完---->AOP之后的代理对象 -----> 二级缓存中

④ Aware、init方法

⑤ BeanPostProcessor:bean的后置处理器,前面生成的对象进行加工 进行AOP--->生成代理对象 自定义BeanPostProcessor ----- getSingleton(AService)

⑥ bean放到单例池中-----singleObjects:concurrentHashMap(beanName, bean对象)

lambda表达式:() -> getEarlyBeanReference(beanName, mbd, bean原始对象)

非循环依赖的场景在第⑤步时会新生成一个代理对象,循环依赖的时候这里不会再次生成代理对象,返回的是原始对象

循环依赖的场景会把代理对象放到第⑥步中的单例池中

什么是一级缓存:单例池:singleObjects

什么是二级缓存:earlySingletonObjects

什么是三级缓存:singletonFactories

为什么需要三级缓存:

三级缓存是什么?三级缓存里面存储的是lambda,在产生循环依赖的时候别的bean需要时才会执行

Spring MVC:

学习视频地址:www.bilibili.com/video/BV1Kz…

image-20220912133427439

Spring cloud Alibaba微服务内容:www.bilibili.com/video/BV1gB…

MyBatis的插件运行原理是?

MyBatis的分页方式?

1、基于SQL进行分页

2、通过RowBonus进行分页

3、

设计模式之代理模式

代理实现方式:

方式一:继承方式 implements

业务类AService,对应的代理类时AServiceProxy

这两个类都实现一个基础接口:IAInterface

AService实现接口后只需要定义完成业务处理逻辑

AServiceProxy 实现接口后的逻辑:完成业务逻辑代码 + 代理任务

方式二:extends方式

一般是用来实现对外部类的扩展

动态代理:

不用手动为每个原始类编写代理类,在运行的时候,动态的创建原始类对应的代理类,在系统中用代理类替换到原始类

Java本身提供了动态代理的语法,底层依赖的是Java的反射语法

避免了静态代理的每个类都需要手动创建一个代理类,造成项目中存在大量的代理类