文章目录
- 1.spring的bean是线程安全的吗?
- 2.什么是Spring IOC 容器?
- 3.DI 依赖注入
- 4.如何实现一个IOC容器
- 5.Spring 的 IoC支持哪些功能?
- 6.IOC初始化过程
- 7.面向切面编程(AOP)
- 8.AOP 思想
- 9.AOP的应用场景
- 10.AOP通知类型
- 11.Spring AOP编程两种方式
- 12.使用注解@Aspect流程
- 13.AOP的相关术语
- 14.AOP编程底层实现机制
1.spring的bean是线程安全的吗?
spring的默认bean作用域是单例的,单例的bean不是线程安全的,但是开发中大部分的bean都是无状态的,不具备存储功能,比如controller、service、dao,他们不需要保证线程安全。
如果要保证线程安全,可以将bean的作用域改为prototype,比如像Model View。
另外还可以采用ThreadLocal来解决线程安全问题。ThreadLocal为每个线程保存一个副本变量,每个线程只操作自己的副本变量。
2.什么是Spring IOC 容器?
IoC(Inverse of Control:控制反转)是⼀种设计思想,就是将原本在程序中⼿动创建对象的控制权,交由Spring框架来管理。 IoC 在其他语⾔中也有应⽤,并⾮ Spring 特有。
IoC 容器是 Spring⽤来实现 IoC 的载体,将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注⼊。这样可以很⼤程度上简化应⽤的开发,把应⽤从复杂的依赖关系中解放出来。 IoC 容器就像是⼀个⼯⼚⼀样,当我们需要创建⼀个对象的时候,只需要配置好配置⽂件/注解即可,完全不⽤考虑对象是如何被创建出来的。
3.DI 依赖注入
DI:(Dependancy Injection:依赖注入)站在容器的角度,将对象创建依赖的其他对象注入到对象中。
4.如何实现一个IOC容器
① 配置文件配置包扫描路径
② 递归包扫描获取.class文件
③ 反射、确定需要交给IOC管理的类
④ 对需要注入的类进行依赖注入
- 配置文件中指定需要扫描的包路径
- 定义一些注解,分别表示访问控制层、业务服务层、数据持久层、依赖注入注解、获取配置文件注解
- 从配置文件中获取需要扫描的包路径,获取到当前路径下的文件信息及文件夹信息,我们将当前路径下所有以.class结尾的文件添加到一个Set集合中进行存储
- 遍历这个set集合,获取在类上有指定注解的类,并将其交给IOC容器,定义一个安全的Map用来存储这些对象
- 遍历这个IOC容器,获取到每一个类的实例,判断里面是有有依赖其他的类的实例,然后进行递归注入。
5.Spring 的 IoC支持哪些功能?
Spring 的 IoC 设计支持以下功能:
①依赖注入
②依赖检查
③自动装配
④支持集合
⑤指定初始化方法和销毁方法
⑥支持回调某些方法(但是需要实现 Spring 接口,略有侵入)
其中,最重要的就是依赖注入,从 XML 的配置上说,即 ref 标签。对应 Spring RuntimeBeanReference 对象。
对于 IoC 来说,最重要的就是容器。容器管理着 Bean 的生命周期,控制着 Bean 的依赖注入。
6.IOC初始化过程
IOC容器初始化是由refresh()方法来启动的,这个方法标志着IOC容器的正式启动。Spring将IOC容器启动的过程分开,并使用不同的模块来完成,如使用ResourceLoader,BeanDefinition等模块, IOC容器的启动主要包括三个过程:
Resource定位过程: Resource定位指beanDefinition的资源定位,由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一的接口。这个过程类似于容器寻找数据的过程。
BeanDefinition的载入: BeanDefinition载入过程指的是把用户定义好的Bean表示为容器内部的数据结构,这个容器的数据结构其实就是BeanDefinition。实际上BeanDefinition就是POJO对象在容器的抽象,通过BeanDefinition来定义的数据结构,像是世间万物在java中的抽象,java的对象又在容器中的抽象就是BeanDefinition。
向容器注册BeanDefinition: 这个注册过程是通过调用BeanDefinitionRegistry接口来完成的,就是把载入过程中解析得到的BeanDefinition向IOC容器进行注册。通过下面的源码可以得到,注册过程就是在IOC容器将BeanDefinition注入到一个HashMap中,IOC容器就是通过这个HashMap来持有BeanDefinition数据的。
7.面向切面编程(AOP)
AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(例如性能监视、事务管理、安全检查、缓存、日志记录等)。
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接⼝,那么Spring AOP会使⽤JDKProxy,去创建代理对象,⽽对于没有实现接⼝的对象,就⽆法使⽤ JDK Proxy 去进⾏代理了,这时候Spring AOP会使⽤基于asm框架字节流的Cglib动态代理 ,这时候Spring AOP会使⽤ Cglib ⽣成⼀个被代理对象的⼦类来作为代理。
8.AOP 思想
基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强 ! 切面:需要代理一些方法和增强代码 。
9.AOP的应用场景
场景一: 记录日志
场景二: 监控方法运行时间 (监控性能)
场景三: 权限控制(通过Around,可以在执行方法前进行权限验证)
场景四: 缓存优化 (第一次调用查询数据库,将查询结果放入内存对象, 第二次调用, 直接从内存对象返回,不需要查询数据库 )
场景五: 事务管理 (调用方法前开启事务, 调用方法后提交或者回滚、关闭事务 )
10.AOP通知类型
①前置通知 Before advice:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常
②后置通知 After returning advice:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行
③异常通知 After throwing advice:在连接点抛出异常后执行
④最终通知 After (finally) advice:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容
⑤环绕通知 Around advice:环绕通知围绕在连接点前后,能在方法调用前后自定义一些操作,还需要负责决定是继续处理 join point (调用 ProceedingJoinPoint 的 proceed 方法)还是中断执行
11.Spring AOP编程两种方式
①Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类植入增强代码。
②AsPectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持。
12.使用注解@Aspect流程
1.切面类 @Aspect: 定义切面类,加上@Aspect、@Component注解
2.切点 @Pointcut
3.Advice通知,在切入点上执行的增强处理,主要有五个注解
4.JoinPoint :方法中的参数JoinPoint为连接点对象,它可以获取当前切入的方法的参数、代理类等信息,因此可以记录一些信息,验证一些信息等;
@Aspect
@Component
//设置注解执行的顺序
@Order(1)
public class AspectTest {
/**
* 定义切点,切点为对应controller
*/
@Pointcut("execution(public * com.example.zcs.Aop.controller.*.*(..))")
public void aopPointCut(){
}
@Before("aopPointCut()")
public void testbefor(JoinPoint joinPoint) {
illegalParam(joinPoint);
System.out.println("执行方法之前执行。。。。。");
}
@After("aopPointCut()")
public void testAfter(JoinPoint joinPoint) {
//illegalParam(joinPoint);
System.out.println("执行方法之后执行。。。。。");
}
/**
*获取请求参数
* @param joinPoint
* @return
*/
private static void illegalParam(JoinPoint joinPoint) {
if(joinPoint == null){
return;
}
boolean flag = false;
try{
// 参数值
Object[] args = joinPoint.getArgs();
if (args != null) {
for (Object o : args) {
System.out.println(o);
}
}
}catch(Exception e){
}
}
}
13.AOP的相关术语
Aspect(切面) : 是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容—它的功能、在何时和何地完成其功能
joinpoint(连接点) :所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点) :所谓切入点是指我们要对哪些joinpoint进行拦截的定义.
通知定义了切面的”什么”和”何时”,切入点就定义了”何地”.
Advice(通知) :所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Target(目标对象) :代理的目标对象
weaving(织入) :是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象
Introduction(引介) :在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
14.AOP编程底层实现机制
AOP 就是要对目标进行代理对象的创建, Spring AOP是基于动态代理的,基于两种动态代理机制: JDK动态代理和CGLIB动态代理
JDK动态代理
JDK动态代理,针对目标对象的接口进行代理 ,动态生成接口的实现类 !(必须有接口)
JDK动态代理的缺点: 只能面向接口代理,不能直接对目标类进行代理 ,如果没有接口,则不能使用JDK代理。
Cglib动态代理
Cglib动态代理基于父类,Cglib的引入为了解决类的直接代理问题(生成代理子类),不需要接口也可以代理 !
什么是cglib ? CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
静态代理
静态代理相当于是多写了一个代理类,在调用的时候调用的是代理类,在代理类中的处理还是原生的处理逻辑,不过在前后添加上需要添加的代码。 缺点:需要为每一个被代理的对象都创建一个代理类。
特点:
代理角色和真实角色都需要实现同一个接口,
真实角色专注于自己的事情,
代理角色目的就是帮助真实角色完成一件事情
多线程的实现方式2:实现一个接口Runnable 使用的就是"静态代理"的思想
代理知识小结
区别:
①Jdk代理:基于接口的代理,一定是基于接口,会生成目标对象的接口类型的子对象。
②Cglib代理:基于类的代理,不需要基于接口,会生成目标对象类型的子对象。
③Spring AOP 优先对接口进行代理 (使用Jdk动态代理)
④如果目标对象没有实现任何接口,才会对类进行代理 (使用cglib动态代理)