Java总结-3

Java总结-3

六、Spring

1. IOC和AOP?

首先声明:IoC & AOP 不是 Spring 提出来的,它们在 Spring 之前其实已经存在了,只不过当时更加偏向于理论。Spring 在技术层次将这两个思想进行了很好的实现。

1.1 IOC?

IoC (Inversion of control )控制反转/反转控制。它是一种思想不是一个技术实现。描述的是:Java 开发领域对象的创建以及管理的问题。

例如:现有类 A 依赖于类 B

  • 传统的开发方式 :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来
  • 使用 IoC 思想的开发方式 :不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面过去即可。

从以上两种开发方式的对比来看:我们 “丧失了一个权力” (创建、管理对象的权力),从而也得到了一个好处(不用再考虑对象的创建、管理等一系列的事情)

  • 为什么叫控制反转?

    控制:指的是对象创建(实例化、管理)的权力,反转:控制权交给外部环境(Spring 框架、IoC 容器)

  • 解决了什么问题?

    IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢?首先对象之间的耦合度或者说依赖程度降低;然后资源变的容易管理;比如你用 Spring 容器提供的话很容易就可以实现一个单例。

1.2 AOP

  • 什么是AOP?

    AOP:Aspect oriented programming 面向切面编程,AOP 是 OOP(面向对象编程)的一种延续。 :指的是横切逻辑,原有业务逻辑代码不动,只能操作横切逻辑代码,所以面向横切逻辑; :横切逻辑代码往往要影响的是很多个方法,每个方法如同一个点,多个点构成一个面。

  • AOP解决了什么问题?

    通过上面的分析可以发现,AOP 主要用来解决:在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。

1.3 AOP实现:JDK动态代理,CGLIB

两种方式:一种是JDK动态代理,另一种是CGLib的方式。

1.3.1 JDK动态代理具体实现原理
  • 通过实现InvocationHandlet接口创建自己的调用处理器;
  • 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
  • 通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;

JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。

1.3.2 CGLib动态代理

CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。

1.3.3 两者对比

JDK动态代理是面向接口的

CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,那么抱歉会失败)。

1.3.4 性能

关于两者之间的性能的话,JDK动态代理所创建的代理对象,在以前的JDK版本中,性能并不是很高,虽然在高版本中JDK动态代理对象的性能得到了很大的提升,但是他也并不是适用于所有的场景。

主要体现在如下的两个指标中:

  • CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少,有研究表明,大概要高10倍;
  • 但是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多,有研究表明,大概有8倍的差距;
  • 因此,对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理。

2.Spring事务管理?

3.Spring启动的过程?

4.Spring Bean的生命周期?

graph TB
st(( ))--通过getBean调用某一个Bean-->a(*调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法)
a-->b(实例化)
b-->c(*调用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法)
c-->d(*调用instantiationAwarebeanPostProcessor的postProcessPropertyValues方法)
d-->e(设置属性值)
e-->f(调用BeanNameAware的setBeanName方法)
f-->g(调用BeanFactoryAware的setBeanFactory方法)
g-->h(*调用BeanPostProcessor的postProcessBeforeInitialization方法)
h-->i(调用InitializingBean的afterPropertiesSet方法)
i-->j(通过init-method属性配置的初始化方法)
j-->k(*调用BeanPostProcessor的postProcessAfterInitialization方法)
k-->l(Spring缓存池中准备就绪的Bean)
k-->m(将准备就绪的Bean交给调用者)
l-->n(调用DisposableBean的destroy方法)
n-->p(通过destroy-method属性配置的销毁方法)
p-->pp(( ))

ps:ApplicationContext中的Bean的生命周期

