Spring 代理与Aop

静态代理与动态代理:

静态代理的作用:为其他对象提供一种代理以控制对这个对象的访问。另一种情况是,有时一个客户不想或者不能直接引用另外一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

静态代理举例:

package com.zhangsan.spring.proxy;

public interface Target {
public void myRequest();
}

 

package com.zhangsan.spring.proxy;

public class RealTarget implements Target {
    @Override
    public void myRequest() {
        System.out.println("from my real Target");
    }
}

 

复制代码
package com.zhangsan.spring.proxy;

public class ProxyTarget implements Target{
    private RealTarget realTarget;
    @Override
    public void myRequest() {
        this.beforeRequest();
        if(realTarget == null){
            realTarget = new RealTarget();
        }
        realTarget.myRequest();
        this.afterRequest();
    }

    private void beforeRequest(){
        System.out.println("before request");
    }

    private void afterRequest(){
        System.out.println("after request");
    }
}
复制代码

 

package com.zhangsan.spring.proxy;

public class ProxyClient {
    public static void main(String[] args) {
        Target target = new ProxyTarget();
        target.myRequest();
    }
}

测试结果:

before request
from my real Target
after request

 

针对于上述的静态代理在实际使用中,容易存在一些不足,这里归纳如下。

  • 如果让一个代理类代理多个被代理类,那么会导致代理类变得过大;(一代多,代理类太大)
  • 如果每个被代理类都对应一个代理类,那么会导致代理类变得过多;(一代一,代理类太多)
  • 由于被代理类和代理类都需要实现相同的接口,当接口定义的方法增加或减少时,被代理类和代理类需要一起修改,不易于代码维护。

上述静态代理存在的问题,可以由动态代理来解决,即在程序运行期间,才决定代理类的生成。

动态代理是这样一种class: 在运行时生成class,在生成它时我们必须提供一组interface给它,然后该class就会声明它实现了这些interface。因此我们可以将该class的实例当作这些interface中的任何一个来用。当然,这个动态代理其实就是一个proxy,它不会替我们做实质性的工作,在生成它的实例时我们必须提供一个handler,由它接管实际的工作。

JDK动态代理:Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类(接口):

(1)Interface InvocationHandler:该接口定义了一个方法public object invoke(Object obj, Method method, Object[] args) 在实际使用时第一个object一般是指代理类,method是被代理的方法,args为该方法的参数数组,这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包括以下内容:

static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) , 通过该方法返回代理类的一个实例,返回后的代理实例可以当作代理类来使用。

JDK动态代理创建步骤:

  1. 创建一个接口Invocation Handler的类,它必须实现invoke方法

  2. 创建被代理的类及接口

  3. 通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)创建一个代理

  4. 通过代理调用方法

动态代理实现样例:

package com.zhangsan.spring.dynamicProxy;

public interface Subject {
    void myNewRequest();
}

 

package com.zhangsan.spring.dynamicProxy;

public class RealSubject implements Subject{
    @Override
    public void myNewRequest() {
        System.out.println("new request from realSubject");
    }
}

 

复制代码
package com.zhangsan.spring.dynamicProxy;

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

public class DynamicSubjectInvocationHandler implements InvocationHandler {
    private Object sub;
    public DynamicSubjectInvocationHandler(Object sub){
        this.sub = sub;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     //功能增强 System.out.println(
"proxy: "+ proxy.getClass()); System.out.println("before:"+method); method.invoke(sub,args); System.out.println("after:"+method); return null; } }
复制代码

 

复制代码
package com.zhangsan.spring.dynamicProxy;

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

public class DynamicProxyClient {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        InvocationHandler invocationHandler = new DynamicSubjectInvocationHandler(realSubject);
        Class<?> classType = invocationHandler.getClass();
        Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(),
                realSubject.getClass().getInterfaces(),invocationHandler);
        subject.myNewRequest();
    }
}

@Test
public void callMyNewRequestByReflect() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method myNewRequest = Class.forName(Subject.class.getName()).getMethod("myNewRequest");
RealSubject realSubject = new RealSubject();
myNewRequest.invoke(realSubject);
}
 
复制代码

main函数运行的测试结果:

proxy: class com.sun.proxy.$Proxy0
before:public abstract void com.gzz.spring.dynamicProxy.Subject.myNewRequest()
new request from realSubject
after:public abstract void com.gzz.spring.dynamicProxy.Subject.myNewRequest()

callMyNewRequestByReflect()函数运行的测试结果:

new request from realSubject

将进行反编译生成的代理类对象拷贝出来如下:

复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.gzz.spring.dynamicProxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void myNewRequest() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.gzz.spring.dynamicProxy.Subject").getMethod("myNewRequest");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
复制代码

通过callMyNewRequestByReflect()函数,利用ava反射机制能在运行时获得类的属性和方法的特性,我们可以模拟invocationHandler的method方法的调用。

而通过反编译生成的代理类对象$Proxy0,我们可以看出代理类在调用其代理方法时,实际是调用的invocationHandler的invoke方法, 且传入的参数是代理对象$Proxy0 和通过反射获得的method m2, 而invocationHandler的invoke方法在执行时,通过反射机制实际执行的是真实对象中m2对应的接口。

 

posted @   小兵要进步  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

侧边栏
点击右上角即可分享
微信分享提示