文章目录
什么是Spring
Spring由哪些模块组成(以Spring4为例)
Spring core中:框架的基本组成部分,包括控制反转和依赖注入
Spring IOC(控制反转)
Spring IOC 的实现原理
工厂机制+反射原理
我悟了:知道为啥我们pojo包的类不用注入吗??因为一般业务中一般我们都是自己创建对象(困扰了我好多天!!!,要不然难道你构造一个class都要注入,这spring容器会爆掉吧!!)
OrderEntity是没有注入的类
简单实现与应用+理解
什么是Spring的依赖注入(DI)
实现控制反转的是IOC容器,实现方式是依赖注入
IOC容器根据目标对象的依赖关系,自动注入依赖的对象
依赖的注入方式(构造器注入+set方式注入)–(Bean的xml显示配置)
构造器注入
set方法注入(需要手动加入成员变量的属性)
<bean id="address" class="com.kuang.pojo.Address">
<property name="address" value="南京"/>
</bean>
<bean id="student" class="com.kuang.pojo.Student">
<!-- 1.普通方式注入-->
<property name="name" value="qinjiang"/>
<!-- 2.bean注入-->
<property name="address" ref="address"/>
<!-- 3.数组注入-->
<property name="books">
<array>
<value>全球高考</value>
<value>好生开车</value>
<value>某某</value>
</array>
</property>
<!-- 4.list注入-->
<property name="hobbies">
<list>
<value>听歌</value>
<value>游戏</value>
<value>敲代码</value>
</list>
</property>
<!-- 5.map注入-->
<property name="card">
<map>
<entry key="身份证" value="112345"/>
<entry key="电话号码" value="1525"/>
</map>
</property>
<!-- 6.set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!-- 7.properties注入-->
<property name="info">
<props>
<prop key="学号">2019</prop>
<prop key="性别">男性</prop>
</props>
</property>
</bean>
什么是Spring bean
在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .
Bean的作用域
解决Bean的线程安全问题:1.不要在class对象中创建可变的成员变量;2.将Bean设置为prototype类型;3.实在要使用可变的成员变量,使用ThreadLocal,本地线程的局部变量(注意防止内存泄漏)
单例 bean 的线程安全问题了解吗?
Spring如何处理并发线程安全问题
Bean的生命周期(太难了,放弃)
1. Bean实例化阶段(扫描Component+定义bean):就是获取扫描的component的class对象封装进Beandefinition(Class,scope类型单例or原型),装进beandefinition的hashmap容器中(键为beanname,值为Beandedinition)----如果是单例的class需要先创建实例对象放入hashmap容器缓存
2. Bean初始化:docreate()阶段,主要是从beandedinition拿到class的实例对象,设置好reference类型的属性(主要是扫描Autowired注解的field字段设置属性)–》该类实现了BeanNameAware接口的执行相应的aware回调–》BeanPostProcessor的初始化前后置处理(一般初始化后置postProcessAfterInitialization用于实现AOP)+中间夹杂着是否类实现了InitializingBean接口执行相应的afterPropertiesSet()
spring容器上下文环境的自定义实现
public class ZhouyuApplicationContext {
private Class configClass;//配置类
// 放置单例bean的池子singletonObjects(beanName,class对象)
// bean定义的池子beanDefinitionMap((beanName,bean的定义--主要是bean的类型---单例、原型))
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
// bean的后置处理器的列表
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
// 配置好spring容器并做好扫描工作,完成所有的扫描(相当于定义+ 注册好需要的bean)
public ZhouyuApplicationContext(Class configClass){
this.configClass=configClass;
// 解析配置类:@ComponentScan扫描类路径
scope(configClass);
// 定义bean+加载“单例”bean(注意必须是单例bean的情况下)
instanceSingletonBean();
}
// 解析配置类:@ComponentScan扫描类路径
private void scope(Class configClass) {
ComponentScan componentScanAnnotations =(ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
String path = componentScanAnnotations.value();
System.out.println(path);
path = path.replace(".", "/");
ClassLoader classLoader = ZhouyuApplicationContext.class.getClassLoader();
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
if(file.isDirectory()){
File[] files = file.listFiles();
for(File file1:files){
System.out.println("【文件scope阶段】"+file1);
String absolutePath = file1.getAbsolutePath();
// 判断是不是class文件类型
if (absolutePath.endsWith(".class")) {
String substring = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
// 获取类的全限定名
String className = substring.replace("\\", ".");//com.zhouyu.service.UserService
System.out.println("【文件scope阶段】"+className);
try {
// 加载类+放入bean定义的池子中--前提是先定义好bean的类型信息(原型、单例)
Class<?> clazz = classLoader.loadClass(className);
// 首先判断这个类是否是component组件
if(clazz.isAnnotationPresent(Component.class)){
//判断这个bean是不是bean的后置处理器
if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
try {
BeanPostProcessor instance = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
beanPostProcessorList.add(instance);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
// ....解析bean,判断是否是单例 的bean
Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
String beanName = componentAnnotation.value();
BeanDefinition beanDefinition = new BeanDefinition();//bean的定义对象、
beanDefinition.setBeanClass(clazz);
// 单例bean还是原型的bean
if(clazz.isAnnotationPresent(Scope.class)){
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
}else{
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName,beanDefinition);
};
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
// 创建单例bean的实例,放入缓存中
private void instanceSingletonBean() {
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")) {
Object bean = doCreateBean(beanName, beanDefinition);
// 放入单例bean的hasnmap的赤字中
singletonObjects.put(beanName, bean);
}
}
}
//创建bean对象的方法+注入依赖的对象(Autowired依赖注入)+bean的后置处理器的初始化前和初始化之后的处理
private Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
// 当前要创建的bean的类型
Class beanClass = beanDefinition.getBeanClass();
try {
Object instance = beanClass.getDeclaredConstructor().newInstance();
// 填充属性+实现依赖注入(所有字段的类型+是否标注Autowired注解)
// 将标注Autowired注解字段值放入原生的构造器的字段中中,实现属性的填充(造成依赖注入更早的创建bean对象)
Field[] fields = beanClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
String fieldName = field.getName();
Object bean = getBean(fieldName);
// 该字段可以被获取
field.setAccessible(true);
//将字段值放入原生的构造器中,实现属性的填充,完成真正的初始化工作
field.set(instance, bean);
}
}
// Aware回调:实现基本数据类型的包装类型的属性注入
if (instance instanceof BeanNameAware) {
((BeanNameAware)instance).setBeanName(beanName);
}
// 初始化之前,BeanPostProcessor(由于每个bean都需要经过这个方法,所以后置处理器是第一个创建bean对象的)
for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
}
// 初始化
if (instance instanceof InitializingBean) {
((InitializingBean)instance).afterPropertiesSet();
}
// 初始化之后,BeanPostProcessor
for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
// (返回被代理的对象)
instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
}
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
//从容器中获取bean,可能是从缓存---hashmap,也可能直接创建新的class对象
public Object getBean(String beanName){
if(beanDefinitionMap.containsKey(beanName)){
if (singletonObjects.containsKey(beanName)) {
return singletonObjects.get(beanName);
} else {
// 如果是原型的bean对象,此时当场进行bean的创建
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
return doCreateBean(beanName, beanDefinition);
}
}else{
throw new NullPointerException();
}
}
}
深入理解SpringBean生命周期之InitializingBean详解
Bean的自动装配原理(隐式配置)
首先需要扫描到所有的组件,在初始化bean的设置属性自动装配Autowired
xml显示配置方式
autowired 属性Byname的自动配置(class对象要有setFiled的方法)
这些属性的对象肯定提前放到容器的beanDefinition中了
autowired 属性Bytype的自动配置
使用注解实现自动装配(@Autowired/@Resource/@Qualifier)
需要在配置文件中开启注解的支持
@Autowired注解
是依赖对象不存在
@Qualifier注解(不能单独使用,需要Autowired注解搭配)
@Resource注解(3级原则–>byname+bytype+抛异常)
具体的装配过程
Spring注解(java中的bean显示配置)
声明为Bean的注解有哪些?
@component,@Controller,@Service,@Mapper,@Repository,@Configuration(结合@Bean)----这些都需要通过类路径来扫描
@Bean(方法返回对象注册)和@Component(类注册)注解的区别
@Configuration注解(一般@Bean需要它的搭配)
Spring AOP(面向切面编程)–底层:代理模式
注意:实际JDK动态代理的invoke()方法和CGLIB的interceptor()方法实际调用的都是AOP的AdvisedSupprt类的MethodInterceptor的invoke()方法
静态代理和动态代理的区别
什么是编译期和运行期
编译期就是生成class字节码文件的过程
运行期就是解释执行字节码文件的过程
动态代理模式(JDK动态代理和CGLIB动态代理)
JDK动态代理的核心:Proxy类和InvocationHandler接口(只能代理实现了接口的类)
Proxy类:
InvocationHandler接口:
Proxy类提供了创建动态理类的实例的方法newProxyInstance,且每个动态代理类有一个==“相关联”==的“调用处理程序对象”—即实现了InvocationHandler接口的类,InvocationHandler接口的invoke方法即可以获取代理类的目标对象的所有方法+可以自定义添加方法。
CGLIB代理的核心MethodInterceptor 接口和 Enhancer 类是核心(代理任何类)
总结与对比
Spring AOP 和 AspectJ AOP 有什么区别?
解释一下Spring AOP里的几个名词
Spring MVC
什么是MVC
什么是Spring MVC
Spring MVC的工作原理
dispatchservlet表示servlet的转发器:
简单的应用实现理解
Restful风格详解
路径变量的优势(对比请求参数@RequestParam)
Spring事务管理
事务是逻辑上的一组操作,要么都执行,要么都不执行
事务的ACID特性
spring事务管理的两种方式
事务的传播特性(针对声明式事务的@Transaction注解,默认:PROPAGATION_REQUIRED)
某事务“挂起”之后,任何操作都不在该事务的控制之下
Spring事务的隔离级别
@Transaction接口(声明式事务)
作用范围
注解的常用配置参数
@Transaction注解原理(AOP)
可能同一类中的方法自调用被transaction标注的方法,spring容器启动的时候压根没有扫描到该方法的注解,更不会为其创建代理对象!!!(我觉得是这样)
Spring AOP的自调用问题
@Transaction注解失效的场景
Spring中用到的设计模式(不为难自己了)
工厂模式( BeanFactory 或 ApplicationContext)
Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。
什么是工厂模式
BeanFactory 或 ApplicationContext的区别
单例模式(Bean的默认作用域)
什么是单例模式(做好手撕的准备)**
bean的作用域
代理模式(Spring AOP)
模板模式(***Template的类)
不就是我们SpringMVC中service(接口约束行为)和serviceImpl(接口的实现类)的模式,但是这样还有一个原因是为了JDK动态代理方便!!!
观察者模式(ApplicationListener)----许多的监听器&回调机制
== Spring事件驱动模型中的三种重要角色:事件,事件监听者,事件发布者(为啥像“生产者与消费者模式”???不明白–是有无消息队列的区别吗)好像是消息队列的区别==
到此为止!!!!