graph TB
st(( ))--启动容器-->aa(调用BeanFactoryPostProcessor的postProcessBeanFactory方法对工厂定义信息进行处理)
aa--通过getBean调用某一个Bean-->a(*调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法)
a-->b(实例化)
b-->c(*调用InstantiationAwareBeanPostProcessor的postprocessAfterInstantiation方法)
c-->d(*调用instantiationAwarebeanPostProcessor的postProcessPropertyValues方法)
d-->e(设置属性值)
e-->f(调用BeanNameAware的setBeanName方法)
f-->g(调用BeanFactoryAware的setBeanFactory方法)
g-->gg(调用ApplicationContextAware的setApplicationnContext方法)
gg-->h(*调用BeanPostProcessor的postProcessBeforeInitialization方法)
h-->i(调用InitializingBean的afterPropertiesSet方法)
i-->j(通过init-method属性配置的初始化方法)
j-->k(*调用BeanPostProcessor的postProcessAfterInitialization方法)
k-->l(Spring缓存池中准备就绪的Bean)
k-->m(将准备就绪的Bean交给调用者)
l-->n(调用DisposableBean的destroy方法)
n-->p(通过destroy-method属性配置的销毁方法)
p-->pp(结束)

5.Spring AOP和Spring Bean的生命周期有什么关系?

  • AOP本身是可以对一个pojo进行操作,比如希望在一个类中的方法执行前和执行后添加日志信息。
  • 在Spring中,Spring AOP、IOC和AspectJ被整合在一起了。
  • Spring AOP使用了JDK动态代理和CGLIB动态代理。(PS:JDK动态代理只支持接口代理,不支持类代理)
    • JDK动态代理主要涉及的类:Proxy和InvocationHandler
    • CGLIB主要涉及到的接口:MethodInterpreter,Enhance,MethodProxy
    • 对于增强,CGLIB手动建立的,AOP定义了5种增强类型:前置增强、后置增强、环绕增强、异常抛出增强、引介增强。
  • 如何管理植入切面的增强?
    • 直接使用ProxyBean
    • 通过Spring配置来定义:ProxyFactoryBean
    • Spring提供了自动代理机制,让容器自动生成代理,避免上述繁琐的配置方式,在内部,Spring使用BeanPostProcessor自动完成这个工作。

6.接收参数的几种方法?

7.@Bean和@Component的区别?

(1)@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。

(2)@Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。

两者的目的是一样的,都是注册bean到Spring容器中。

  • 区别:

    • @Component(@Controller、@Service、@Repository)通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中。
    • 而@Bean注解通常是我们在标有该注解的方法中定义产生这个bean的逻辑。
    • @Component 作用于类,@Bean作用于方法。
  • 总结:

    @Component和@Bean都是用来注册Bean并装配到Spring容器中,但是Bean比Component的自定义性更强。可以实现一些Component实现不了的自定义加载类。

8. Spring中的设计模式

https://juejin.cn/post/6844903849849962509

(1)单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

(2)工厂模式

Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。

(3)观察者模式

  • Spring 的事件流程总结: ApplicationEvent,ApplicationListener,ApplicationEventPublisher
