前置问题: 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…
Spring cloud Alibaba微服务内容:www.bilibili.com/video/BV1gB…
MyBatis的插件运行原理是?
MyBatis的分页方式?
1、基于SQL进行分页
2、通过RowBonus进行分页
3、
设计模式之代理模式
代理实现方式:
方式一:继承方式 implements
业务类AService,对应的代理类时AServiceProxy
这两个类都实现一个基础接口:IAInterface
AService实现接口后只需要定义完成业务处理逻辑
AServiceProxy 实现接口后的逻辑:完成业务逻辑代码 + 代理任务
方式二:extends方式
一般是用来实现对外部类的扩展
动态代理:
不用手动为每个原始类编写代理类,在运行的时候,动态的创建原始类对应的代理类,在系统中用代理类替换到原始类
Java本身提供了动态代理的语法,底层依赖的是Java的反射语法
避免了静态代理的每个类都需要手动创建一个代理类,造成项目中存在大量的代理类