文章目录
- Spring
- 什么是AOP? 你怎么应用的?底层原理?
- 什么是IOC?IOC的工作流程?
- Spring支持哪些注入方式?
- Spring事务原理,如何开启事务,事务的传播机制有哪些?
- Spring多线程事务能不能保证一致性?
- Spring事务失效的原因?
- 为什么有些公司禁止使用@Transactional声明式事务?
- Bean的生命周期及常用自定义方法
- Bean作用域
- 有两个相同id的Bean会报错吗?
- 循环依赖问题以及解决办法,什么是三级缓存?
- Spring用到了哪些设计模式?
- SpingMVC
- Spring MVC是什么,核心是什么,它的执行流程?
- Spring MVC的控制器(bean)是不是单例模式(是不是线程安全)?存在什么问题?如何解决?
- Springboot
- 起步依赖、自动配置原理;yml等配置文件的配置优先级
- 常见注解有哪些? @Autowird 与 @Resource区别;@Component和@Bean区别;@Conditional作用
- Spring 的常见注解
- SpringMVC的常见注解
- Springboot的常见注解
- @Autowird 与 @Resource的区别
- @Component和@Bean的区别
- @Conditional注解作用?
- 其他
- 过滤器与拦截器的区别
- 如何解决跨域问题?
- 如何让你的Bean在其他Bean加载之前加载?
- 如何统计一个Bean中方法的调用次数?
- 如何根据配置动态生成Bean?
Spring
什么是AOP? 你怎么应用的?底层原理?
什么是AOP?
AOP是面向切面编程,在spring中用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合,一般比如可以做为公共日志保存,事务处理等。
你怎么应用的?
我们当时在后台系统中,就是使用aop来记录了系统的操作日志。主要思路是这样的,使用aop中的环绕通知+切点表达式,这个表达式就是要找到要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,比如类信息、方法信息、注解、请求方式等,获取到这些参数以后,保存到数
据库。
AOP的底层原理?
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDKProxy,去创
建代理对象, 而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用基于
asm框架字节流的Cglib动态代理 ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理。
AOP当中涉及到的一些核心概念:
- 连接点:JoinPoint,可以被AOP控制的方法
- 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
- 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
切面:Aspect,描述通知与切入点的对应关系(通知+切入点就形成了一个切面)
目标对象:Target,通知所应用的对象Spring中AOP的通知类型:
- @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
- @Before:前置通知,此注解标注的通知方法在目标方法前被执行
- @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行
JDK动态代理只提供接口的代理,不支持类的代理。
- JDK会在运行时为目标类生成一个动态代理类$proxy*.class .
- 该代理类是实现了目标类接口,并且代理类会实现接口所有的方法增强代码
- 调用时先去调用处理类进行增强,再通过反射的方式进行调用目标方法,从而实现AOP。
如果代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
- CGLIB的底层是通过ASM(一种用于直接生成或修改字节码的框架,全称为 “Abstract Syntax Notation One”)在运行时动态的生成目标类的一个子类。(还有其他相关类)会生成多个。
- 并且会重写父类所有的方法增强代码,
- 调用时先通过代理类进行增强,再直接调用父类对应的方法进行调用目标方法。从而实现AOP。
- CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
- CGLIB除了生成目标子类代理类,还有一个FastClass(路由类),可以(但不是必须))让本类方法调用进行增强,而不会像jdk代理那样本类方法调用增强会失效。
JDK动态代理生成类速度快,调用慢,CGLIB生成类速度慢,但后续调用快。就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。
JDK动态代理实现:
- .创建一个实现 InvocationHandler 接口的代理处理器类,重写 invoke() 方法,在该方法中执行额外的逻辑,并调用被代理对象的方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 执行额外的逻辑System.out.println("Before method " + method.getName());// 调用被代理对象的方法Object result = method.invoke(target, args);// 执行额外的逻辑System.out.println("After method " + method.getName());return result;}
}
- 使用 Proxy.newProxyInstance() 方法创建代理对象。
import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {RealSubject realSubject = new RealSubject();InvocationHandler handler = new MyInvocationHandler(realSubject);Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(),RealSubject.class.getInterfaces(),handler);proxySubject.request();}
}
CGLIB 动态代理实现:
- 创建一个实现 MethodInterceptor 接口的代理处理器类,重写 intercept() 方法,在该方法中执行额外的逻辑,并调用被代理对象的方法。
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang