框架复习总结


别问 问就是为了面试豁出了老命

IOC控制翻转和DI

控制反转-依赖注入.jpg

控制反转和依赖注入其实说的是一个东西,为了解耦,将创建对象的任务交付给Spring的容器来创建,而不是用new来创建。

Bean

bean的作用域

  • Singleton : 单例,在IOC容器中只存在一个,会在容器内缓存
  • prototype : 多例,利用getBean()频繁创建,同时也会频繁的销毁
  • Web
    • request : 每一次 HTTP 请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
    • session : session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效
    • global session

Bean的生命周期

bean生命周期.jpg
bean的生命周期分为四个阶段

  1. 实例化 (createBeanInstance)
    • resolveBeforeInstantiation
      • InstantiationAwareBeanPostProcessor
  2. 属性赋值(populateBean)
  3. 初始化(initializeBean)
    • 后置修正
      • 检查是否实现了Aware类的接口
      • 然后判断(invokeAware) BeanNameAware,BeanFactoryAware,ApplicationContextAware接口
      • BeanPostProcessor
        • postProcessBeforeInitialzation
        • postConstruct
        • postProcessAfterInitialzation
    • InitializingBean 可以在正式完成前增加自定义逻辑
    • 为了减小侵入程度,bean提供了配置init-method,通过设置函数名,然后在InitializingBean中完成指定函数逻辑
  4. 销毁

静态代理和动态代理

静态代理

A方法需要C方法来修饰,那么需要创建B实现A+C,之后调用B来实现
静态代理.jpg

SpringMVC

springmvc执行流程.jpg

动态代理

  • Proxy + InvocationHandler
    被代理对象接口
    1
    2
    3
    4
    public interface UserService {
    public void addUser(User user);
    public User getUser(int id);
    }

被代理类接口实现

1
2
3
4
5
6
7
8
9
10
11
public class UserServiceImpl implements UserService {
public void addUser(User user) {
System.out.println("add user into database.");
}
public User getUser(int id) {
User user = new User();
user.setId(id);
System.out.println("getUser from database.");
return user;
}
}

代理(中间)类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ProxyUtil implements InvocationHandler {
private Object target; // 被代理的对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do sth before....");
Object result = method.invoke(target, args);
System.out.println("do sth after....");

return result;
}
ProxyUtil(Object target){
this.target = target;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
}

测试实现

1
2
3
4
5
6
7
8
9
10
11
public class ProxyTest {
public static void main(String[] args){
Object proxyedObject = new UserServiceImpl(); // 被代理的对象
ProxyUtil proxyUtils = new ProxyUtil(proxyedObject);
// 生成代理对象,对被代理对象的这些接口进行代理:UserServiceImpl.class.getInterfaces()
UserService proxyObject = (UserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
UserServiceImpl.class.getInterfaces(), proxyUtils);
proxyObject.getUser(1);
proxyObject.addUser(new User());
}
}

核心则在于被代理的对象必须要有含有自己方法的接口,才可以使用Proxy+InvocationHandler,同时,代理类中主要是通过调用被重写的invoke()方法。

  • CGlib + MethodInterceptor

Cglib代理的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CGProxy implements MethodInterceptor{
private Object target; // 被代理对象
public CGProxy(Object target){
this.target = target;
}
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable {
System.out.println("do sth before....");
Object result = proxy.invokeSuper(arg0, arg2);
System.out.println("do sth after....");
return result;
}
public Object getProxyObject() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass()); // 设置父类
// 设置回调
enhancer.setCallback(this); // 在调用父类方法时,回调 this.intercept()
// 创建代理对象
return enhancer.create();
}
}

测试结果

1
2
3
4
5
6
7
8
9
public class CGProxyTest {
public static void main(String[] args){
Object proxyedObject = new UserServiceImpl(); // 被代理的对象
CGProxy cgProxy = new CGProxy(proxyedObject);
UserService proxyObject = (UserService) cgProxy.getProxyObject();
proxyObject.getUser(1);
proxyObject.addUser(new User());
}
}