graph TB
st(( ))-->a(1. 定义一个事件, 实现一个继承自ApplicationEvent, 并且写相应的构造函数)
a-->b(2. 定义一个事件监听者: 实现ApplicationListener接口, 重写onApplicationEvent方法)
b-->c(3. 使用事件发布者发布消息: 可以通过ApplicationEventPublisher的publishEvent方法发布消息)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 定义一个事件,继承自ApplicationEvent并且写相应的构造函数
public class DemoEvent extends ApplicationEvent{
private static final long serialVersionUID = 1L;

private String message;

public DemoEvent(Object source,String message){
super(source);
this.message = message;
}

public String getMessage() {
return message;
}


// 定义一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;
@Component
public class DemoListener implements ApplicationListener<DemoEvent>{

//使用onApplicationEvent接收消息
@Override
public void onApplicationEvent(DemoEvent event) {
String msg = event.getMessage();
System.out.println("接收到的信息是:"+msg);
}

}
// 发布事件,可以通过ApplicationEventPublisher 的 publishEvent() 方法发布消息。
@Component
public class DemoPublisher {

@Autowired
ApplicationContext applicationContext;

public void publish(String message){
//发布事件
applicationContext.publishEvent(new DemoEvent(this, message));
}
}

(4)代理模式

(5)模板方法

(6)适配器模式

(7)装饰者模式

9. Spring 的启动过程是怎样的?

(1)SpringApplication.java注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* Class that can be used to bootstrap and launch a Spring application from a Java main
* method. By default class will perform the following steps to bootstrap your
* application:
*
* <ul>
* <li>Create an appropriate {@link ApplicationContext} instance (depending on your
* classpath)</li>
* <li>Register a {@link CommandLinePropertySource} to expose command line arguments as
* Spring properties</li>
* <li>Refresh the application context, loading all singleton beans</li>
* <li>Trigger any {@link CommandLineRunner} beans</li>
* </ul>
*
* In most circumstances the static {@link #run(Class, String[])} method can be called
* directly from your {@literal main} method to bootstrap your application:
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableAutoConfiguration
* public class MyApplication {
*
* // ... Bean definitions
*
* public static void main(String[] args) {
* SpringApplication.run(MyApplication.class, args);
* }
* }
* </pre>
*
* <p>
* For more advanced configuration a {@link SpringApplication} instance can be created and
* customized before being run:
*
* <pre class="code">
* public static void main(String[] args) {
* SpringApplication application = new SpringApplication(MyApplication.class);
* // ... customize application settings here
* application.run(args)
* }
* </pre>
*
* {@link SpringApplication}s can read beans from a variety of different sources. It is
* generally recommended that a single {@code @Configuration} class is used to bootstrap
* your application, however, you may also set {@link #getSources() sources} from:
* <ul>
* <li>The fully qualified class name to be loaded by
* {@link AnnotatedBeanDefinitionReader}</li>
* <li>The location of an XML resource to be loaded by {@link XmlBeanDefinitionReader}, or
* a groovy script to be loaded by {@link GroovyBeanDefinitionReader}</li>
* <li>The name of a package to be scanned by {@link ClassPathBeanDefinitionScanner}</li>
* </ul>
*
* Configuration properties are also bound to the {@link SpringApplication}. This makes it
* possible to set {@link SpringApplication} properties dynamically, like additional
* sources ("spring.main.sources" - a CSV list) the flag to indicate a web environment
* ("spring.main.web-application-type=none") or the flag to switch off the banner
* ("spring.main.banner-mode=off").
*
* @author Phillip Webb
* @author Dave Syer
* @author Andy Wilkinson
* @author Christian Dupuis
* @author Stephane Nicoll
* @author Jeremy Rickard
* @author Craig Burke
* @author Michael Simons
* @author Madhura Bhave
* @author Brian Clozel
* @author Ethan Rubinson
* @since 1.0.0
* @see #run(Class, String[])
* @see #run(Class[], String[])
* @see #SpringApplication(Class...)
*/

img

10.Spring的自动装配?

11.ApplicationContext通常的实现是什么?

12.AOP实现流程?

(1)基于接口的增强

以下是通过接口实现增强的使用,用起来很笨重。后面来讲基于@AspectJ的方式就简单很多!

graph TB
A1(获取spring提供的代理工厂)-.->B1(设置目标代理)
B1-.->C1(为代理目标设置增强)
C1-.->D1(生成代理实例)
举一个例子,如何自行定义一个权限控制的注解?注解+AOP实现
  • 先定义一个注解,比如叫@AuthCheck
  • 在接口上添加@AuthCheck注解
  • 对一个类添加@AspectJ注解,在这个类中通过@PointCut来扫描@AuthCheck,就是切点;然后定义一些增强,比如使用@Before搞一个前置增强,这个增强对切点进行处理,可以将切点的参数一并携带,进行一些逻辑处理!

13.Springboot自动配置的流程?

(1)refresh()

以下refresh()定义了Spring容器在加载配置文件后的各项处理过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
// (1)初始化Bean Factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
// (2)调用工厂后处理器
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
// (3)初始化Bean后处理器
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
// (4)初始化消息源
initMessageSource();

// Initialize event multicaster for this context.
// (5)初始化应用上下文事件广播器
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
// (6)初始化其他的Bean
onRefresh();

// Check for listener beans and register them.
// (7)注册事件监听器
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// (8)初始化所有的单实例Bean,使用懒加载模式的除外
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
// (9)完成刷新并发布容器刷新事件
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

(2)spring从配置文件创建完整bean的流程

graph TB
st((配置文件))--ResourceLoader装载配置文件-->a(Resource)
a--BeanDefinitoinReader解析配置信息-->b(BeanDefinitionRegistry加工前的BeanDefinition)
b-->c(BeanDefinitionRegistry加工后的BeanDefinition)
b-->d(PropertyEditorRegistry存放的自定义的PropertyEditor)
c--InstantiationStrategy实例化Bean对象-->e(Bean实例未设置属性)
d--BeanWrapper设置Bean属性-->f(Bean实例已设置属性)
e--BeanWrapper设置Bean属性-->f
f--BeanPostprocessror对Bean进行加工-->g(Bean实例准备完成)
1
2
3
4
5
6
7
(1) ResourceLoader从存储介质加载Spring配置信息,并使用Resource表示这个配置文件资源。
(2) BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中的每一个<bean>解析成一个BeanDefinition对象,并且保存到BeanDefinitionRegistry中。
(3) 容器扫描BeanDefinitonRegistry中的BeanDefinition,使用Java反射机制自动识别出Bean工厂后处理器(实现了BeanFactoryPostProcessor接口的Bean),然后调用这些Bean工厂后处理器对BeanDefinitionRegistry中的BeanDefinition进行加工处理。
(4) Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并且调用InstantiationStrategy着手进行Bean实例化工作。
(5) 在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装。BeanWrapper提供了很多以Java反射机制操作bean的方法,它将结合该Bean的BeanDefinition以及容器中的属性编辑器,完成Bean的属性注入工作。
(6) 利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean)对已经完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean。
总结:先对BeanDefinition操作,然后对Bean操作。

(3)Spring boot自动配置

举例:在引入MyBatis的starter后,MyBatis相关的Bean自动装配进入容器,如何仅仅通过starter来实现?

1)SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration

2)@EnableAutoConfiguration 作用:利用EnableAutoConfigurationImportSelector给容器中导入一些组件可以查看selectImports()方法的内容;

