Spring相关面试题汇总

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动态代理实现:

  1. .创建一个实现 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;
    }

    @Override
    public 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;
    }
}

  1. 使用 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 动态代理实现:

  1. 创建一个实现 MethodInterceptor 接口的代理处理器类,重写 intercept() 方法,在该方法中执行额外的逻辑,并调用被代理对象的方法。
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值