通过反射学习Spring AOP的CGLIB动态代理

反射:有了反射Java才被可以称之为动态语言,反射允许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操作任意对象的内部属性及方法。

某种意义上来讲,反射其实是破坏了Java的安全性。

//Test.java
public class Test {
    private String name="不可见的";
}

//Fps.java

public class Fps {
    public static void main(String[] args) throws Exception{
        Test test = new Test();
        //获取Test的Class对象,反向的调用test
        Class testClass = test.getClass(); //得到 test 对象的字节码 对象
        Field field = testClass.getDeclaredField("name");
        field.setAccessible(true);
        System.out.println("输出结果:"+field.get(test));
    }
}

执行结果:“输出结果:不可见的”

我们通过反射的方法得到了Test私有的属性的值,当然它不仅仅能做到这些,它的能量超乎想象!

Class是一个很特殊的类,它是一个运行期的信息类,通过它,你可以得到 类名,包名,构造方法等等,通过Class可以得到类的全部信息,包括类的对象。

重点不是AOP的动态代理吗,跑题了?
言归正传,大部分和Java相关的框架都是使用的反射,可以说反射就是框架的灵魂,一点也毫不夸张。

AOP的动态代理实现方案有两种,JDK的动态代理和CGLIB动态代理,区别在于JDK自带的动态代理,必须要有接口,而CGLIB动态代理有没有接口都可以。

CGLIB动态代理

先看一个简单的类,我们来一步一步的实现动态代理

//Test.java
public class Test {
    public void test() {
        System.out.println("执行test");
    }
}

和得到私有对象一样,得到Test方法然后执行。

//FPS.java
public class Fps {
    public static void main(String[] args) throws Exception{
        Test test = new Test();
        //获取Test的Class对象,反向的调用test
        Class testClass = test.getClass(); //得到 test 对象的字节码 对象
        Method m = testClass.getMethod("test");
        m.invoke(test);
     }
}

执行结果:“执行test”

然后我们创建TestA

//TestA .java
public class TestA implements MethodInterceptor {
    /**
     * 代理方法, 每次调用目标方法时都会进到这里
     */
    @Override
    public Object intercept(Object obj, Method method,
     Object[] args, MethodProxy methodProxy) throws Throwable {
       
        System.out.println("Before TestA");
        return methodProxy.invokeSuper(obj, args);
    }
}

模拟CGLIB的实现方案

//FPS.java
public class Fps {
    public static void main(String[] args) throws Exception{
        Test test = new Test();
        //获取Test的Class对象,反向的调用test
        Class testClass = test.getClass(); //得到 test 对象的字节码 对象
        // Method m = testClass.getMethod("test");
        //m.invoke(test);
        //创建代理对象
        Test test1 = (Test) Enhancer.create(testClass,new TestA());
        test1.test();
     }
}

执行结果:“Before TestA 执行test”

Enhancer 是CGLib中的一个字节码增强器

Test test1 = (Test) Enhancer.create(testClass,new TestA());

等同于

 Enhancer  test1= new Enhancer(); //生成代理对象
 test1 setSuperclass(testClass);  //设置testClass为代理对象的父类
 test1 setCallback(new TestA());  //设置回调对象为TestA
 Test test2= (Test)test1.create();//生成一个代理类对象

CGLIB产生代理对象的原理:实际上是将一个新的类作为它的子类,我们在使用它时,就相当我们把一个类给了它,它返回给我们这个类的子类

我们将TestA的功能扩充下,就可以实现前置拦截,后置拦截,异常拦截,等等

//TestA.java
public class TestA implements MethodInterceptor {
    /**
     * 代理方法, 每次调用目标方法时都会进到这里
     */
    @Override
    public Object intercept(Object obj, Method method,
     Object[] args, MethodProxy methodProxy) throws Throwable {
       	Object obj1= null;
       		begin();
        	if (isIntercept(method, args)) {
                before();
                obj1= methodProxy.invokeSuper(obj, args);
                after();
            } else {
                obj1= methodProxy.invokeSuper(obj,args);
            }
            end();
        return obj1;
    }
    
	//开始
    public void begin() {}
    //切面
    public boolean isIntercept(Method method, Object[] args) throws Throwable {
    return true;}
    //前置
    public void before() throws Throwable {}
    //后置
    public void after() throws Throwable {}
    //结束
    public void end() {}
}
//spring 还有个异常,有兴趣的朋友可以取了解下

到这里基本就结束了,可以看到,只要在对应方法中加入想要的方案就就可以进行动态插入了,但是这里有个问题就是不可能所有的逻辑都写在TestA中啊,朋友们想到了什么?没错,继承啊,当我们需要一个新的业务时,继承TestA就行了

public class TestB  extends TestA{
    //切面
    public boolean isIntercept(Method method, Object[] args) throws Throwable {
        return method.getName().equals("test");
    }
    //前置
    public void before() throws Throwable {
        System.out.println("还没开始");
    }
    //后置
    public void after() throws Throwable {
        System.out.println("已经结束了");
    }
}

以上就是Spring AOP的实现方案,只不过Spring定义一个工厂类来创建代理,对于我们而言有无皆可,相信朋友们肯定已经了解了CGLIB了,了解了CGLIB,回头看下JDK动态代理,你会发现原理差不多,除了适用范围不同外。

代理代理类继承代理类实现方法原理适用范围
CGLIBMethodInterceptorintercept生成一个类的子类,然后在在其子类上加入前置后置等等方案ALL
JDK动态代理InvocationHandlerinvoke生成接口的实现类,然后再实现类上加入前置后置等等方案接口
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值