List configurations = getCandidateConfigurations(annotationMetadata, attributes);

获取候选的配置

1
2
3
4
5
> SpringFactoriesLoader.loadFactoryNames()
> 扫描所有jar包类路径下 META‐INF/spring.factories
> 把扫描到的这些文件的内容包装成properties对象
> 从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
>

将 类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中;每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置;

3)、每一个自动配置类进行自动配置功能;

14.BeanFactory和FactoryBean的区别?

  • BeanFactory是工厂,我们通过getBean获取Bean。
  • FactoryBean是一个工厂类接口,可以用来定制Bean的逻辑,Spring提供了很多FactoryBean的实现类,隐藏了实例化一些复杂Bean的细节。

15.@Resource和@Autowired的作用的相同的么?

  • 这是一个sb的问题,没啥子实际区别!

16.BeanFactory和ApplicationContext的区别?

  • 生命周期上有区别
  • 对Bean的初始化有区别

17.在 Spring中如何注入一个java集合?

18.MyBatis 相关

(1)简单谈谈你对 Mybatis 的理解?

(2)MyBatis 接口绑定的优点是什么?

(3)实现 MyBatis 接口绑定分别有哪几种方式?

(4)MyBatis 如何实现一对一关联关系?

(5)MyBatis 如何实现一对多关联关系?

(6)说说 MyBatis 动态 SQL 的具体使用步骤?

(7)MyBatis 与 Hibernate 的区别是什么?

(8)MyBatis 如何实现模糊查询?

19.Nginx 反向代理实现高并发的具体步骤是什么?

20.Nginx 搭建 Tomcat 集群的核心配置应该怎么写?

21.bean之间的关系?(继承,依赖)

22.配置外部数据源?context:property-placeholder,使用${var}

23.SpEL的使用

(1)SpEL的作用?

24.bean的配置方式?

(1)xml文件

(2)注解(可以使用value修改名字)

25.Spring事务管理

(1)编程式事务管理(注释)

(2)声明式事务管理(XML)

26.Spring Boot事务管理

27.Spring事务的传播行为

28.Spring的事务隔离级别

29. 注解

30. Spring 问题?

30.1 Spring 循环依赖?

循环依赖:一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用。

