Spring框架八股
IoC
原理
https://www.jianshu.com/p/ad05cfe7868e
IoC控制反转,是一种设计思想,将以往通过手动创建对象的控制权交由Spring管理,降低对象之间的耦合性。其控制反转,指的是控制对象创建的权力,然后将控制权反转交给外部环境管理。
所有的Bean在项目启动时生成,加载到Spring容器中统一管理,我们需要使用的时候再去容器中取Bean。而不是单独的去new一个相关类来进行调用。
IoC只是一种思想,而依赖注入DI是具体实现。
实现
底层xml配置文件,编写对应属性kv,如k - 类名,v - 类的全路径。
创建一个工厂类解析xml,获取对应类的全路径,并通过反射创建该类对象。
最后从工厂中调用创建好的对象即可。
现在我们开发都是使用注解注入Bean替代xml配置。
AOP
简述
AOP面向切面编程,能将与业务无关,却被业务模块共同调用的服务进行封装(如工具类等),然后进行统一调用,降低模块之间的耦合性,利于拓展和维护。
AOP基于代理模式实现,其分为静态代理和动态代理。
- AspectJ AOP 静态代理
- Spring AOP 动态代理(JDK、CGLIB)
Spring AOP
我们要代理的对象实现了接口时,Spring AOP使用 JDK动态代理 去创建代理对象;对于没有实现接口的对象,Spring AOP使用 CGLIB动态代理 去生成一个被代理对象的子类来作为代理(继承)。
Spring默认使用的 JDK动态代理。
JDK动态代理原理(反射)
编写一个代理类:实现 InvocationHandler 接口,将原类方法通过重写 invoke() 进行代理实现,invoke()中可以自行添加内容。
1
2
3
4/**
* proxy 代理类,method 代理方法,args[] 方法参数
*/
invoke(Object proxy, Method method, Object[] args)编写工厂类生成代理对象:Proxy.newProxyinstance,获取全部接口,将接口方法通过代理进行增强,最后返回代理对象。
1
2// loader 类加载器,interfaces[] 全部接口,handler 自行实现的代理类
newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler)
JDK动态代理基于反射实现,工厂类实现了原类的全部接口,并对接口的所有方法进行了代理。通过代理对象执行原类方法时,代理对象会通过反射回调我们实现的代理类的 invoke(),也就是代理方法被调用。
特点:
- JDK动态代理通过反射实现,是JDK原生的。
- JDK动态代理,被代理类必须实现接口,且只能代理接口中定义的方法,如果代理类自行编写了不存在于接口的方法,那么JDK动态代理不会实现该方法。
CGLIB动态代理原理(字节码)
底层对代理类的字节码进行操作,生成该类的一个子类,并重写父类的所有可重写方法,也就是生成自定义的代理方法(自行生成子类继承父类,对子类进行代理)。然后通过字节码操作生成代理类。
特点:
- CGLIB代理的类无需实现接口,CGLIB会自行生成子类继承原类来代理。
- 由于final修饰的类无法被继承,所以CGLIB不能代理final类。
- CGLIB代理是生成子类,对原类方法进行重写,生成相应的代理方法,如果原方法由final 或 private修饰,我们无法重写方法,所以final和private修饰的方法不能被代理。
AspectJ AOP(静态代理)
Spring AOP是运行时增强,基于代理;Aspect AOP是编译时增强,基于字节码操作。
Bean
Bean就是IoC容器管理的对象。
Bean生命周期
Bean实例化,根据实现的接口,调用对应方法完成相应操作,如在BeanFactory中获取容器实例,加载Bean所在应用的上下文引用等。
Bean初始化完成后,可以被应用程序使用,它们一直驻留在应用上下文中,,直到应用上下文被销毁。
可以执行destroy()销毁Bean。
Bean作用域
- singleton:单例,唯一Bean实例
- prototype:多实例,每次请求都创建一个Bean
- request:每次Http请求都创建一个Bean,只在当前Http request内有效
- session:每次新session的Http请求会创建一个Bean,只有当前HttpSession内有效
- global - session:全局Session,一个Bean对应一个实例
Bean线程安全问题
单例可能会设计多线程修改变量。改变Bean作用域,选择多实例,每个请求都创建一个Bean。或使用ThreadLcoal存储变量。
Spring事务
@Transaction
Spring事务对应数据库事务,也是ACID,隔离级别也一致,多了一种默认的级别default,和数据库的级别同步。
1 |
注意Spring事务默认是运行时异常才回滚,我们可以设置为任何异常都回滚。
AOP
@Transaction也是通过AOP动态代理实现的。由于是动态代理,只有注解方法被类以外方法调用时事务才生效,如果本类方法直接调用则事务无法生效。
MyBatis的#{}、${}
- #{}:sql参数占位符,mybatis会认定传入参数是一个字符串,将其字段加上’ ‘,替换我们需要的参数。经过预编译,防止sql注入。
- ${}:变量占位符,直接传值,不做处理。
@SpringBootApplication
1 |
主启动类注解由三个注解组成:
@SpringBootConfiguration:代表主启动注解是一个配置类
@ComponentScan:默认扫描主启动类包下的全部注入组件(@Component等),可自定义不扫描的Bean。
@EnableAutoConfiguration:开启自动装配
在META-INF/spring.factories下配置自动加载类,一般都是 **AutoConfiguration 结尾的类,通过@Conditional注解按需加载实现自动装配。