关于代理机制

java本身提供了一种代理机制,何为代理?通俗来讲就是把 一个类 用 另外一个类 替代了。

初始代理机制

让我们通过一个例子来初步了解代理机制吧

首先提供一个接口 ISomeClass.java

public interface ISomeClass
{
    String doDealString(String mess);

    int doDealInt(int num);
}

提供一个 SomeClass.java 实现上面的接口

public class SomeClass implements ISomeClass
{

    public SomeClass()
    {

    }

    @Override
    public String doDealString(String mess)
    {
        return "[" + mess + "]";
    }

    @Override
    public int doDealInt(int num)
    {
        return num + 1;
    }

}

给出一个 DirectJDKProxy.java 来品味一下 代理机制

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

public class DirectJDKProxy
{
    public static Object getProxy(Object object)
    {
        Class<?> klass=object.getClass();
        // 获取类加载器
        ClassLoader classLoader=klass.getClassLoader();
        // 获取类所有的接口
        Class<?>[] interfaces=klass.getInterfaces();
        return Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler()
        {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
            {
                System.out.println("要执行[" + method.getName() + "]方法了");
                // 以下三行证明DoDealString方法 被 invoke方法干预了
                String arg0=(String) args[0];
                arg0="(" + arg0 + ")";
                args[0]=arg0;

                Object result=method.invoke(object, args);
                System.out.println("执行完[" + method.getName() + "]方法了");
                return result;
            }
        });
    }

    public static void main(String[] args)
    {
        SomeClass someClass=new SomeClass();
        // 获取someClass(接口类型的)的代理对象
        ISomeClass someClassProxy=(ISomeClass) getProxy(someClass);
        // 这里的DoDealString方法 被 invoke方法干预了
        String str=someClassProxy.doDealString("这是原始参数");
        System.out.println("执行结果:" + str);
    }

}

*invoke更改了函数执行的手段。我们也可以对它进行分析,如果它是合理的,继续往下走;如果不合理,拦截下来不再执行。
*发现用户执行了一个 不该执行的(权限不允许的)操作,但居然还执行了,就可以通过一套检查,检测到非法,就可以拦截操作,而且,拦截操作是不用修改 SomeClass.java 的代码的,这叫“非侵入式的更改” !!!不会影响SomeClass的逻辑,但是可以获取返回值,对返回值进行操作。
使用场合:权限管理 日志管理

有关日志(log4j.properties
所谓的日志是指程序中专门写部分代码,将某些信息写到外存。比如一个用户登陆后查看敏感信息,就可以将某时某分某人信息写到外存里,保存到一个文件里面。如果对非敏感信息进行了敏感操作(比如删除),也要记录下来,将某时某分某人信息写到外存里,保存到一个文件里面。这样的信息有助于破案。如果对删除操作进行了日志,还可以对日志进行反过程,恢复数据。
异常如果被截获下来,就可以知道那个类的那个方法发生了异常,以及异常如果一层一层抛上去的,对调试很有意义。尤其是尚未被发现的错误。
一旦出了问题,相关的开发商可以要求把相关的 日志文件 发过去,开发商可以根据日志里面记载的东西精确地找到错误所在,还原错误场景。

执行结果如下:
在这里插入图片描述

JDK代理机制

特点:必须实现接口,而且只能拦截接口方法
基于上面的例子进行修改SomeClass.java

public class SomeClass implements ISomeClass
{

    public SomeClass()
    {}

    @Override
    public String doDealString(String mess)
    {
        System.out.println("执行方法中……");
        return "[" + mess + "]";
    }

    @Override
    public int doDealInt(int num)
    {
        return num + 1;
    }

    public void doSomething()
    {
        System.out.println("这个方法在JDK代理机制中不会被拦截!");
    }

}

再提供一个SJDKProxy.java

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

public class SJDKProxy
{
    private Object object;

    public SJDKProxy()
    {}

    public Object getObject()
    {
        return object;
    }

    public void setObject(Object object)
    {
        this.object=object;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<?> klass)
    {
        try
        {
            Object thisObject=klass.newInstance();

            return (T) innerProxy(thisObject);
        }
        catch(InstantiationException e)
        {
            e.printStackTrace();
        }
        catch(IllegalAccessException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    private Object innerProxy(Object object)
    {
        Class<?> klass=object.getClass();

        return Proxy.newProxyInstance(klass.getClassLoader(), klass.getInterfaces(), new InvocationHandler()
        {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
            {
                System.out.println("前置拦截");

                Object result=method.invoke(object, args);

                System.out.println("后置拦截");

                return result;
            }
        });
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy()
    {
        if(object == null)
        {
            return null;
        }

        return (T) innerProxy(object);
    }

}

DirectJDKProxy.java 改动部分如下

public static void main(String[] args)
    {
        SomeClass someClass=new SomeClass();

        SJDKProxy sjdk=new SJDKProxy();
        ISomeClass some=sjdk.getProxy(SomeClass.class);
        System.out.println(some.doDealString("abcd"));
        someClass.doSomething();
    }

在这里插入图片描述

cglib 代理机制

特点:
相关的方法不能是final,不能把 Complex.java 里的方法改成final。
通过生成子类

首先给出Complex.java
然后给出SCglibProxy.java

import java.lang.reflect.Method;

import about_proxy.jdk.core.Complex;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class SCglibProxy
{
    private Object object;

    public SCglibProxy()
    {}

    public Object getObject()
    {
        return object;
    }

    public void setObject(Object object)
    {
        this.object=object;
    }

    private Object innerProxy(Object object)
    {
        Class<?> parentClass=object.getClass();
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(parentClass);
        // MethodInterceptor方法拦截器
        enhancer.setCallback(new MethodInterceptor()
        {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable
            {
                System.out.println("proxy的类型:" + proxy.getClass());
                System.out.println("methodProxy的类型:" + methodProxy.getClass());
                System.out.println("proxy instanceof parentClass:" + (proxy instanceof Complex));
                Object result=null;
                System.out.println("前置拦截!");
                result=method.invoke(object, args);
                System.out.println("后置拦截!");

                return result;
            }
        });

        return enhancer.create();
    }

    @SuppressWarnings("unchecked")
    public <T> T getPorxy()
    {
        return object == null ? null : ((T) innerProxy(object));
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<?> klass)
    {
        try
        {
            Object object=klass.newInstance();
            return (T) innerProxy(object);
        }
        catch(InstantiationException e)
        {
            e.printStackTrace();
        }
        catch(IllegalAccessException e)
        {
            e.printStackTrace();
        }

        return null;
    }

}

DirectJDKProxy.java 改动部分如下

 public static void main(String[] args)
    {
        SCglibProxy sCglibProxy=new SCglibProxy();
        Complex complex1=sCglibProxy.getProxy(Complex.class);
        System.out.println(complex1.toString());

        SCglibProxy cglibProxy=new SCglibProxy();
        Complex complex2=cglibProxy.getProxy(Complex.class);
        System.out.println(complex2.toString());
    }

运行结果如下:
在这里插入图片描述
以上代码还有一些不足:
增加多个拦截 —— 拦截器链
还可以针对方法,进行各种拦截
前置拦截和后置拦截应该写成接口,让用户实现,
考虑增加异常拦截
怎样结合上面两个方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值