20211027服务启动错误

问题:rc.local增加启动脚本错误导致用root用户启动服务导致服务无法启动

1
su - user -c "***.sh xxx"

原因:服务将多个配置文件更新成root权限,但由于环境变量在用户目录中,导致服务无法启动,并且部分文件权限已更改

解决:查看启动脚本,调试shell脚本,最终定位到某个配置文件无法读取,原因为权限不够。查找服务目录下所有权限有问题的文件。

1
2
find . -uid 0
find . -gid 0

修改权限

1
chown -R group:user  /path

重新启动

jps查看java进程

netstat -anp|grep pid查看进程与端口

spring IOC

核心容器

1.BeanFactory

工厂的顶层接口,但是只负责生产对象,不负责怎么生产对象。

IOC容器负责具体生产过程。

2.BeanDefinition

bean对象的定义

image-20210920180524436

3.BeanDefinitionReader

bean的解析

web IOC初始化流程

序号/类名 DispatcherServlet FrameworkServlet HttpServletBean HttpServlet
init
initServletBean
initWebApplicationContext
configureAndRefreshWebApplicationContext
refresh
onRefresh
initStrategies

基于xml的IOC容器初始化

IOC容器的初始化包括beandefinition的resource定位,加载和注册三个基本过程

1
2
3
super(parent);   //设置容器资源加载器
this.setConfigLocations(configLocations);//设置bean资源路径定位
this.refresh();//开始启动

IOC容器的启动

IOC容器对bean配置资源的载入是从refresh()函数开始的,refresh是一个模板方法,规定了IOC容器的启动流程,有些逻辑交给子类实现。ClassPathXmlApplicationContext通过调用父类AbstractApplicationContext的refresh方法启动IOC容器对Bean定义的载入过程

作用:IOC容器创建前,如果已经有容器存在,把已经有的容器给销毁,保证refresh之后使用的是新建立起来的IOC容器

容器的创建

1
2
AbstractApplicationContext中 obtainFreshBeanFactory方法调用子容器的refreshBeanFactory
实际实现是在AbstractRefreshableApplicationContext中

先销毁,再载入

载入配置路径

AbstractRefreshableApplicationContext中定义了抽象的loadBeanDefinitions方法,实际实现是其子类AbstractXmlApplicatioContext中对该方法实现,并且调用了loadBeanDefinitions方法载入Bean

分配路径处理策略

loadBeanDefinitions方法对Bean进行加载

![image-20210921163013437](C:\Users\admin\Desktop\spring IOC\image-20210921163013437.png)

解析配置文件路径

XmlBeanDefinitionReader通过调用ClassPathXmlApplicatioinContext的父类DefaultResourceLoader的getResource方法获取加载的资源

开始读取配置内容

XmlBeanDefinitionReader里面的loadBeanDefinitions(Resource…)方法代表bean文件的资源定义以后的载入过程,将Bean配置信息转换成Document对象,该过程有documentLoader方法实现

准备文档对象

DocumentLoader将Bean配置资源转换成Document对象

分配解析策略

xmlBeanDefinitionReader类中的doLoadBeanDefinition方法从特定的XML文件中实际载入Bean配置资源的方法。

Bean配置资源的载入解析分为以下两个过程:

xml解析器将Bean配置信息转换得到Document对象;

完成xml解析后,按照spring Bean的定义规则对Document对象进行解析

将配置载入内存

BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类DefaultBeanDefinitionDocumentReader对Document对象进行解析

载入<bean>元素

Bean配置信息中的<import>和<alias>元素解析在DefaultBeanDefinitionDocumentReader中已经完成,对Bean配置信息中使用最多的<bean>元素交由BeanDefinitionParserDelegate来解析

载入<property>元素

BeanDefinitionParserDelegate在解析<Bean>调用parsePropertyElements方法解析<Bean>元素中的<property>属性子元素

载入<property>子元素

载入<list>子元素

分配注册策略

DefaultBeanDefinitionDocumentReader对Bean定义转换的Document对象解析的流程中,在其parseDefaultElement方法中完成对Document对象的解析流程中,封装BeanDefinition的BeanDefinitionHold对象,然后调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IOC容器注册解析的Bean,BeanDefinitionReaderUtils的注册的源码如下

向容器注册

基于Annotation的IOC初始化

定义

类级别的注解

类内部的注解

定位扫描Bean路径

直接将注解Bean注册到容器中

通过扫描指定的包及其包下的所有类

读取Annotation元数据

IOC时序图

多线程的复习

hashmap与chm

扩容因子 0.75

数组+链表 或者数组+红黑树

什么时候转红黑树?

1.链表长度大于8的时候

2.数组长度大于64

红黑树在节点小于6时会变成链表

chm

cas、synchronize

1.7链表+数组 头插法-死循环

1.8链表+数组+红黑树 64扩容 尾插法

jdk1.8取消了重复锁,使用synchronize

reentranlock

1.aqs里面有一个volitale修饰的stat字段,标记有没有抢到锁,如果大于1,那么就有,并且代表重复次数

2.其他获取锁的线程,获取锁失败,那么就会进去aqs里面的一个等待队列