循环依赖总结一下(假设A,B之间循环依赖):
一级缓存singletonObject,也就是常说的单例池,是个Map
二级缓存earlySingletonObjects,也就是提前一点的单例池,哈哈,字面翻译,也是Map
三级缓存singletonFactories,这个Map有点特殊,因为这个Map的value存放的是一个lambda表达式
1、单例池不能存放原始对象,只能存放经过完整生命周期的对象,也就是java bean
2、A,B在注入属性都会执行一个addSingletonFactory方法,这个方法里面三级缓存就出现了,三级缓存put了key为beanName,value为一个lambda表达式
3、其实最容易绕晕的地方是,当B注入属性A的时候,执行populateBean注入一个bean的属性的时候会执行getSingleton这个方法,一定要记得!!populateBean方法体中没有直接调用getSingleton这个方法,但一定要记得,执行了这个方法
4、getSingleton这个方法,会依次到一级缓存,二级缓存,三级缓存中get(beanName),很显然当B注入A属性的时候,一级,二级里面都没有内容,只有三级有,这时会执行lambda表达式,lambda表达式的作用就是生成代理对象!!然后把生成的代理对象存入二级缓存,并返回这个代理对象,B就会得到这个代理对象A,B就会认为这个代理对象A就是A的最后的bean对象,因此也就完成了对A的属性注入这步操作,接着依次执行B后续的操作,最后就完成了B的生命周期,B就成功变成了bean对象,B也就完成了使命
5、当B完成使命之后,A就会继续注入B,这时就会注入属性成功了,接下来开始执行AOP操作,因为上一步中A已经生成了代理对象A,也就是相当于完成了AOP,所以B就不执行AOP操作了,此时A就会执行最后一步操作,将代理对象A放入到单例池中去,这时A就会执行方法getSingleton,从二级缓存中获得了代理对象A,最后将其存入单例池,也就是一级缓存!好了,现在A和B都放入了单例池,圆满结束!!!!

30.2 Spring为什么要有三级缓存?

三级缓存的实现在代码中的 SingletonBeanRegistry 中,其中有以下几个核心属性:

  • singletonObjects:一级缓存, 用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用。

  • earlySingletonObjects:二级缓存,用于存放提前曝光的单例对象的cache,原始的 bean 对象(尚未填充属性)。

  • singletonFactories:三级缓存,用于存放 bean 工厂对象(ObjectFactory)。三级缓存中用到了 ObjectFactory,这里的 ObjectFactory 可以理解为三级缓存中 Bean 的代理对象,其 getObject() 方法描述了如何获取这个三级缓存的对象。设计成这样除了方便实现三级缓存解决循环依赖,另外也是方便 Spring 在 ObjectFactory 中做一些拓展。

  • singletonsCurrentlyInCreation:用于存放正在被创建的 Bean 对象。

    二级和三级只有在产生循环依赖的时候用到。

img

img

img

31. Spring单例实现

使用ConcurrentHashMap存放Bean

1
2
3
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
synchronized (this.singletonObjects)

七、Spring Boot

1.Spring boot重要的构成部分

2.Spring Boot启动过程

https://www.e-learn.cn/content/qita/2004793

