AOP的底层实现---动态代理

    技术2023-08-22  94

    动态代理分为两种:JDK动态代理与CGLIB动态代理.

    什么是代理(proxy)?什么是动态代理?

    代理: 代理拥有被代理的属性与方法,可以代表被代理类完成被代理类不想做,不得不做,或者想做却不能做的任务。比如说,一个方法无法通过自身来调用,可以通过代理来调用。

    动态代理:代理者是全能的,能够代理任何的对象,所以在代理前都不清楚要代理什么内容,只有在创建号代理之后才能明确。

    一、通过JDK实现切面逻辑的动态代理

    接口代码

    package JDKproxy; public interface Userinterface { void addUser(); }

    接口实现类:

    package JDKproxy; public class UserinterfaceImpl implements Userinterface { public void addUser() { System.out.println("添加用户"); } }

    前置切入的方法与后置切入的方法

    public static void check(){ System.out.println("检查用户属性"); } public static void save(){ System.out.println("用户属性归档"); }

    动态代理的实现类

    package JDKproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //JDK提供的调用方法的一个接口,代理机制下调用方法的接口,必须实现invoke()方法 public class JDKProxy implements InvocationHandler { //被代理的对象 public Object targetobj; //创建被代理对象 public Object createProxy(Object targetobj ){ this.targetobj=targetobj; //创建一个代理对象的方法,第一个参数获得类加载器,帮助动态或者静态加载类,每一个类都有一个类加载器,第二个参数获得对象所在的类所实现的任何一个接口。 //第三个参数是是invocationhandle接口本身 return Proxy.newProxyInstance(targetobj.getClass().getClassLoader(),targetobj.getClass().getInterfaces(),this); } //传入一个被代理对象,返回一个代理的对象 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //真正调用方法的地方 //切入前,前置切入 Aspect.check(); Object ret= method.invoke(targetobj,args); //切入后,后置切入 Aspect.save(); return ret; } }

    主方法:

    package JDKproxy; public class RunTest { public static void main(String[] args) { Userinterface userinterface=new UserinterfaceImpl(); // userinterface.addUser(); //创建userinterface的动态代理 Userinterface proxy=(Userinterface) new JDKProxy().createProxy(userinterface); //通过动态代理调用被代理对象的方法 proxy.addUser(); } }

    首先,通过createProxy()的newInstance方法创建被代理对象的动态代理对象,在创建好代理对象之后,代理对象调用方法时,会自动调用invoke()方法,在invoke方法里实现拓展方法。并通过method反射机制实现之前的方法。

    二、CGLIB实现动态代理

    CGLIb是通过字节码技术,在运行时动态创建被代理者的子类。

    第一步 添加cglib依赖

    <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.10</version> </dependency>

    第二步 创建CGLIB代理实现类

    package CGLIBProxy; import JDKproxy.Aspect; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CGlibproxy implements MethodInterceptor { //在字节码阶段,调用代码的时候会调用的方法 public Object createProxy(Object targetobj){ //通过Enhance类来创建CGlib的动态代理对象 Enhancer enhancer=new Enhancer(); //设置它的类为被代理对象所在的类 enhancer.setSuperclass(targetobj.getClass()); //回调 enhancer.setCallback(this); //创建代理对象 return enhancer.create(); } public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { Aspect.check(); //切面逻辑在这里触发,调用父类的方法 methodProxy.invokeSuper(proxy,objects); Aspect.save(); return null; } }

    实现MethodInterceptor接口,使用createproxy方法创建产生代理对象,在代理对象调用被代理对象的方法时会自动调用intercept方法,此方法也就是切面逻辑出发的地方。

    package CGLIBProxy; public class Runtest { public static void main(String[] args) { User user=new User(); user.addUser(); //createProxy的参数时被代理的对象,此方法用于产生代理 User Proxy=(User) new CGlibproxy().createProxy(user); Proxy.addUser(); } }

    三、二者区别

    1、JDK动态代理是在代码创建阶段生成的,优点:创建对象很快,但整体运行逻辑会很慢。 2、CGLIB在代理运行阶段创捷一个子类继承被代理类。

    Processed: 0.010, SQL: 11