与Proxy+InvocationHandler不同,Cglib是利用enhancer.create创造了一个代理对象,而这个大力对象的父类就是被代理类,利用enhancer.setSuperclass()指定,同时利用enhancer.setCallback()回调被重写的intercept,完成对方法的包裹

Spring事务

事务是一组操作,要么全部成功,要么全部失败

  • 事务特性 ACID
    • 原子性
    • 一致性
    • 隔离性
    • 持久性

事务分类

  • 声明式事务(推荐,@Transactional)
  • 编程式事务 (TransactionManager)

    事务隔离级别(和mysql一直)

  • 未提交读
  • 提交读
  • 可重复读
  • 串行化

    事务的传播行为

  • PROPAGATION_REQUIRED(默认开启)
    • 如果外部没有开启事务,则内部自己开启子事务
    • 如果外部开启事务,则内部和外部属于同一个事务
  • PROPAGATION_REQUIRES_NEW
    • 不论外部有没有开启事务,则内部自己都开启子事务
    • 如果当前已存在事务,则直接挂起
  • PROPAGATION_NESTED
    • 外部未开启事务,和require一样
    • 外部开启事务,则内部方法变成子事务,可以一起会滚,内部的子事务可以独立回滚
  • PROPAGATION_MANDATORY
    • 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

JDBC

JDBC.jpg

一般来说多使用PreparedStatement在执行之前会进行预编译
效率高于Statement,且能够有效防止SQL注入
PreparedStatement支持?占位符而不是直接拼接,提高可读性

Mybatis

  • Mybatis工作流程
    Mybatis.jpg
  • Myabtis多级缓存
    Mybatis缓存.jpg

当一级缓存和耳机缓存同时打开的时候,先到二级缓存再到一级缓存

Spring Boot

自动装配原理

自动装配原理主要集中在@SpringbootApplication注解中

  • @EnableAutoConfiguration
    启用 SpringBoot 的自动配置机制
  • @Configuration
    启用 SpringBoot 的自动配置机制
  • @ComponentScan
    扫描被@Component (@Service,@Controller)注解的bean,注解默认会扫描该类所在的包下所有的类

Springboot自动装配原理.jpg

  1. 进入@SpringbootApplication
  2. 利用@EnableAutoConfiguration注解开启自动装配
  3. 在EnableAutoConfiguration接口的实现中利用@Import主节导入了 EnableAutoConfigurationImportSelector.class
  4. EnableAutoConfigurationImportSelector 的父类AutoConfigurationImportSelector利用List集合存储了配置信息
    • 在AutoConfigurationImportSelector中selectImports()方法详解
      selectImport.jpg
    • 第一步会优先的判断是不是开启了自动装配,如果没有开启的话则返回空数组
    • 之后会找到一个spring-autoconfigure-metadata.properties的文件去预加载一些配置文件
      • tips:(这个文件是,如果要加载一个类,那么要加载这个类需要的其它的类或是配置)
    • 之后利用 this.getCandidateConfigurations 在List中存储相关的配置文件
    • 之后用Set exclusions = this.getExclusions去除list中的配置
      • tips:这个地方是@EnableAutoConfiguration上一些exclude、excludeName属性
    • 最后返回一个String[]的数组
  5. 其中getcandidateConfiguration中是利用SpringFactoriesloader获取了配置对象

Springboot执行流程

  1. StopWatch stopWatch = new StopWatch();用来记录时间
  2. SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting();
    • 在start方法中使用ApplicationStartingEvent(this.application, this.args));
    • 监听所有的启动事件
  3. ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
    • 创建运行时环境 StandardServletEnvironment
    • 配置配置PropertySources
    • 配置Profiles
  4. configureIgnoreBeanInfo(environment); // 获取系统属性
  5. context = createApplicationContext(); // 创建相应的环境
    • 创建ApplicationContext
  6. exceptionReporters = getSpringFactoriesInstances();
    • SpringBoot启动失败后异常处理相关的组件
  7. refreshContext(context); // 初始化容器
  8. 发送发送ApplicationReadyEvent事件