java面试:Spring AOP 使用的动态代理,JDK动态代理和CGLIB动态代理

JDK动态代理:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxy implements InvocationHandler {

    private Object target;//目标类

    public JdkProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 这里可以做增强,处理自己需求
        System.out.println("before-新增的处理,干点啥呢???");
        //对原始操作进行调用(反射)
        Object result = method.invoke(target, args);
        System.out.println("after-新增的处理,干完了!!!");
        return result;
    }

    /**
     * 创建代理类方法
     * @return
     */
    public Object createProxyObject(){
        //目标类类加载器
        ClassLoader loader=target.getClass().getClassLoader();
        //目标类所实现的所有接口
        Class[] interfaces=target.getClass().getInterfaces();
        Object object = Proxy.newProxyInstance(loader, interfaces, this);
        return object;
    }
}

CGLIB动态代理:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    
    public Object createProxyObject(Class clsss){
        //1.Enhancer在内存中造出一个没有名称的动态类
        Enhancer enhancer=new Enhancer();
        //2.通过继承,先获取目标类对应的功能
        enhancer.setSuperclass(clsss);
        //3.增强,见intercept()
        enhancer.setCallback(this);

        return enhancer.create();
    }

    /**
     *  拦截增强方法
     * @param o 代理对象
     * @param method 被拦截的方法
     * @param objects 参数
     * @param methodProxy cglib方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before-intercept干点啥");
        Object result = methodProxy.invokeSuper(o,objects);
        System.out.println("after-intercept干完了");
        return result;
    }
}

测试类:

public static void main(String[] args) {
        
        MyInterfaceImpl myInterface = new MyInterfaceImpl();
        JdkProxy jdkProxy = new JdkProxy(myInterface);
        MyInterface myIn = (MyInterface) jdkProxy.createProxyObject();
        System.out.println(myIn.doTest());

        System.out.println("=====我是一个分割线==========");

        CglibProxy cglibProxy = new CglibProxy();
        MyInterface myInCglb = (MyInterface)cglibProxy.createProxyObject(MyInterfaceImpl.class);
        System.out.println(myInCglb.doTest());
    }

测试发现,代理类完成了被代理类的功能:

java面试:Spring AOP 使用的动态代理,JDK动态代理和CGLIB动态代理_第1张图片

代理:

个人理解,就是一个代理类,拥有被代理类的功能,同时代理类可以添加一些自己的骚操作,然后向外提供服务。官方话语:Spring AOP 使用的动态代理,所谓的动态代理就是说 AOP 框架不会去修改字节码,而是在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

总结:

  • 1.Spring默认使用jdk动态代理,如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。
  • 2.JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类。
  • 3.CGLIB 是一个代码生成的类库,可以在运行时动态的生成某个类的子类,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。
  • 4.jdk创建对象的速度远大于cglib,cglib执行速度略大于jdk。因为cglib创建对象时需要操作字节码,生成的类会在Java的永久代中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。(解释1)

关注公众号,回复 面试 获取初级中级高级面试题。

你可能感兴趣的:(java面试,java,proxy,aop,spring,jdk)