3.假如等待队列后,自旋获取锁,如果获取不到锁,进行park

4.如果获取到锁的线程执行完毕,必须手动调用unlock,unlock把state赋值为0,这是所有线程重新来抢占锁

5.对新的

AQS

1.作用,是什么

2.那些数据结构,比如state,node clh队列

3.对外暴露了一些api,reales lock trylock

4.cas操作

volatile

保证了可见,有序性

dcl需要volatile吗?为什么需要

线程池

为什么要用线程池?

管理线程,防止无休止的创建

线程池怎么用的,参数怎么配的?

int corepoolsize 核心线程数

int maximumpoolsize 最大线程数

long keepalivetime 时间

TimeUnit unit 时间单位

BlockingQueue workQueue 阻塞队列

ThreadFactory threadFactory 创建线程的工厂

RejectedWxecutionHandler handler 如果都满了,队列满了,最大线程数满了,拒绝策略

1.执行线程。已有线程数小于核心线程数,会通过worker里的thread.start开启线程

2.这个线程会执行run方法,run方法里面自选调用传进来

3.run不为空都会执行第二步,run还会被阻塞队列获取,如果阻塞队列不为空,那么线程一直在执行

4.如果阻塞队列为空,如果有线程需要回收,会根据keepAliveTime与unit来进行poll,到时间就回收,否则take

5.需要回收的条件:1.线程数大于核心线程 2.设置allowCreThreadTimeOut=true

死锁的四大条件

1.互斥

2.持有等待

3.不可抢占

4.循环等待

第三次复习

spring

管理bean

IOC:控制反正,交给spring去管理

aop:动态代理,默认,实现了接口的jdk,否则是cglib,也可以配置

IOC过程

1.扫描

2.将扫描的结果封装为beandefenition,放到beandefinitionmap

3.实例化bean,调用getBean,封装成beanwrapper

4.applybeanpostprocessorbeforeinitialization

5.invokeinitmethods调用bean初始化方法

6.applybeanpostprocessor

7销毁

springboot

传播机制

required:

required_new:

nested:

失效的场景

1.不是public,final

2.数据库不支持

3.没有调用代理类的方法,调用自己的方法

4.可配的异常类型。默认runtime,可以配置其他的

mybatis

复习第二天

1.mybatis的一二级缓存的区别

一级-sqlsession

二级-xml文件

全链路压测,接口压测

jmeter

创建型

单例,工厂,建造者,原型

结构型

装饰,桥接,代理,组合

行为型

策略,委派,责任链

饿汉

类加载的时候初始化,创建对象安全,内存浪费

饿汉式

不会浪费,怎么保证安全

双重检查锁:外面的性能,里面的安全 dcl

静态内部类:懒加载

注册式

枚举:饿汉

容器式单例:

反射,序列化,clone

反射:重写私有构造方法

序列化:重写readResoleve,返回单例

动态代理

mybatis和aop

1.类加载器,接口,invokehandler

2.生产类通过反射并且需要实现被代理类的所有接口

cglib

生产多个fastclass,

asm框架,fastclass机制调用

jdk要有接口,cglib不是接口继承父类

jdk更慢,cglib更快

jdk需要public方法

高可用

1.集群

2.降级

3.拆分服务

4.动态扩容

5.限流

6.熔断

代理模式

代理模式是对对象的功能增强。比如前置通知和后置通知。

代理模式分为两种,静态代理,动态代理;动态代理又分为jdk代理和cglib代理。

静态代理

通常被代理对象实现同一个接口,代理对象通过接口动态构造了被代理对象,并且把被代理对象的接口方法做逐一的增强。

1
2
3
4
5
6
public interface Car {

void drive();

void stop();
}
1
2
3
4
5
6
7
8
9
10
11
12
public class Benz implements Car {
@Override
public void drive() {
System.out.println("Benz car drive");
}

@Override
public void stop() {
System.out.println("Benz car stop");

}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class Baoma implements Car {
@Override
public void drive() {
System.out.println("Baoma Car drive");
}

@Override
public void stop() {
System.out.println("Baoma car stop");

}
}
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
public class Driver {
private Car car;
public Driver(Car car){
this.car = car;
}

public void drive(){
before();
car.drive();
after();
}

public void stop(){
before();
car.stop();
after();
}


public void before(){
System.out.println("**************");
}

public void after(){
System.out.println("--------------");
}
}
1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Driver driver = new Driver(new Baoma());
driver.drive();
driver.stop();
}
}

动态代理

动态代理分两种,jdk和cglib

jdk代理

jdk是jdk自带的代理,不需要任何依赖,对象需要实现同一个接口,代理对象需要实现InvocationHandler,依赖倒置原则,减少对代理类的依赖

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
public class JdkDriver implements InvocationHandler {
private Car car;


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.car,args);
after();
return result;
}


public Car getInstance(Car car){
this.car = car;
Class<?> clazz = car.getClass();
return (Car)Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}

public void before(){
System.out.println("****************");
}

public void after(){
System.out.println("-----------------");
}


}
1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
JdkDriver jdkDriver = new JdkDriver();
Car car = jdkDriver.getInstance(new Baoma());
car.drive();
car.speed();
}
}