graph TB
A1(加载resources/META-INF/spring.factories中配置的ApplicationContextInitializer ApplicationListener)-.->B1(加载 resources/META-INF/spring.factories 中配置的 SpringApplicationRunListener)
B1-.->C1(创建 StandardServletEnvironment 并完成初始配置)
C1-.->D1(通过 EventPublishingRunListener发布ApplicationEnvironmentPreparedEvent事件)
D1-.->E1(加载resources/META-INF/spring.factories中配置的EnvironmentPostProcessor,
并触发其 postProcessEnvironment调用,完成Environment的后处理,主要用于加载属性源到 Environment中) E1-.->F1(将Environment绑定到SpringApplication 中) F1-.->G1(创建ApplicationContext:AnnotationConfigServletWebServerApplicationContext) G1-.->H1(加载 resources/META-INF/spring.factories 中配置的 SpringBootExceptionReporter'FailureAnalyzers') H1-.->I1(执行所有已加载的 ApplicationContextInitializer,附加自定义配置) I1-.->J1(通过EventPublishingRunListener发布 ApplicationContextInitializedEvent事件) J1-.->K1(创建 BeanDefinitionLoader, 将应用程序主类解析为 BeanDefinition 并注册到 DefaultListableBeanFactory中) K1-.->L1(通过 EventPublishingRunListener 发布 ApplicationPreparedEvent 事件) L1-.->M1(prepareRefresh:清除类路径扫描器缓存写入closed, active 标识,验证所有必须的属性是否都能解析) M1-.->N1(obtainFreshBeanFactory:写入 refreshed 标识, 获取 DefaultListableBeanFactory) N1-.->O1(prepareBeanFactory:写入 BeanPostProcessor写入可以忽略的依赖注入接口, 注册部分内部可解析的依赖接口等) O1-.->P1(postProcessBeanFactory:注册 WebApplicationScope, 注册部分内部可解析的依赖接口) P1-.->Q1(invokeBeanFactoryPostProcessors:执行
SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor
注册用于获取MetadataReader的org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory的BeanDefinition) Q1-.->R1(registerBeanPostProcessors:按照 PriorityOrdered, Ordered, 普通的顺序将 BeanPostProcessor添加到 BeanFactory 中) R1-.->S1(initMessageSource:注册 messageSource 单例'DelegatingMessageSource') S1-.->T1(注册applicationEventMulticaster单例'SimpleApplicationEventMulticaster', 用于广播 ApplicationEvent) T1-.->U1(onRefresh:设置主题, 创建内嵌服务器'WebServer',
获取 ServletContextInitializer DispatcherServletRegistrationBean初始化器
并注册DispatcherServlet到 javax.servlet.ServletContext和org.apache.catalina.core.ApplicationContext中.
注册 OrderedCharacterEncodingFilter,OrderedHiddenHttpMethodFilter,
OrderedFormContentFilter, OrderedRequestContextFilter等过滤器,
也可注册自定义过滤器. 写入 ServletContextPropertySource, ServletConfigPropertySource到Environment中) U1-.->V1(registerListeners:注册内置的 ApplicationListener, 自定义的 ApplicationListener 到 ApplicationEventMulticaster中) V1-.->W1(finishBeanFactoryInitialization:冻结 DefaultListableBeanFactory 中注册的BeanDefinition 信息,
并实例化所有非延迟初始化的单例 bean.
在所有 eager 单例初始化完成之后,
如果其实现了 SmartInitializingSingleton 接口, 则触发其 afterSingletonsInstantiated 调用完成后处理) W1-.->X1(注册 DefaultLifecycleProcessor,查找所有实现 SmartLifecycle 接口的 bean && 如果它是 isAutoStartup,则触发其start方法调用) X1-.->Y1(通过 EventPublishingRunListener 发布 ContextRefreshedEvent 事件) Y1-.->Z1(启动 WebServer) Z1-.->A2(通过 EventPublishingRunListener 发布 ServletWebServerInitializedEvent 事件) A2-.->B2(清理各种缓存) B2-.->C2(注册 Application 的 ShutdownHook) C2-.->D2(触发 SpringApplicationRunListener 的 started 通知) D2-.->E2(通过 EventPublishingRunListener 发布 ApplicationStartedEvent 事件) E2-.->F2(按照 Order 对 ApplicationRunner,CommandLineRunner 进行排序,并顺序执行) F2-.->G2(触发 SpringApplicationRunListener 的 running 通知) G2-.->H2(通过 EventPublishingRunListener 发布 ApplicationReadyEvent 事件) H2-.->I2(应用程序启动完成)

3. 自定义spring-boot-starter

img

  • 写一个@Enable*的注解,@Import相关的@Configuration
  • 写具体的实现
  • 写@Configuration,创建Bean

八、RocketMq

1. 事务机制

(1)half机制

2. Dledger(外部机制实现高可用)

(1)Raft协议

  • Leader
  • follower
  • candidate(竞选状态)

3. 私信队列

  • 一直没有消费———>Retry队列———->死信队列————->加入另外的消费者消费

4. 怎么避免消息丢失?

5. 消息堆积处理?

6. 顺序消费?

-------------本文结束感谢您的阅读-------------
我知道是不会有人点的,但万一有人想不开呢?