Java代理模式

静态代理

代理类自己编写,在编译器已经确认了代理类。

实现步骤

1.定义接口及其实现类

public interface SayHelloService {
    void say();
}
public class SayHelloServiceImpl implements SayHelloService {
    @Override
    public void say() {
        System.out.println("Hello Bitch");
    }
}


2.定义类代理对象

 

public class SayHelloServiceProxy implements SayHelloService {
    private SayHelloService target;

    public SayHelloServiceProxy(SayHelloService service) {
        this.target = service;
    }
    
    @Override
    public void say() {
        System.out.println("记录日志。。。。。。");
        target.say();
        System.out.println("清理数据。。。。。。");
    }

    public static void main(String[] args) {
        SayHelloServiceProxy proxy = new SayHelloServiceProxy(new SayHelloServiceImpl());
        proxy.say();
    }

}

代理类实现了目标对象的接口,对原有得接口做了扩展,其中所有的对象都是在编译期都确定好了。

缺点

需要代理对象实现目标对象的接口,假如目标对象方法很多或者需要代理多个对象,复杂度就会很高。

而动态代理不需要在编译期确定代理类,可以在运行时期动态生成,反射是动态代理的一种实现方式。

java中的动态代理

主要由以下两种方式实现:

JDK动态代理

JDK动态代理需要目标对象实现一个或多个接口,否则只能使用CGLIB实现动态代理。

实现步骤

1.定义目标类和公共接口

public interface UserService {
     void add();
}

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        // TOD Auto-generated method stub
        System.out.println("-------add--------");
    }
}


2.定义调用处理器类,可以再运行时生成代理类,并带上一些增强的功能

java.lang.reflect.Proxy : 这是生成代理类的主类,通过 Proxy 类生成的代理类都继承了 Proxy 类,即 DynamicProxyClas extends Proxy。

java.lang.reflect.InvocationHandler:调用处理类

 

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("------begin " + method.getName() + "------");
        Object result = method.invoke(target, args);
        System.out.println("------end " + method.getName() + "-------");
        return result;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
    }

    public static void main(String[] args) {
        UserService service = new UserServiceImpl();
        MyInvocationHandler handler = new MyInvocationHandler(service);
        UserService proxy = (UserService) handler.getProxy();
        proxy.add();
    }

}

原理解析

上面关键点在于Proxy.newProxyInstance() 方法创建了一个代理对象,查看他的源码,封装了创建代理类及对象的方法,如下:

 

public static Object newProxyInstance(ClassLoader loader,
                                     Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

其中的getProxyClass0(loader, intfs)实际生成了代理类,这个代理类是动态代理的关键,因为是在运行时动态生成的,我们可以通过下面的方法将生成的文件显示出来,探探究竟

public static void main(String[] args) throws IOException {

    byte[] testProxies = ProxyGenerator.generateProxyClass("Proxy0", UserServiceImpl.class.getInterfaces());
    String path = "E:/userProxies.class";
    FileOutputStream fileOutputStream = new FileOutputStream(path);
    fileOutputStream.write(testProxies);
    fileOutputStream.flush();
    fileOutputStream.close();

}

反编译生成的文件如下

 

public final class Proxy0 extends Proxy implements UserService {
    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 add() 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("org.example.proxy.inter.UserService").getMethod("add");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

分析:jdk动态生成了一个代理类,继承于Proxy,当我们调用add()方法时,将此方法当做参数传了进去,super.h.invoke(this, m3, (Object[])null)。 最终调用了InvocationHandler的invoke方法。

InvocationHandler的invoke:

public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
       InvocationTargetException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}


通过反射,得到被代理对象的方法实现。

一整套下来,达到了代理的功能。

Cglib动态代理

Cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 Java 类与实现 Java接口。

public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        //设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    //实现 MethodInterceptor接口方法
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置代理");
        //通过代理类调用父类中的方法
        Object result = methodProxy.invokeSuper(obj, args);
        System.out.println("后置代理");
        return result;
    }

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        //通过生成子类的方式创建代理类
        UserServiceImpl proxyImp = (UserServiceImpl) proxy.getProxy(UserServiceImpl.class);
        proxyImp.add();

    }
}

二者区别

使用动态代理的对象必须实现一个或多个接口

使用 cglib 代理的对象则无需实现接口,达到代理类无侵入。

SpringAOP

主要由JDK动态代理和CGLIB动态代理实现

JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类。如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。

CGLIB(Code Genration Libray),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。

posted @ 2021-08-27 16:29  杰哥!  阅读(36)  评论(0编辑  收藏  举报
/*scroll to top 火箭按钮*/