反射代理类,实现InvocationHandler,实现ivoke方法,对类方法进行修饰;提供get方法,return jdk的proxy类的代理生成对象,需要classloader,interfaces,this;

反射原理:动态生成源代码->输出到磁盘->编译成.class文件->加载到jvm中使用

Cglib代理

不需要实现特定的接口,cglib代理类实现MethodInterceptor,提供intercept和get方法

1
2
3
4
5
public class Car {
public void buy(){
System.out.println("i want to buy a car");
}
}
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
public class Mycglibproxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}

public Object getInstance(Class<?> clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}

public void before(){
System.out.println("****************");
}

public void after(){
System.out.println("-----------------");
}

}
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
Car car = (Car) new Mycglibproxy().getInstance(Car.class);
car.buy();
}
}

区别

1.jdk代理基于反射,cglib使用的是asm框架,fastclass机制

2.jdk一定要有接口,cglib不能实现final类

redis list

指令:

flushall 删库跑路

lpush queue c

lpush queue d e

rpush queue f g

lpop queue

rpop queue

lindex queue 0 单个索引获取数据

lrange queue 0 -1 获取所有数据

特点:

数据可以重复

简单的消息队列:

rpush lpop

blpop key1 timeput

redis hash

1.1string来存储多个键值对

String 里面一个值只能对应一个对象

hash里面一个

利用key为冒号分层的效果,达到目的

set food:meat:beaf 1

set food:meat:pork 2

keys food*

String来存储多个键值对

mset批量set

第一级表名:第二级主键的值:第三级字段的名称 字段的内容

key不同导致不好

hash来存储对个键值对

hash

key–field–value

好处:

1.节省空间—–不用冒号,用聚集

2.减少命名冲突—用一个key

3.减少资源消耗—不用mget,用hget,只用一个key,不用多个key

坏处:

1.过期只能对key,不能对field

2.bit位

3.每个field 500M,有500 field,hash里面集群只能对key取模导致不能对单个key分布式

指令:

hset h1 f 6

hmset h1 a 1 b 2 c 3 d 4

hget h1 a

hmget h1 a b c d

hkeys h1

hvals h1

hgetall h1

hget exists h1

hdel h1 f

hlen h1

hincrby h1 a 10

hincrby h1 a -10

购物车:

key:用户id

field:商品id

value:商品数量

删除 hdel

全选 hgetall

商品数量 hlen

springboot自动装配

1.IOC流程

1.把所有要托管的spring管理的bean拿到,beanDefinition,并且放到beanDefinitionMap

2.bean实例化,进行属性注入

3.初始化Bean,是否实现BeanNameAware

4.是否实现了BeanPostProcessor类,调用postProcessBeforeIn

5.初始化方法

6.是否实现了BeanPostProcessor类,调用postProcessAfterIn。。。。AOP实现

入口在哪里

refresh()

扫描

1.默认会扫描当前目录及子目录下@Service @Component @Controller @Repository @Bean @Configuration

2.加注解@ComponentScans({“com.huihui.demo”,”com.huihui.boot”}),或@Import(ClassB.class)

3.importselector selectimport

4.xml

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
SpringApplication.run--->refreshContext---refresh---this.finishBeanFactoryInitialization(beanFactory)---eanFactory.preInstantiateSingletons()---getBean---doGetBean---createBean---doCreateBean


public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);

try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);//getbean的方法
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}

this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}

}
}
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
76
77
78
79
80
81
82
83
84
85
86
87
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//2.创建实例
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}

if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}

Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}

synchronized(mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable var17) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
}

mbd.postProcessed = true;
}
}

boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}

this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}

Object exposedObject = bean;

try {
//2.属性注入,DI
this.populateBean(beanName, mbd, instanceWrapper);
//3.初始化Bean,是否实现BeanNameAware
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}

throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
}

if (earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length;

for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}

if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}

try {
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
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
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
//3.初始化Bean,是否实现BeanNameAware
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
4.是否实现了BeanPostProcessor类,调用postProcessBeforeIn
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}

try {
//5.初始化方法
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}

if (mbd == null || !mbd.isSynthetic()) {
//6.是否实现了BeanPostProcessor类,调用postProcessAfterIn。。。。AOP实现
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

2.手写start组件

1
@SpringBootApplication->@EnableAutoConfiguration->@Import({AutoConfigurationImportSelector.class})->DeferredImportSelector->ImportSelector->selectImports->this.getAutoConfigurationEntry->this.getCandidateConfigurations-> SpringFactoriesLoader.loadFactoryNames->loadSpringFactories->classLoader.getResources("META-INF/spring.factories")

META-INF/spring

image-20210824013535315

1.写一个自动装配的类

PersonTest

2.META-INF/spring.factories 添加

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.start001.start.PersonTest

3.pom文件里面build删除,防止maven冲突

4.clean,package,install

5.其他项目引入当前项目生产的maven包

1
2
3
<groupId>com.example.start001</groupId>
<artifactId>start</artifactId>
<version>0.0.1-SNAPSHOT</version>